Skip to content

Commit

Permalink
[APINotes] Add SWIFT_RETURNS_(UN)RETAINED support to APINotes
Browse files Browse the repository at this point in the history
rdar://141007510
  • Loading branch information
fahadnayyar authored and Michael137 committed Dec 16, 2024
1 parent 75c217d commit 5a5002e
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 3 deletions.
6 changes: 5 additions & 1 deletion clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ class FunctionInfo : public CommonEntityInfo {
/// The result type of this function, as a C type.
std::string ResultType;

/// Ownership convention for return value
std::string SwiftReturnOwnership;

/// The function parameters.
std::vector<ParamInfo> Params;

Expand Down Expand Up @@ -622,7 +625,8 @@ inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
LHS.NumAdjustedNullable == RHS.NumAdjustedNullable &&
LHS.NullabilityPayload == RHS.NullabilityPayload &&
LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params &&
LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
LHS.RawRetainCountConvention == RHS.RawRetainCountConvention &&
LHS.SwiftReturnOwnership == RHS.SwiftReturnOwnership;
}

inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 33; // SwiftEscapable
const uint16_t VERSION_MINOR = 34; // SwiftReturnOwnership

const uint8_t kSwiftConforms = 1;
const uint8_t kSwiftDoesNotConform = 2;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,13 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) {
endian::readNext<uint16_t, llvm::endianness::little>(Data);
Info.ResultType = std::string(Data, Data + ResultTypeLen);
Data += ResultTypeLen;

unsigned SwiftReturnOwnershipLength =
endian::readNext<uint16_t, llvm::endianness::little>(Data);
Info.SwiftReturnOwnership = std::string(reinterpret_cast<const char *>(Data),
reinterpret_cast<const char *>(Data) +
SwiftReturnOwnershipLength);
Data += SwiftReturnOwnershipLength;
}

/// Used to deserialize the on-disk Objective-C method table.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/APINotes/APINotesTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const {
<< "RawRetainCountConvention: " << RawRetainCountConvention << ' ';
if (!ResultType.empty())
OS << "Result Type: " << ResultType << ' ';
if (!SwiftReturnOwnership.empty())
OS << "SwiftReturnOwnership: " << SwiftReturnOwnership << ' ';
if (!Params.empty())
OS << '\n';
for (auto &PI : Params)
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,7 @@ unsigned getFunctionInfoSize(const FunctionInfo &FI) {
for (const auto &P : FI.Params)
size += getParamInfoSize(P);
size += sizeof(uint16_t) + FI.ResultType.size();
size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();
return size;
}

Expand All @@ -1135,6 +1136,9 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {

writer.write<uint16_t>(FI.ResultType.size());
writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
writer.write(ArrayRef<char>{FI.SwiftReturnOwnership.data(),
FI.SwiftReturnOwnership.size()});
}

/// Used to serialize the on-disk global function table.
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ struct Method {
bool DesignatedInit = false;
bool Required = false;
StringRef ResultType;
StringRef SwiftReturnOwnership;
};

typedef std::vector<Method> MethodsSeq;
Expand Down Expand Up @@ -309,6 +310,8 @@ template <> struct MappingTraits<Method> {
IO.mapOptional("DesignatedInit", M.DesignatedInit, false);
IO.mapOptional("Required", M.Required, false);
IO.mapOptional("ResultType", M.ResultType, StringRef(""));
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
StringRef(""));
}
};
} // namespace yaml
Expand Down Expand Up @@ -404,6 +407,7 @@ struct Function {
StringRef SwiftName;
StringRef Type;
StringRef ResultType;
StringRef SwiftReturnOwnership;
};

typedef std::vector<Function> FunctionsSeq;
Expand All @@ -426,6 +430,8 @@ template <> struct MappingTraits<Function> {
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
IO.mapOptional("ResultType", F.ResultType, StringRef(""));
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
StringRef(""));
}
};
} // namespace yaml
Expand Down Expand Up @@ -938,6 +944,7 @@ class YAMLConverter {
emitError("'FactoryAsInit' is no longer valid; use 'SwiftName' instead");

MI.ResultType = std::string(M.ResultType);
MI.SwiftReturnOwnership = std::string(M.SwiftReturnOwnership);

// Translate parameter information.
convertParams(M.Params, MI, MI.Self);
Expand Down Expand Up @@ -1063,6 +1070,7 @@ class YAMLConverter {
convertNullability(Function.Nullability, Function.NullabilityOfRet, FI,
Function.Name);
FI.ResultType = std::string(Function.ResultType);
FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership);
FI.setRetainCountConvention(Function.RetainCountConvention);
}

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,11 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
AnyTypeChanged = true;
}

