diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index 435905a07b1b6..b66d0d1da2192 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -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 Params; @@ -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) { diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index a03cef36294db..939235179c363 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -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; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index b2fdd2f5bb163..11d2c7a4c8df6 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -373,6 +373,13 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) { endian::readNext(Data); Info.ResultType = std::string(Data, Data + ResultTypeLen); Data += ResultTypeLen; + + unsigned SwiftReturnOwnershipLength = + endian::readNext(Data); + Info.SwiftReturnOwnership = std::string(reinterpret_cast(Data), + reinterpret_cast(Data) + + SwiftReturnOwnershipLength); + Data += SwiftReturnOwnershipLength; } /// Used to deserialize the on-disk Objective-C method table. diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp index d06277fa36727..f726faa832bcc 100644 --- a/clang/lib/APINotes/APINotesTypes.cpp +++ b/clang/lib/APINotes/APINotesTypes.cpp @@ -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) diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index e8d35ce97aabe..cbe6bccb80860 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -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; } @@ -1135,6 +1136,9 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) { writer.write(FI.ResultType.size()); writer.write(ArrayRef{FI.ResultType.data(), FI.ResultType.size()}); + writer.write(FI.SwiftReturnOwnership.size()); + writer.write(ArrayRef{FI.SwiftReturnOwnership.data(), + FI.SwiftReturnOwnership.size()}); } /// Used to serialize the on-disk global function table. diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index b993c8bcae0f4..d623b9042ee1a 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -275,6 +275,7 @@ struct Method { bool DesignatedInit = false; bool Required = false; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector MethodsSeq; @@ -309,6 +310,8 @@ template <> struct MappingTraits { 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 @@ -404,6 +407,7 @@ struct Function { StringRef SwiftName; StringRef Type; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector FunctionsSeq; @@ -426,6 +430,8 @@ template <> struct MappingTraits { 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 @@ -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); @@ -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); } diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index c61dfda51a40f..9f09e55d0a579 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -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() && diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes index c5171e2f287d2..88e0da1382d6c 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes @@ -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 @@ -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 diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h index f205cd3c6e7b7..b6900fee8a979 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h @@ -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; }; diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp index d0e7e31fc1d72..3981ef1ed419a 100644 --- a/clang/test/APINotes/swift-import-as.cpp +++ b/clang/test/APINotes/swift-import-as.cpp @@ -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 @@ -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"