https://github.com/fahadnayyar updated https://github.com/llvm/llvm-project/pull/118938
>From 781bb2a49fed8fa38059cfd23563b02c82f83eb0 Mon Sep 17 00:00:00 2001 From: Fahad Nayyar <f_nay...@apple.com> Date: Thu, 5 Dec 2024 18:25:49 -0800 Subject: [PATCH] [APINotes] Add SWIFT_RETURNS_(UN)RETAINED support to APINotes rdar://141007510 --- clang/include/clang/APINotes/Types.h | 6 +++- clang/lib/APINotes/APINotesFormat.h | 2 +- clang/lib/APINotes/APINotesReader.cpp | 7 ++++ clang/lib/APINotes/APINotesTypes.cpp | 2 ++ clang/lib/APINotes/APINotesWriter.cpp | 4 +++ clang/lib/APINotes/APINotesYAMLCompiler.cpp | 8 +++++ clang/lib/Sema/SemaAPINotes.cpp | 5 +++ .../Inputs/Headers/SwiftImportAs.apinotes | 13 ++++++++ .../APINotes/Inputs/Headers/SwiftImportAs.h | 11 ++++++- clang/test/APINotes/swift-import-as.cpp | 32 +++++++++++++++++++ 10 files changed, 87 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index ff374ad3ada065..9c01978fd49eff 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<ParamInfo> 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 a03cef36294dbb..939235179c3639 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 45a344c13f470e..fa06dffdd14b03 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<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. diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp index d06277fa367274..f726faa832bcce 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 480e1190358d48..1aae07bbdd30e1 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1093,6 +1093,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; } @@ -1118,6 +1119,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. diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 0668dda910f2a8..414a59a4f12d0f 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -162,6 +162,7 @@ struct Method { bool DesignatedInit = false; bool Required = false; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector<Method> MethodsSeq; @@ -196,6 +197,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 @@ -291,6 +294,7 @@ struct Function { StringRef SwiftName; StringRef Type; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector<Function> FunctionsSeq; @@ -313,6 +317,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 @@ -825,6 +831,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); @@ -950,6 +957,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 0dedfc490c86fd..4f79775bc5e913 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -511,6 +511,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 c5171e2f287d28..88e0da1382d6c7 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 f205cd3c6e7b71..b6900fee8a979a 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 d0e7e31fc1d726..3981ef1ed419ae 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 <SwiftImportAs.h> @@ -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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits