Skip to content

Commit 48f7f63

Browse files
authoredDec 9, 2024··
[APINotes] Add SWIFT_RETURNS_(UN)RETAINED support (#118938)
Adding support to APINotes to annotate C++ methods and functions with `swift_attr("returns_retained")` and `swift_attr("returns_unretained")` rdar://141007510
1 parent 2e8ce30 commit 48f7f63

File tree

10 files changed

+87
-3
lines changed

10 files changed

+87
-3
lines changed
 

‎clang/include/clang/APINotes/Types.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,9 @@ class FunctionInfo : public CommonEntityInfo {
542542
/// The result type of this function, as a C type.
543543
std::string ResultType;
544544

545+
/// Ownership convention for return value
546+
std::string SwiftReturnOwnership;
547+
545548
/// The function parameters.
546549
std::vector<ParamInfo> Params;
547550

@@ -622,7 +625,8 @@ inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
622625
LHS.NumAdjustedNullable == RHS.NumAdjustedNullable &&
623626
LHS.NullabilityPayload == RHS.NullabilityPayload &&
624627
LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params &&
625-
LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
628+
LHS.RawRetainCountConvention == RHS.RawRetainCountConvention &&
629+
LHS.SwiftReturnOwnership == RHS.SwiftReturnOwnership;
626630
}
627631

628632
inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {

‎clang/lib/APINotes/APINotesFormat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
2424
/// API notes file minor version number.
2525
///
2626
/// When the format changes IN ANY WAY, this number should be incremented.
27-
const uint16_t VERSION_MINOR = 33; // SwiftEscapable
27+
const uint16_t VERSION_MINOR = 34; // SwiftReturnOwnership
2828

2929
const uint8_t kSwiftConforms = 1;
3030
const uint8_t kSwiftDoesNotConform = 2;

‎clang/lib/APINotes/APINotesReader.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,13 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) {
373373
endian::readNext<uint16_t, llvm::endianness::little>(Data);
374374
Info.ResultType = std::string(Data, Data + ResultTypeLen);
375375
Data += ResultTypeLen;
376+
377+
unsigned SwiftReturnOwnershipLength =
378+
endian::readNext<uint16_t, llvm::endianness::little>(Data);
379+
Info.SwiftReturnOwnership = std::string(reinterpret_cast<const char *>(Data),
380+
reinterpret_cast<const char *>(Data) +
381+
SwiftReturnOwnershipLength);
382+
Data += SwiftReturnOwnershipLength;
376383
}
377384

378385
/// Used to deserialize the on-disk Objective-C method table.

‎clang/lib/APINotes/APINotesTypes.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const {
7777
<< "RawRetainCountConvention: " << RawRetainCountConvention << ' ';
7878
if (!ResultType.empty())
7979
OS << "Result Type: " << ResultType << ' ';
80+
if (!SwiftReturnOwnership.empty())
81+
OS << "SwiftReturnOwnership: " << SwiftReturnOwnership << ' ';
8082
if (!Params.empty())
8183
OS << '\n';
8284
for (auto &PI : Params)

‎clang/lib/APINotes/APINotesWriter.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,7 @@ unsigned getFunctionInfoSize(const FunctionInfo &FI) {
10931093
for (const auto &P : FI.Params)
10941094
size += getParamInfoSize(P);
10951095
size += sizeof(uint16_t) + FI.ResultType.size();
1096+
size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();
10961097
return size;
10971098
}
10981099

@@ -1118,6 +1119,9 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
11181119

11191120
writer.write<uint16_t>(FI.ResultType.size());
11201121
writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
1122+
writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
1123+
writer.write(ArrayRef<char>{FI.SwiftReturnOwnership.data(),
1124+
FI.SwiftReturnOwnership.size()});
11211125
}
11221126

11231127
/// Used to serialize the on-disk global function table.

‎clang/lib/APINotes/APINotesYAMLCompiler.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ struct Method {
162162
bool DesignatedInit = false;
163163
bool Required = false;
164164
StringRef ResultType;
165+
StringRef SwiftReturnOwnership;
165166
};
166167

167168
typedef std::vector<Method> MethodsSeq;
@@ -196,6 +197,8 @@ template <> struct MappingTraits<Method> {
196197
IO.mapOptional("DesignatedInit", M.DesignatedInit, false);
197198
IO.mapOptional("Required", M.Required, false);
198199
IO.mapOptional("ResultType", M.ResultType, StringRef(""));
200+
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
201+
StringRef(""));
199202
}
200203
};
201204
} // namespace yaml
@@ -291,6 +294,7 @@ struct Function {
291294
StringRef SwiftName;
292295
StringRef Type;
293296
StringRef ResultType;
297+
StringRef SwiftReturnOwnership;
294298
};
295299

