Skip to content

Commit e3ea4e1

Browse files
authored
Merge pull request swiftlang#75897 from fahadnayyar/f-dev-frt-return-ownership-annotations-pr
[cxx-interop] Add SWIFT_RETURNS_RETAINED and SWIFT_RETURNS_UNRETAINED…
2 parents f40c654 + ea43283 commit e3ea4e1

File tree

8 files changed

+552
-0
lines changed

8 files changed

+552
-0
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ ERROR(failed_base_method_call_synthesis,none,
248248
"failed to synthesize call to the base method %0 of type %0",
249249
(ValueDecl *, ValueDecl *))
250250

251+
ERROR(both_returns_retained_returns_unretained,none,
252+
"%0 cannot be annotated with both swift_attr('returns_retained') and swift_attr('returns_unretained') attributes", (const clang::NamedDecl*))
253+
251254
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
252255
NOTE(record_field_not_imported, none, "field %0 unavailable (cannot import)", (const clang::NamedDecl*))
253256
NOTE(invoked_func_not_imported, none, "function %0 unavailable (cannot import)", (const clang::NamedDecl*))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3262,6 +3262,30 @@ namespace {
32623262
return property->getParsedAccessor(AccessorKind::Set);
32633263
}
32643264

3265+
// If a C++ decl is annotated with both swift_attr("returns_retained") and
3266+
// swift_attr("returns_unretained") then emit an error in the swift
3267+
// compiler. Note: this error is not emitted in the clang compiler because
3268+
// these attributes are used only for swift interop.
3269+
if (decl->hasAttrs()) {
3270+
bool returnsRetainedAttrIsPresent = false;
3271+
bool returnsUnretainedAttrIsPresent = false;
3272+
for (const auto *attr : decl->getAttrs()) {
3273+
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
3274+
if (swiftAttr->getAttribute() == "returns_unretained") {
3275+
returnsUnretainedAttrIsPresent = true;
3276+
} else if (swiftAttr->getAttribute() == "returns_retained") {
3277+
returnsRetainedAttrIsPresent = true;
3278+
}
3279+
}
3280+
}
3281+
3282+
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
3283+
HeaderLoc loc(decl->getLocation());
3284+
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
3285+
decl);
3286+
}
3287+
}
3288+
32653289
return importFunctionDecl(decl, importedName, correctSwiftName,
32663290
std::nullopt);
32673291
}

lib/ClangImporter/SwiftBridging/swift/bridging

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@
164164
#define SWIFT_NONESCAPABLE \
165165
__attribute__((swift_attr("~Escapable")))
166166

167+
/// Specifies that the return value is passed as owned for C++ functions and
168+
/// methods returning types annotated as `SWIFT_SHARED_REFERENCE`
169+
#define SWIFT_RETURNS_RETAINED __attribute__((swift_attr("returns_retained")))
170+
/// Specifies that the return value is passed as unowned for C++ functions and
171+
/// methods returning types annotated as `SWIFT_SHARED_REFERENCE`
172+
#define SWIFT_RETURNS_UNRETAINED \
173+
__attribute__((swift_attr("returns_unretained")))
174+
167175
#else // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
168176

169177
// Empty defines for compilers that don't support `attribute(swift_attr)`.
@@ -179,6 +187,8 @@
179187
#define SWIFT_UNCHECKED_SENDABLE
180188
#define SWIFT_NONCOPYABLE
181189
#define SWIFT_NONESCAPABLE
190+
#define SWIFT_RETURNS_RETAINED
191+
#define SWIFT_RETURNS_UNRETAINED
182192

183193
#endif // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
184194

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3350,6 +3350,25 @@ class CFunctionTypeConventions : public Conventions {
33503350
const clang::FunctionType *type)
33513351
: Conventions(kind), FnType(type) {}
33523352

