Skip to content

[cxx-interop] Add RETURNS_RETAINED annotations to C++ thunks#88597

Open
patrykstefanski wants to merge 1 commit intoswiftlang:mainfrom
patrykstefanski:add_returns_retained_annotations_to_cxx_thunks
Open

[cxx-interop] Add RETURNS_RETAINED annotations to C++ thunks#88597
patrykstefanski wants to merge 1 commit intoswiftlang:mainfrom
patrykstefanski:add_returns_retained_annotations_to_cxx_thunks

Conversation

@patrykstefanski
Copy link
Copy Markdown
Contributor

Swift functions exposed to C++ return +1 (retained) values, but the generated C++ thunks in the -Swift.h header lacked ownership annotations. This prevented Clang's static analyzer from verifying reference counts when C++ code calls into Swift.

Add NS_RETURNS_RETAINED, CF_RETURNS_RETAINED, and SWIFT_RETURNS_RETAINED annotations to thunk signatures based on the return type:

  • NS_RETURNS_RETAINED for ObjC classes (NSString, etc.)
  • CF_RETURNS_RETAINED for CF types (CFString, etc.)
  • SWIFT_RETURNS_RETAINED for foreign reference types

rdar://165231653

Swift functions exposed to C++ return +1 (retained) values, but the
generated C++ thunks in the -Swift.h header lacked ownership
annotations. This prevented Clang's static analyzer from verifying
reference counts when C++ code calls into Swift.

Add NS_RETURNS_RETAINED, CF_RETURNS_RETAINED, and SWIFT_RETURNS_RETAINED
annotations to thunk signatures based on the return type:
- NS_RETURNS_RETAINED for ObjC classes (NSString, etc.) and existentials (id)
- CF_RETURNS_RETAINED for CF types (CFString, etc.)
- SWIFT_RETURNS_RETAINED for foreign reference types

rdar://165231653
@patrykstefanski patrykstefanski added the c++ interop Feature: Interoperability with C++ label Apr 21, 2026
@patrykstefanski patrykstefanski requested a review from a team as a code owner April 21, 2026 22:27
Copy link
Copy Markdown
Contributor

@j-hui j-hui left a comment

Choose a reason for hiding this comment

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

This LGTM!

Just wondering, is there ever a need to print a RETURNS_UNRETAINED annotation?

// CHECK: #if !defined(CF_RETURNS_RETAINED)
// CHECK: #if !defined(SWIFT_RETURNS_RETAINED)

// CHECK: SWIFT_INLINE_THUNK NSString *_Nonnull getName()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It looks like these are emitted in alphabetical order. WDYT about flipping the naming scheme so it's swiftClassReturn, swiftClassPassthrough, methodGetNSString etc? That way you can keep them grouped by category, but sort the decls in alphabetical order and place the check comments right next to the decl being checked.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that's a great idea! I'll do it

Copy link
Copy Markdown
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

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

LG, thanks!


// A function returning NSString? generates a thunk returning `NSString
// *_Nullable`.
Type unwrapped = resultTy->getOptionalObjectType();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: could this be simplified via lookThroughSingleOptionalType?

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.

4 participants