[clang] [APINotes] Add SWIFT_RETURNS_(UN)RETAINED support to APINotes (PR #118938)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 6 08:19:39 PST 2024
https://github.com/fahadnayyar updated https://github.com/llvm/llvm-project/pull/118938
>From b134b97d3f8888f44bdf2d9147dda33c9c1e4077 Mon Sep 17 00:00:00 2001
From: Fahad Nayyar <f_nayyar at 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 | 15 ++++++++-
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 | 4 +++
.../Inputs/Headers/SwiftImportAs.apinotes | 13 ++++++++
.../APINotes/Inputs/Headers/SwiftImportAs.h | 11 ++++++-
clang/test/APINotes/swift-import-as.cpp | 32 +++++++++++++++++++
9 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index ff374ad3ada065..0220bfb2ff1b66 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;
@@ -600,6 +603,15 @@ class FunctionInfo : public CommonEntityInfo {
friend bool operator==(const FunctionInfo &, const FunctionInfo &);
+ FunctionInfo &operator|=(const FunctionInfo &RHS) {
+ static_cast<CommonEntityInfo &>(*this) |= RHS;
+
+ if (SwiftReturnOwnership.empty())
+ SwiftReturnOwnership = RHS.SwiftReturnOwnership;
+
+ return *this;
+ }
+
private:
NullabilityKind getTypeInfo(unsigned index) const {
assert(NullabilityAudited &&
@@ -622,7 +634,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/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..fc70e820dca4a7 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -511,6 +511,10 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
AnyTypeChanged = true;
}
+ // returns_(un)retained
+ if (!Info.SwiftReturnOwnership.empty())
+ D->addAttr(SwiftAttrAttr::Create(S.Context, 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..c01420740e0d55 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: 'returns_unretained'
+ - Name: methodReturningFrt_returns_retained
+ SwiftReturnOwnership: 'returns_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: 'returns_unretained'
+ - Name: functionReturningFrt_returns_retained
+ SwiftReturnOwnership: 'returns_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..92a529a4d8097f 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"
More information about the cfe-commits
mailing list