Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🍒 [APINotes] Add SWIFT_RETURNS_(UN)RETAINED support to APINotes #9713

Open
wants to merge 1 commit into
base: stable/20240723
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"