// returns_(un)retained
if (!Info.SwiftReturnOwnership.empty())
D->addAttr(SwiftAttrAttr::Create(S.Context,
"returns_" + Info.SwiftReturnOwnership));

// Result type override.
QualType OverriddenResultType;
if (Metadata.IsActive && !Info.ResultType.empty() &&
Expand Down
13 changes: 13 additions & 0 deletions clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ Name: SwiftImportAs
Tags:
- Name: ImmortalRefType
SwiftImportAs: reference
Methods:
- Name: methodReturningFrt__
- Name: methodReturningFrt_returns_unretained
SwiftReturnOwnership: unretained
- Name: methodReturningFrt_returns_retained
SwiftReturnOwnership: retained
- Name: RefCountedType
SwiftImportAs: reference
SwiftReleaseOp: RCRelease
Expand All @@ -17,3 +23,10 @@ Tags:
SwiftEscapable: false
- Name: EscapableType
SwiftEscapable: true

Functions:
- Name: functionReturningFrt__
- Name: functionReturningFrt_returns_unretained
SwiftReturnOwnership: unretained
- Name: functionReturningFrt_returns_retained
SwiftReturnOwnership: retained
11 changes: 10 additions & 1 deletion clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
struct ImmortalRefType {};
struct ImmortalRefType {
ImmortalRefType * methodReturningFrt__(void);
ImmortalRefType * methodReturningFrt_returns_unretained(void);
ImmortalRefType * methodReturningFrt_returns_retained(void);
};

ImmortalRefType * functionReturningFrt__(void);
ImmortalRefType * functionReturningFrt_returns_unretained(void);
ImmortalRefType * functionReturningFrt_returns_retained(void);


struct RefCountedType { int value; };

Expand Down
32 changes: 32 additions & 0 deletions clang/test/APINotes/swift-import-as.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter CopyableType | FileCheck -check-prefix=CHECK-COPYABLE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter NonEscapableType | FileCheck -check-prefix=CHECK-NON-ESCAPABLE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter EscapableType | FileCheck -check-prefix=CHECK-ESCAPABLE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt__ | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT-UNRETAINED %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT-RETAINED %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt__ | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-UNRETAINED %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-RETAINED %s

#include <SwiftImportAs.h>

Expand Down Expand Up @@ -36,3 +42,29 @@
// CHECK-ESCAPABLE: Dumping EscapableType:
// CHECK-ESCAPABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct EscapableType
// CHECK-ESCAPABLE: SwiftAttrAttr {{.+}} "Escapable"

// CHECK-FUNCTION-RETURNING-FRT: Dumping functionReturningFrt__:
// CHECK-FUNCTION-RETURNING-FRT: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt__ 'ImmortalRefType *()'
// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained"
// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained"

// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: Dumping functionReturningFrt_returns_unretained:
// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_unretained 'ImmortalRefType *()'
// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained"

// CHECK-FUNCTION-RETURNING-FRT-RETAINED: Dumping functionReturningFrt_returns_retained:
// CHECK-FUNCTION-RETURNING-FRT-RETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_retained 'ImmortalRefType *()'
// CHECK-FUNCTION-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained"

// CHECK-METHOD-RETURNING-FRT: Dumping ImmortalRefType::methodReturningFrt__:
// CHECK-METHOD-RETURNING-FRT: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt__ 'ImmortalRefType *()'
// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained"
// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained"

// CHECK-METHOD-RETURNING-FRT-UNRETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_unretained:
// CHECK-METHOD-RETURNING-FRT-UNRETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_unretained 'ImmortalRefType *()'
// CHECK-METHOD-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained"

// CHECK-METHOD-RETURNING-FRT-RETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_retained:
// CHECK-METHOD-RETURNING-FRT-RETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_retained 'ImmortalRefType *()'
// CHECK-METHOD-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained"

0 comments on commit 5a5002e

Please sign in to comment.