296300
typedef std::vector<Function> FunctionsSeq;
@@ -313,6 +317,8 @@ template <> struct MappingTraits<Function> {
313317
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
314318
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
315319
IO.mapOptional("ResultType", F.ResultType, StringRef(""));
320+
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
321+
StringRef(""));
316322
}
317323
};
318324
} // namespace yaml
@@ -825,6 +831,7 @@ class YAMLConverter {
825831
emitError("'FactoryAsInit' is no longer valid; use 'SwiftName' instead");
826832

827833
MI.ResultType = std::string(M.ResultType);
834+
MI.SwiftReturnOwnership = std::string(M.SwiftReturnOwnership);
828835

829836
// Translate parameter information.
830837
convertParams(M.Params, MI, MI.Self);
@@ -950,6 +957,7 @@ class YAMLConverter {
950957
convertNullability(Function.Nullability, Function.NullabilityOfRet, FI,
951958
Function.Name);
952959
FI.ResultType = std::string(Function.ResultType);
960+
FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership);
953961
FI.setRetainCountConvention(Function.RetainCountConvention);
954962
}
955963

‎clang/lib/Sema/SemaAPINotes.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,11 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
511511
AnyTypeChanged = true;
512512
}
513513

514+
// returns_(un)retained
515+
if (!Info.SwiftReturnOwnership.empty())
516+
D->addAttr(SwiftAttrAttr::Create(S.Context,
517+
"returns_" + Info.SwiftReturnOwnership));
518+
514519
// Result type override.
515520
QualType OverriddenResultType;
516521
if (Metadata.IsActive && !Info.ResultType.empty() &&

‎clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ Name: SwiftImportAs
33
Tags:
44
- Name: ImmortalRefType
55
SwiftImportAs: reference
6+
Methods:
7+
- Name: methodReturningFrt__
8+
- Name: methodReturningFrt_returns_unretained
9+
SwiftReturnOwnership: unretained
10+
- Name: methodReturningFrt_returns_retained
11+
SwiftReturnOwnership: retained
612
- Name: RefCountedType
713
SwiftImportAs: reference
814
SwiftReleaseOp: RCRelease
@@ -17,3 +23,10 @@ Tags:
1723
SwiftEscapable: false
1824
- Name: EscapableType
1925
SwiftEscapable: true
26+
27+
Functions:
28+
- Name: functionReturningFrt__
29+
- Name: functionReturningFrt_returns_unretained
30+
SwiftReturnOwnership: unretained
31+
- Name: functionReturningFrt_returns_retained
32+
SwiftReturnOwnership: retained

‎clang/test/APINotes/Inputs/Headers/SwiftImportAs.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
struct ImmortalRefType {};
1+
struct ImmortalRefType {
2+
ImmortalRefType * methodReturningFrt__(void);
3+
ImmortalRefType * methodReturningFrt_returns_unretained(void);
4+
ImmortalRefType * methodReturningFrt_returns_retained(void);
5+
};
6+
7+
ImmortalRefType * functionReturningFrt__(void);
8+
ImmortalRefType * functionReturningFrt_returns_unretained(void);
9+
ImmortalRefType * functionReturningFrt_returns_retained(void);
10+
211

312
struct RefCountedType { int value; };
413

‎clang/test/APINotes/swift-import-as.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
// 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
77
// 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
88
// 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
9+
// 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
10+
// 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
11+
// 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
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 methodReturningFrt__ | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT %s
13+
// 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
14+
// 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
915

1016
#include <SwiftImportAs.h>
1117

@@ -36,3 +42,29 @@
3642
// CHECK-ESCAPABLE: Dumping EscapableType:
3743
// CHECK-ESCAPABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct EscapableType
3844
// CHECK-ESCAPABLE: SwiftAttrAttr {{.+}} "Escapable"
45+
46+
// CHECK-FUNCTION-RETURNING-FRT: Dumping functionReturningFrt__:
47+
// CHECK-FUNCTION-RETURNING-FRT: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt__ 'ImmortalRefType *()'
48+
// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained"
49+
// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained"
50+
51+
// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: Dumping functionReturningFrt_returns_unretained:
52+
// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_unretained 'ImmortalRefType *()'
53+
// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained"
54+
55+
// CHECK-FUNCTION-RETURNING-FRT-RETAINED: Dumping functionReturningFrt_returns_retained:
56+
// CHECK-FUNCTION-RETURNING-FRT-RETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_retained 'ImmortalRefType *()'
57+
// CHECK-FUNCTION-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained"
58+
59+
// CHECK-METHOD-RETURNING-FRT: Dumping ImmortalRefType::methodReturningFrt__:
60+
// CHECK-METHOD-RETURNING-FRT: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt__ 'ImmortalRefType *()'
61+
// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained"
62+
// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained"
63+
64+
// CHECK-METHOD-RETURNING-FRT-UNRETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_unretained:
65+
// CHECK-METHOD-RETURNING-FRT-UNRETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_unretained 'ImmortalRefType *()'
66+
// CHECK-METHOD-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained"
67+
68+
// CHECK-METHOD-RETURNING-FRT-RETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_retained:
69+
// CHECK-METHOD-RETURNING-FRT-RETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_retained 'ImmortalRefType *()'
70+
// CHECK-METHOD-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained"

0 commit comments

Comments
 (0)
Please sign in to comment.