3353+
// Determines owned/unowned ResultConvention of the returned value based on
3354+
// returns_retained/returns_unretained attribute.
3355+
std::optional<ResultConvention>
3356+
getForeignReferenceTypeResultConventionWithAttributes(
3357+
const TypeLowering &tl, const clang::FunctionDecl *decl) const {
3358+
if (tl.getLoweredType().isForeignReferenceType() && decl->hasAttrs()) {
3359+
for (const auto *attr : decl->getAttrs()) {
3360+
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
3361+
if (swiftAttr->getAttribute() == "returns_unretained") {
3362+
return ResultConvention::Unowned;
3363+
} else if (swiftAttr->getAttribute() == "returns_retained") {
3364+
return ResultConvention::Owned;
3365+
}
3366+
}
3367+
}
3368+
}
3369+
return std::nullopt;
3370+
}
3371+
33533372
public:
33543373
CFunctionTypeConventions(const clang::FunctionType *type)
33553374
: Conventions(ConventionsKind::CFunctionType), FnType(type) {}
@@ -3467,6 +3486,13 @@ class CFunctionConventions : public CFunctionTypeConventions {
34673486
return ResultConvention::Indirect;
34683487
}
34693488

3489+
// Explicitly setting the ownership of the returned FRT if the C++
3490+
// global/free function has either swift_attr("returns_retained") or
3491+
// ("returns_unretained") attribute.
3492+
if (auto resultConventionOpt =
3493+
getForeignReferenceTypeResultConventionWithAttributes(tl, TheDecl))
3494+
return *resultConventionOpt;
3495+
34703496
if (isCFTypedef(tl, TheDecl->getReturnType())) {
34713497
// The CF attributes aren't represented in the type, so we need
34723498
// to check them here.
@@ -3545,6 +3571,14 @@ class CXXMethodConventions : public CFunctionTypeConventions {
35453571
// possible to make it easy for LLVM to optimize away the thunk.
35463572
return ResultConvention::Indirect;
35473573
}
3574+
3575+
// Explicitly setting the ownership of the returned FRT if the C++ member
3576+
// method has either swift_attr("returns_retained") or
3577+
// ("returns_unretained") attribute.
3578+
if (auto resultConventionOpt =
3579+
getForeignReferenceTypeResultConventionWithAttributes(resultTL, TheDecl))
3580+
return *resultConventionOpt;
3581+
35483582
if (TheDecl->hasAttr<clang::CFReturnsRetainedAttr>() &&
35493583
resultTL.getLoweredType().isForeignReferenceType()) {
35503584
return ResultConvention::Owned;
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#pragma once
2+
3+
// FRT or SWIFT_SHARED_REFERENCE type
4+
struct FRTStruct {
5+
// Friend function declarations
6+
friend FRTStruct *returnInstanceOfFRTStruct(int v);
7+
friend FRTStruct *returnInstanceOfFRTStructWithAttrReturnsRetained(int v);
8+
friend FRTStruct *returnInstanceOfFRTStructWithAttrReturnsUnretained(int v);
9+
} __attribute__((swift_attr("import_reference")))
10+
__attribute__((swift_attr("retain:retainFRTStruct")))
11+
__attribute__((swift_attr("release:releaseFRTStruct")));
12+
13+
// Retain function for the FRT or SWIFT_SHARED_REFERENCE type FRTStruct
14+
void retainFRTStruct(FRTStruct *_Nonnull b) {}
15+
16+
// Release function for the FRT or SWIFT_SHARED_REFERENCE type FRTStruct
17+
void releaseFRTStruct(FRTStruct *_Nonnull b) {}
18+
19+
// Friend function definition
20+
FRTStruct *returnInstanceOfFRTStruct() { return new FRTStruct; }
21+
22+
// Friend function definition
23+
FRTStruct *returnInstanceOfFRTStructWithAttrReturnsRetained()
24+
__attribute__((swift_attr("returns_retained"))) {
25+
return new FRTStruct;
26+
}
27+
28+
// Friend function definition
29+
FRTStruct *returnInstanceOfFRTStructWithAttrReturnsUnretained()
30+
__attribute__((swift_attr("returns_unretained"))) {
31+
return new FRTStruct;
32+
}
33+
34+
// Global/free C++ functions returning FRT without any attributes
35+
FRTStruct *_Nonnull global_function_returning_FRT();
36+
FRTStruct *_Nonnull global_function_returning_copy();
37+
FRTStruct *_Nonnull global_function_returning_create();
38+
FRTStruct *_Nonnull global_function_returning_init();
39+
FRTStruct *_Nonnull global_function_returning_clone();
40+
41+
// Global/free C++ functions returning FRT with attribute
42+
// swift_attr("returns_retained") or SWIFT_RETURNS_RETAINED
43+
FRTStruct *_Nonnull global_function_returning_FRT_with_attr_returns_retained()
44+
__attribute__((swift_attr("returns_retained")));
45+
FRTStruct *_Nonnull global_function_returning_copy_with_attr_returns_retained()
46+
__attribute__((swift_attr("returns_retained")));
47+
FRTStruct
48+
*_Nonnull global_function_returning_create_with_attr_returns_retained()
49+
__attribute__((swift_attr("returns_retained")));
50+
FRTStruct *_Nonnull global_function_returning_init_with_attr_returns_retained()
51+
__attribute__((swift_attr("returns_retained")));
52+
FRTStruct *_Nonnull global_function_returning_clone_with_attr_returns_retained()
53+
__attribute__((swift_attr("returns_retained")));
54+
55+
// Global/free C++ functions returning FRT with attribute
56+
// swift_attr("returns_unretained") or SWIFT_RETURNS_UNRETAINED
57+
FRTStruct *_Nonnull global_function_returning_FRT_with_attr_returns_unretained()
58+
__attribute__((swift_attr("returns_unretained")));
59+
FRTStruct
60+
*_Nonnull global_function_returning_copy_with_attr_returns_unretained()
61+
__attribute__((swift_attr("returns_unretained")));
62+
FRTStruct
63+
*_Nonnull global_function_returning_create_with_attr_returns_unretained()
64+
__attribute__((swift_attr("returns_unretained")));
65+
FRTStruct
66+
*_Nonnull global_function_returning_init_with_attr_returns_unretained()
67+
__attribute__((swift_attr("returns_unretained")));
68+
FRTStruct
69+
*_Nonnull global_function_returning_clone_with_attr_returns_unretained()
70+
__attribute__((swift_attr("returns_unretained")));
71+
72+
// Static Global/free functions returning FRT
73+
static FRTStruct *_Nonnull global_static_function_returning_FRT();
74+
static FRTStruct
75+
*_Nonnull global_static_function_returning_FRT_with_attr_returns_retained()
76+
__attribute__((swift_attr("returns_retained")));
77+
static FRTStruct
78+
*_Nonnull global_static_function_returning_FRT_with_attr_returns_unretained()
79+
__attribute__((swift_attr("returns_unretained")));
80+
static FRTStruct *_Nonnull global_static_function_returning_copy();
81+
static FRTStruct *_Nonnull global_static_function_returning_create();
82+
static FRTStruct
83+
*_Nonnull global_static_function_returning_copy_with_attr_returns_retained()
84+
__attribute__((swift_attr("returns_retained")));
85+
static FRTStruct
86+
*_Nonnull global_static_function_returning_copy_with_attr_returns_unretained()
87+
__attribute__((swift_attr("returns_unretained")));
88+
89+
// Global/free functions returning FRT without _Nonnull
90+
FRTStruct *global_function_returning_FRT_wihout_Nonnull();
91+
FRTStruct *
92+
global_function_returning_FRT_with_attr_returns_retained_wihout_Nonnull()
93+
__attribute__((swift_attr("returns_retained")));
94+
FRTStruct *
95+
global_function_returning_FRT_with_attr_returns_unretained_wihout_Nonnull()
96+
__attribute__((swift_attr("returns_unretained")));
97+
FRTStruct *global_function_returning_copy_wihout_Nonnull();
98+
FRTStruct *global_function_returning_create_wihout_Nonnull();
99+
FRTStruct *
100+
global_function_returning_copy_with_attr_returns_retained_wihout_Nonnull()
101+
__attribute__((swift_attr("returns_retained")));
102+
FRTStruct *
103+
global_function_returning_copy_with_attr_returns_unretained_wihout_Nonnull()
104+
__attribute__((swift_attr("returns_unretained")));
105+
106+
// Struct having static methods returning FRT without any attributes
107+
struct StructWithStaticMethodsReturningFRTWithoutAttributes {
108+
static FRTStruct *_Nonnull StaticMethodReturningFRT();
109+
static FRTStruct *_Nonnull StaticMethodReturningFRT_copy();
110+
static FRTStruct *_Nonnull StaticMethodReturningFRT_create();
111+
static FRTStruct *_Nonnull StaticMethodReturningFRT_init();
112+
static FRTStruct *_Nonnull StaticMethodReturningFRT_clone();
113+
};
114+
115+
// Struct having static methods returning FRT with attribute
116+
// swift_attr("returns_retained") or SWIFT_RETURNS_RETAINED
117+
struct StructWithStaticMethodsReturningFRTWithAttributeReturnsRetained {
118+
static FRTStruct *_Nonnull StaticMethodReturningFRT()
119+
__attribute__((swift_attr("returns_retained")));
120+
static FRTStruct *_Nonnull StaticMethodReturningFRT_copy()
121+
__attribute__((swift_attr("returns_retained")));
122+
static FRTStruct *_Nonnull StaticMethodReturningFRT_create()
123+
__attribute__((swift_attr("returns_retained")));
124+
static FRTStruct *_Nonnull StaticMethodReturningFRT_init()
125+
__attribute__((swift_attr("returns_retained")));
126+
static FRTStruct *_Nonnull StaticMethodReturningFRT_clone()
127+
__attribute__((swift_attr("returns_retained")));
128+
};
129+
130+
// Struct having static methods returning FRT with attribute
131+
// swift_attr("returns_unretained") or SWIFT_RETURNS_UNRETAINED
132+
struct StructWithStaticMethodsReturningFRTWithAttributeReturnsUnretained {
133+
static FRTStruct *_Nonnull StaticMethodReturningFRT()
134+
__attribute__((swift_attr("returns_unretained")));
135+
static FRTStruct *_Nonnull StaticMethodReturningFRT_copy()
136+
__attribute__((swift_attr("returns_unretained")));
137+
static FRTStruct *_Nonnull StaticMethodReturningFRT_create()
138+
__attribute__((swift_attr("returns_unretained")));
139+
static FRTStruct *_Nonnull StaticMethodReturningFRT_init()
140+
__attribute__((swift_attr("returns_unretained")));
141+
static FRTStruct *_Nonnull StaticMethodReturningFRT_clone()
142+
__attribute__((swift_attr("returns_unretained")));
143+
};
144+
145+
// Global/free C++ functions returning FRT with both attributes
146+
// swift_attr("returns_unretained") and swift_attr("returns_retained")
147+
FRTStruct
148+
*_Nonnull global_function_returning_FRT_with_both_attrs_returns_retained_returns_unretained()
149+
__attribute__((swift_attr("returns_retained")))
150+
__attribute__((swift_attr("returns_unretained")));
151+
152+
// Struct having static method returning FRT with both attributes
153+
// swift_attr("returns_unretained") and swift_attr("returns_retained")
154+
struct
155+
StructWithStaticMethodsReturningFRTWithBothAttributesReturnsRetainedAndReturnsUnretained {
156+
static FRTStruct *_Nonnull StaticMethodReturningFRT()
157+
__attribute__((swift_attr("returns_retained")))
158+
__attribute__((swift_attr("returns_unretained")));
159+
};
160+
161+
struct NonFRTStruct {};
162+
163+
// Global/free C++ functions returning non-FRT
164+
NonFRTStruct *_Nonnull global_function_returning_non_FRT();
165+
NonFRTStruct
166+
*_Nonnull global_function_returning_non_FRT_with_attr_returns_retained()
167+
__attribute__((swift_attr("returns_retained")));
168+
NonFRTStruct
169+
*_Nonnull global_function_returning_non_FRT_with_attr_returns_unretained()
170+
__attribute__((swift_attr("returns_unretained")));
171+
NonFRTStruct *_Nonnull global_function_returning_non_FRT_create();
172+
NonFRTStruct *_Nonnull global_function_returning_non_FRT_copy();
173+
174+
// Struct having static method returning non-FRT
175+
struct StructWithStaticMethodsReturningNonFRT {
176+
static NonFRTStruct *_Nonnull StaticMethodReturningNonFRT();
177+
static NonFRTStruct
178+
*_Nonnull StaticMethodReturningNonFRTWithAttrReturnsRetained()
179+
__attribute__((swift_attr("returns_retained")));
180+
static NonFRTStruct
181+
*_Nonnull StaticMethodReturningNonFRTWithAttrReturnsUnretained()
182+
__attribute__((swift_attr("returns_unretained")));
183+
static NonFRTStruct *_Nonnull StaticMethodReturningNonFRT_create();
184+
static NonFRTStruct *_Nonnull StaticMethodReturningNonFRT_copy();
185+
};
186+
187+
// Tests for templated functions
188+
template <typename T>
189+
FRTStruct *_Nonnull global_templated_function_returning_FRT(T a);
190+
191+
template <typename T>
192+
FRTStruct *_Nonnull global_templated_function_returning_FRT_copy(T a);
193+
194+
template <typename T>
195+
FRTStruct *_Nonnull global_templated_function_returning_FRT_create(T a);
196+
197+
template <typename T>
198+
FRTStruct *_Nonnull global_templated_function_returning_FRT_init(T a);
199+
200+
template <typename T>
201+
FRTStruct *_Nonnull global_templated_function_returning_FRT_clone(T a);
202+
203+
template <typename T>
204+
FRTStruct
205+
*_Nonnull global_templated_function_returning_FRT_with_attr_returns_retained(
206+
T a) __attribute__((swift_attr("returns_retained")));
207+
208+
template <typename T>
209+
FRTStruct
210+
*_Nonnull global_templated_function_returning_FRT_copy_with_attr_returns_retained(
211+
T a) __attribute__((swift_attr("returns_retained")));
212+
213+
template <typename T>
214+
FRTStruct
215+
*_Nonnull global_templated_function_returning_FRT_create_with_attr_returns_retained(
216+
T a) __attribute__((swift_attr("returns_retained")));
217+
218+
template <typename T>
219+
FRTStruct
220+
*_Nonnull global_templated_function_returning_FRT_with_attr_returns_unretained(
221+
T a) __attribute__((swift_attr("returns_unretained")));
222+
223+
template <typename T>
224+
FRTStruct
225+
*_Nonnull global_templated_function_returning_FRT_copy_with_attr_returns_unretained(
226+
T a) __attribute__((swift_attr("returns_unretained")));
227+
228+
template <typename T>
229+
FRTStruct
230+
*_Nonnull global_templated_function_returning_FRT_create_with_attr_returns_unretained(
231+
T a) __attribute__((swift_attr("returns_unretained")));

test/Interop/Cxx/foreign-reference/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ module DerivedFieldGetterReturnsOwnedFRT {
4949
requires cplusplus
5050
}
5151

52+
module FunctionsAndMethodsReturningFRT {
53+
header "cxx-functions-and-methods-returning-frt.h"
54+
requires cplusplus
55+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: rm -rf %t
2+
// RUN: not %target-swift-frontend -typecheck -I %S/Inputs %s -cxx-interoperability-mode=upcoming-swift 2>&1 | %FileCheck %s
3+
4+
import FunctionsAndMethodsReturningFRT
5+
6+
let frtLocalVar1 = global_function_returning_FRT_with_both_attrs_returns_retained_returns_unretained()
7+
// CHECK: error: 'global_function_returning_FRT_with_both_attrs_returns_retained_returns_unretained' cannot be annotated with both swift_attr('returns_retained') and swift_attr('returns_unretained') attributes
8+
9+
let frtLocalVar2 = StructWithStaticMethodsReturningFRTWithBothAttributesReturnsRetainedAndReturnsUnretained.StaticMethodReturningFRT()
10+
// CHECK: error: 'StaticMethodReturningFRT' cannot be annotated with both swift_attr('returns_retained') and swift_attr('returns_unretained') attributes

0 commit comments

Comments
 (0)