-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[cxx-interop] Default ownership convention as 3rd optional parameter of SWIFT_SHARED_REFERENCE annotation #79574
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,19 @@ | |
#define _CXX_INTEROP_CONCAT(...) \ | ||
_CXX_INTEROP_CONCAT_(__VA_ARGS__,,,,,,,,,,,,,,,,,) | ||
|
||
/// Specifies that a C++ `class` or `struct` is reference-counted using | ||
#define SWIFT_SHARED_REFERENCE_2ARGS(_retain, _release) \ | ||
__attribute__((swift_attr("import_reference"))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release)))) | ||
|
||
#define SWIFT_SHARED_REFERENCE_3ARGS(_retain, _release, _ownership) \ | ||
__attribute__((swift_attr("import_reference"))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release)))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(ownership:_ownership)))) | ||
|
||
// FN_TODO: modify the documentation | ||
/// Specifies that a C++ `class` or `struct` is reference-counted using | ||
/// the given `retain` and `release` functions. This annotation lets Swift import | ||
/// such a type as reference counted type in Swift, taking advantage of Swift's | ||
/// automatic reference counting. | ||
|
@@ -71,10 +83,10 @@ | |
/// object.doSomething() | ||
/// // The Swift compiler will release object here. | ||
/// ``` | ||
#define SWIFT_SHARED_REFERENCE(_retain, _release) \ | ||
__attribute__((swift_attr("import_reference"))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \ | ||
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release)))) | ||
#define _CXX_INTEROP_GET_MACRO(_1, _2, _3, NAME, ...) NAME | ||
#define SWIFT_SHARED_REFERENCE(...) \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to define this as |
||
_CXX_INTEROP_GET_MACRO(__VA_ARGS__, SWIFT_SHARED_REFERENCE_3ARGS, \ | ||
SWIFT_SHARED_REFERENCE_2ARGS)(__VA_ARGS__) | ||
|
||
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime | ||
/// is presumed to be immortal, i.e. the reference to such object is presumed to | ||
|
@@ -232,7 +244,7 @@ | |
// Empty defines for compilers that don't support `attribute(swift_attr)`. | ||
#define SWIFT_SELF_CONTAINED | ||
#define SWIFT_RETURNS_INDEPENDENT_VALUE | ||
#define SWIFT_SHARED_REFERENCE(_retain, _release) | ||
#define SWIFT_SHARED_REFERENCE(_retain, _release, ...) | ||
#define SWIFT_IMMORTAL_REFERENCE | ||
#define SWIFT_UNSAFE_REFERENCE | ||
#define SWIFT_NAME(_name) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1346,17 +1346,39 @@ class Conventions { | |
} | ||
|
||
// Determines owned/unowned ResultConvention of the returned value based on | ||
// returns_retained/returns_unretained attribute. | ||
// SWIFT_RETURNS_(UN)RETAINED annotation on the C++ API and then based on | ||
// ownership:(un)retained as the 3rd optional parameter of | ||
// SWIFT_SHARED_REFERENCE annotation on the returned type | ||
std::optional<ResultConvention> | ||
getCxxRefConventionWithAttrs(const TypeLowering &tl, | ||
const clang::Decl *decl) const { | ||
if (tl.getLoweredType().isForeignReferenceType() && decl->hasAttrs()) { | ||
for (const auto *attr : decl->getAttrs()) { | ||
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) { | ||
if (swiftAttr->getAttribute() == "returns_unretained") { | ||
return ResultConvention::Unowned; | ||
} else if (swiftAttr->getAttribute() == "returns_retained") { | ||
return ResultConvention::Owned; | ||
if (tl.getLoweredType().isForeignReferenceType()) { | ||
if (decl->hasAttrs()) { | ||
for (const auto *attr : decl->getAttrs()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have this pattern in our codebase so many times, I am wondering if we should have a helper function at this point. Something like:
So we could simplify all of the code snippets like this to:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in PR-81093 |
||
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) { | ||
if (swiftAttr->getAttribute() == "returns_unretained") { | ||
return ResultConvention::Unowned; | ||
} else if (swiftAttr->getAttribute() == "returns_retained") { | ||
return ResultConvention::Owned; | ||
} | ||
} | ||
} | ||
} | ||
if (auto *classDecl = tl.getLoweredType() | ||
.getASTType() | ||
.getPointer() | ||
->lookThroughAllOptionalTypes() | ||
->getClassOrBoundGenericClass()) { | ||
if (auto clangRecordDecl = | ||
dyn_cast<clang::RecordDecl>(classDecl->getClangDecl())) { | ||
for (const auto *attr : clangRecordDecl->getAttrs()) { | ||
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) { | ||
if (swiftAttr->getAttribute() == "ownership:unretained") { | ||
return ResultConvention::Unowned; | ||
} else if (swiftAttr->getAttribute() == "ownership:retained") { | ||
return ResultConvention::Owned; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
#pragma once | ||
#include "visibility.h" | ||
#include <functional> | ||
|
||
// FRT or SWIFT_SHARED_REFERENCE type | ||
|
@@ -326,3 +327,106 @@ struct Derived : Base { | |
FRTStruct *_Nonnull VirtualMethodReturningFRTUnowned() override | ||
__attribute__((swift_attr("returns_unretained"))); | ||
}; | ||
|
||
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS | ||
|
||
namespace DefaultOwnershipConventionOnCXXForegnRefType { | ||
struct __attribute__((swift_attr("import_reference"))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for this change it would be important to add tests that are testing the bridging header directly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be relevant now in PR-81093. But feel free to leave a comment on the new PR if you feel strongly about this. |
||
__attribute__((swift_attr("retain:defRetain1"))) | ||
__attribute__((swift_attr("release:defRelease1"))) | ||
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {}; | ||
|
||
RefTypeDefaultRetained *returnRefTypeDefaultRetained() { | ||
return new RefTypeDefaultRetained(); | ||
} | ||
|
||
struct __attribute__((swift_attr("import_reference"))) | ||
__attribute__((swift_attr("retain:defRetain2"))) | ||
__attribute__((swift_attr("release:defRelease2"))) | ||
__attribute__((swift_attr("ownership:unretained"))) RefTypeDefaultUnretained {}; | ||
|
||
RefTypeDefaultUnretained *returnRefTypeDefaultUnretained() { | ||
return new RefTypeDefaultUnretained(); | ||
} | ||
} // namespace DefaultOwnershipConventionOnCXXForegnRefType | ||
void defRetain1( | ||
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultRetained *v) {}; | ||
void defRelease1( | ||
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultRetained *v) {}; | ||
|
||
void defRetain2( | ||
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultUnretained *v) { | ||
}; | ||
void defRelease2( | ||
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultUnretained *v) { | ||
}; | ||
|
||
namespace FunctionAnnotationHasPrecedence { | ||
struct __attribute__((swift_attr("import_reference"))) | ||
__attribute__((swift_attr("retain:defaultRetain1"))) | ||
__attribute__((swift_attr("release:defaultRelease1"))) | ||
__attribute__((swift_attr("ownership:unretained"))) RefTypeDefaultUnRetained {}; | ||
|
||
RefTypeDefaultUnRetained *returnRefTypeDefaultUnRetained() { | ||
return new RefTypeDefaultUnRetained(); | ||
} | ||
RefTypeDefaultUnRetained *returnRefTypeDefaultUnRetainedAnnotatedRetained() | ||
__attribute__((swift_attr("returns_retained"))) { | ||
return new RefTypeDefaultUnRetained(); | ||
} | ||
|
||
struct __attribute__((swift_attr("import_reference"))) | ||
__attribute__((swift_attr("retain:defaultRetain2"))) | ||
__attribute__((swift_attr("release:defaultRelease2"))) | ||
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {}; | ||
|
||
RefTypeDefaultRetained *returnRefTypeDefaultRetained() { | ||
return new RefTypeDefaultRetained(); | ||
} | ||
RefTypeDefaultRetained *returnRefTypeDefaultRetainedAnnotatedUnRetained() | ||
__attribute__((swift_attr("returns_unretained"))) { | ||
return new RefTypeDefaultRetained(); | ||
} | ||
|
||
} // namespace FunctionAnnotationHasPrecedence | ||
|
||
void defaultRetain1( | ||
FunctionAnnotationHasPrecedence::RefTypeDefaultUnRetained *v) {}; | ||
void defaultRelease1( | ||
FunctionAnnotationHasPrecedence::RefTypeDefaultUnRetained *v) {}; | ||
|
||
void defaultRetain2( | ||
FunctionAnnotationHasPrecedence::RefTypeDefaultRetained *v) {}; | ||
void defaultRelease2( | ||
FunctionAnnotationHasPrecedence::RefTypeDefaultRetained *v) {}; | ||
|
||
namespace DefaultOwnershipSuppressUnannotatedAPIWarning { | ||
|
||
struct __attribute__((swift_attr("import_reference"))) | ||
__attribute__((swift_attr("retain:rretain"))) | ||
__attribute__((swift_attr("release:rrelease"))) RefType {}; | ||
|
||
RefType *returnRefType() { return new RefType(); } | ||
|
||
struct __attribute__((swift_attr("import_reference"))) | ||
__attribute__((swift_attr("retain:dretain"))) | ||
__attribute__((swift_attr("release:drelease"))) | ||
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {}; | ||
|
||
RefTypeDefaultRetained *returnRefTypeDefaultRetained() { | ||
return new RefTypeDefaultRetained(); | ||
} | ||
|
||
} // namespace DefaultOwnershipSuppressUnannotatedAPIWarning | ||
|
||
void rretain(DefaultOwnershipSuppressUnannotatedAPIWarning::RefType *v) {}; | ||
void rrelease(DefaultOwnershipSuppressUnannotatedAPIWarning::RefType *v) {}; | ||
|
||
void dretain( | ||
DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) { | ||
}; | ||
void drelease( | ||
DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) { | ||
}; | ||
|
||
SWIFT_END_NULLABILITY_ANNOTATIONS | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: missing new line at the end of the file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: formatting, the backslashes are not in the same column.