Skip to content

[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

Conversation

fahadnayyar
Copy link
Contributor

Since #76798 we started emitting warning for C++ APIs returning SWIFT_SHARED_REFERENCE types when called from Swift. This adds some extra annotation burden on the C++ side.

This patch is adding a way to to specify the return value ownership at the type level for C++ foreign reference types by extending SWIFT_SHARED_REFERENCE with an optional parameter taking retained or unretained like:
SWIFT_SHARED_REFERENCE (retainFunction, releaseFunction, retained)
SWIFT_SHARED_REFERENCE (retainFunction, releaseFunction, unretained)

The 3rd optional parameter expands to:
__attribute__((swift_attr("ownership:retained")))
and
__attribute__((swift_attr("ownership:unretained")))
repectively.

rdar://145453509

@fahadnayyar fahadnayyar force-pushed the cxx-frt-default-return-ownership branch from 667b5d9 to 28104c0 Compare February 24, 2025 08:34
@fahadnayyar fahadnayyar marked this pull request as ready for review February 24, 2025 08:35
@fahadnayyar
Copy link
Contributor Author

@swift-ci please smoke test

@fahadnayyar fahadnayyar added the c++ interop Feature: Interoperability with C++ label Feb 24, 2025
@fahadnayyar fahadnayyar self-assigned this Feb 24, 2025
@Xazax-hun
Copy link
Contributor

I wonder if something like returnedAsRetained might be better? Only saying retained or unretained might not give a full picture what do we mean.

#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)))) \
Copy link
Contributor

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.

__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(...) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to define this as (_retain, _release, ...)? That would make it more readable for someone opening this header file.

return ResultConvention::Owned;
if (tl.getLoweredType().isForeignReferenceType()) {
if (decl->hasAttrs()) {
for (const auto *attr : decl->getAttrs()) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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:

template<typename T>
std::optional<T> matchSwiftAttrs(const clang::Decl *d, ArrayRef<StringRef, T> matches) {
 ...
   if (swiftAttr->getAttribute() == matches[i].first)
     return matches[i].second; 
 ...
}

So we could simplify all of the code snippets like this to:

if (auto match = matchSwiftAttrs(decl, {{"returns_unretained", ResultConvention::Unowned},
            {"returns_retained", ResultConvention::Owned}})
    return match;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in PR-81093

DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) {
};

SWIFT_END_NULLABILITY_ANNOTATIONS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing new line at the end of the file.

SWIFT_BEGIN_NULLABILITY_ANNOTATIONS

namespace DefaultOwnershipConventionOnCXXForegnRefType {
struct __attribute__((swift_attr("import_reference")))
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

…of SWIFT_SHARED_REFERENCE annotation

rdar://145453509
@fahadnayyar fahadnayyar force-pushed the cxx-frt-default-return-ownership branch from 28104c0 to fc1d877 Compare April 22, 2025 04:30
@fahadnayyar fahadnayyar marked this pull request as draft April 25, 2025 07:22
@fahadnayyar
Copy link
Contributor Author

Closing this PR because I have started a new PR-81093 to address this problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants