Skip to content

Commit 28104c0

Browse files
committed
[cxx-interop] Default ownership convention as 3rd optional parameter of SWIFT_SHARED_REFERENCE annotation
rdar://145453509
1 parent c42268e commit 28104c0

File tree

6 files changed

+195
-14
lines changed

6 files changed

+195
-14
lines changed

lib/ClangImporter/ImportDecl.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -3478,6 +3478,23 @@ namespace {
34783478
unannotatedAPIWarningNeeded = true;
34793479
}
34803480

3481+
if (const auto *returnPtrTy = retType->getAs<clang::PointerType>()) {
3482+
clang::QualType returnPointeeType = returnPtrTy->getPointeeType();
3483+
if (const auto *returnRecordType =
3484+
returnPointeeType->getAs<clang::RecordType>()) {
3485+
clang::RecordDecl *returnRecordDecl = returnRecordType->getDecl();
3486+
for (const auto *attr : returnRecordDecl->getAttrs()) {
3487+
if (const auto *swiftAttr =
3488+
dyn_cast<clang::SwiftAttrAttr>(attr)) {
3489+
if (swiftAttr->getAttribute() == "ownership:unretained" ||
3490+
swiftAttr->getAttribute() == "ownership:retained") {
3491+
unannotatedAPIWarningNeeded = false;
3492+
}
3493+
}
3494+
}
3495+
}
3496+
}
3497+
34813498
if (unannotatedAPIWarningNeeded) {
34823499
HeaderLoc loc(decl->getLocation());
34833500
Impl.diagnose(loc, diag::no_returns_retained_returns_unretained,

lib/ClangImporter/SwiftBridging/swift/bridging

+18-6
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,19 @@
4545
#define _CXX_INTEROP_CONCAT(...) \
4646
_CXX_INTEROP_CONCAT_(__VA_ARGS__,,,,,,,,,,,,,,,,,)
4747

48-
/// Specifies that a C++ `class` or `struct` is reference-counted using
48+
#define SWIFT_SHARED_REFERENCE_2ARGS(_retain, _release) \
49+
__attribute__((swift_attr("import_reference"))) \
50+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
51+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release))))
52+
53+
#define SWIFT_SHARED_REFERENCE_3ARGS(_retain, _release, _ownership) \
54+
__attribute__((swift_attr("import_reference"))) \
55+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
56+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release)))) \
57+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(ownership:_ownership))))
58+
59+
// FN_TODO: modify the documentation
60+
/// Specifies that a C++ `class` or `struct` is reference-counted using
4961
/// the given `retain` and `release` functions. This annotation lets Swift import
5062
/// such a type as reference counted type in Swift, taking advantage of Swift's
5163
/// automatic reference counting.
@@ -71,10 +83,10 @@
7183
/// object.doSomething()
7284
/// // The Swift compiler will release object here.
7385
/// ```
74-
#define SWIFT_SHARED_REFERENCE(_retain, _release) \
75-
__attribute__((swift_attr("import_reference"))) \
76-
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
77-
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release))))
86+
#define _CXX_INTEROP_GET_MACRO(_1, _2, _3, NAME, ...) NAME
87+
#define SWIFT_SHARED_REFERENCE(...) \
88+
_CXX_INTEROP_GET_MACRO(__VA_ARGS__, SWIFT_SHARED_REFERENCE_3ARGS, \
89+
SWIFT_SHARED_REFERENCE_2ARGS)(__VA_ARGS__)
7890

7991
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime
8092
/// is presumed to be immortal, i.e. the reference to such object is presumed to
@@ -196,7 +208,7 @@
196208
// Empty defines for compilers that don't support `attribute(swift_attr)`.
197209
#define SWIFT_SELF_CONTAINED
198210
#define SWIFT_RETURNS_INDEPENDENT_VALUE
199-
#define SWIFT_SHARED_REFERENCE(_retain, _release)
211+
#define SWIFT_SHARED_REFERENCE(_retain, _release, ...)
200212
#define SWIFT_IMMORTAL_REFERENCE
201213
#define SWIFT_UNSAFE_REFERENCE
202214
#define SWIFT_NAME(_name)

lib/SIL/IR/SILFunctionType.cpp

+30-8
Original file line numberDiff line numberDiff line change
@@ -1305,17 +1305,39 @@ class Conventions {
13051305
}
13061306

13071307
// Determines owned/unowned ResultConvention of the returned value based on
1308-
// returns_retained/returns_unretained attribute.
1308+
// SWIFT_RETURNS_(UN)RETAINED annotation on the C++ API and then based on
1309+
// ownership:(un)retained as the 3rd optional parameter of
1310+
// SWIFT_SHARED_REFERENCE annotation on the returned type
13091311
std::optional<ResultConvention>
13101312
getCxxRefConventionWithAttrs(const TypeLowering &tl,
13111313
const clang::Decl *decl) const {
1312-
if (tl.getLoweredType().isForeignReferenceType() && decl->hasAttrs()) {
1313-
for (const auto *attr : decl->getAttrs()) {
1314-
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
1315-
if (swiftAttr->getAttribute() == "returns_unretained") {
1316-
return ResultConvention::Unowned;
1317-
} else if (swiftAttr->getAttribute() == "returns_retained") {
1318-
return ResultConvention::Owned;
1314+
if (tl.getLoweredType().isForeignReferenceType()) {
1315+
if (decl->hasAttrs()) {
1316+
for (const auto *attr : decl->getAttrs()) {
1317+
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
1318+
if (swiftAttr->getAttribute() == "returns_unretained") {
1319+
return ResultConvention::Unowned;
1320+
} else if (swiftAttr->getAttribute() == "returns_retained") {
1321+
return ResultConvention::Owned;
1322+
}
1323+
}
1324+
}
1325+
}
1326+
if (auto *classDecl = tl.getLoweredType()
1327+
.getASTType()
1328+
.getPointer()
1329+
->lookThroughAllOptionalTypes()
1330+
->getClassOrBoundGenericClass()) {
1331+
if (auto clangRecordDecl =
1332+
dyn_cast<clang::RecordDecl>(classDecl->getClangDecl())) {
1333+
for (const auto *attr : clangRecordDecl->getAttrs()) {
1334+
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
1335+
if (swiftAttr->getAttribute() == "ownership:unretained") {
1336+
return ResultConvention::Unowned;
1337+
} else if (swiftAttr->getAttribute() == "ownership:retained") {
1338+
return ResultConvention::Owned;
1339+
}
1340+
}
13191341
}
13201342
}
13211343
}

test/Interop/Cxx/foreign-reference/Inputs/cxx-functions-and-methods-returning-frt.h

+104
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include "visibility.h"
23
#include <functional>
34

45
// FRT or SWIFT_SHARED_REFERENCE type
@@ -326,3 +327,106 @@ struct Derived : Base {
326327
FRTStruct *_Nonnull VirtualMethodReturningFRTUnowned() override
327328
__attribute__((swift_attr("returns_unretained")));
328329
};
330+
331+
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
332+
333+
namespace DefaultOwnershipConventionOnCXXForegnRefType {
334+
struct __attribute__((swift_attr("import_reference")))
335+
__attribute__((swift_attr("retain:defRetain1")))
336+
__attribute__((swift_attr("release:defRelease1")))
337+
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {};
338+
339+
RefTypeDefaultRetained *returnRefTypeDefaultRetained() {
340+
return new RefTypeDefaultRetained();
341+
}
342+
343+
struct __attribute__((swift_attr("import_reference")))
344+
__attribute__((swift_attr("retain:defRetain2")))
345+
__attribute__((swift_attr("release:defRelease2")))
346+
__attribute__((swift_attr("ownership:unretained"))) RefTypeDefaultUnretained {};
347+
348+
RefTypeDefaultUnretained *returnRefTypeDefaultUnretained() {
349+
return new RefTypeDefaultUnretained();
350+
}
351+
} // namespace DefaultOwnershipConventionOnCXXForegnRefType
352+
void defRetain1(
353+
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultRetained *v) {};
354+
void defRelease1(
355+
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultRetained *v) {};
356+
357+
void defRetain2(
358+
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultUnretained *v) {
359+
};
360+
void defRelease2(
361+
DefaultOwnershipConventionOnCXXForegnRefType::RefTypeDefaultUnretained *v) {
362+
};
363+
364+
namespace FunctionAnnotationHasPrecedence {
365+
struct __attribute__((swift_attr("import_reference")))
366+
__attribute__((swift_attr("retain:defaultRetain1")))
367+
__attribute__((swift_attr("release:defaultRelease1")))
368+
__attribute__((swift_attr("ownership:unretained"))) RefTypeDefaultUnRetained {};
369+
370+
RefTypeDefaultUnRetained *returnRefTypeDefaultUnRetained() {
371+
return new RefTypeDefaultUnRetained();
372+
}
373+
RefTypeDefaultUnRetained *returnRefTypeDefaultUnRetainedAnnotatedRetained()
374+
__attribute__((swift_attr("returns_retained"))) {
375+
return new RefTypeDefaultUnRetained();
376+
}
377+
378+
struct __attribute__((swift_attr("import_reference")))
379+
__attribute__((swift_attr("retain:defaultRetain2")))
380+
__attribute__((swift_attr("release:defaultRelease2")))
381+
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {};
382+
383+
RefTypeDefaultRetained *returnRefTypeDefaultRetained() {
384+
return new RefTypeDefaultRetained();
385+
}
386+
RefTypeDefaultRetained *returnRefTypeDefaultRetainedAnnotatedUnRetained()
387+
__attribute__((swift_attr("returns_unretained"))) {
388+
return new RefTypeDefaultRetained();
389+
}
390+
391+
} // namespace FunctionAnnotationHasPrecedence
392+
393+
void defaultRetain1(
394+
FunctionAnnotationHasPrecedence::RefTypeDefaultUnRetained *v) {};
395+
void defaultRelease1(
396+
FunctionAnnotationHasPrecedence::RefTypeDefaultUnRetained *v) {};
397+
398+
void defaultRetain2(
399+
FunctionAnnotationHasPrecedence::RefTypeDefaultRetained *v) {};
400+
void defaultRelease2(
401+
FunctionAnnotationHasPrecedence::RefTypeDefaultRetained *v) {};
402+
403+
namespace DefaultOwnershipSuppressUnannotatedAPIWarning {
404+
405+
struct __attribute__((swift_attr("import_reference")))
406+
__attribute__((swift_attr("retain:rretain")))
407+
__attribute__((swift_attr("release:rrelease"))) RefType {};
408+
409+
RefType *returnRefType() { return new RefType(); }
410+
411+
struct __attribute__((swift_attr("import_reference")))
412+
__attribute__((swift_attr("retain:dretain")))
413+
__attribute__((swift_attr("release:drelease")))
414+
__attribute__((swift_attr("ownership:retained"))) RefTypeDefaultRetained {};
415+
416+
RefTypeDefaultRetained *returnRefTypeDefaultRetained() {
417+
return new RefTypeDefaultRetained();
418+
}
419+
420+
} // namespace DefaultOwnershipSuppressUnannotatedAPIWarning
421+
422+
void rretain(DefaultOwnershipSuppressUnannotatedAPIWarning::RefType *v) {};
423+
void rrelease(DefaultOwnershipSuppressUnannotatedAPIWarning::RefType *v) {};
424+
425+
void dretain(
426+
DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) {
427+
};
428+
void drelease(
429+
DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) {
430+
};
431+
432+
SWIFT_END_NULLABILITY_ANNOTATIONS

test/Interop/Cxx/foreign-reference/frt-retained-unretained-attributes-error.swift

+6
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,9 @@ let w = x - y
5353
let f = FunctionVoidToFRTStruct()
5454
let frt = f()
5555
// CHECK-NOT: warning: 'operator()' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE
56+
57+
58+
let _ = DefaultOwnershipSuppressUnannotatedAPIWarning.returnRefType()
59+
// CHECK: warning: 'returnRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE
60+
let _ = DefaultOwnershipSuppressUnannotatedAPIWarning.returnRefTypeDefaultRetained()
61+
// CHECK-NOT: warning: 'returnRefTypeDefaultRetained' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE

test/Interop/Cxx/foreign-reference/frt-retained-unretained-attributes.swift

+20
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,23 @@ func testVirtualMethods(base: Base, derived: Derived) {
245245
var frt4 = mutableDerived.VirtualMethodReturningFRTOwned()
246246
// CHECK: function_ref @{{.*}}VirtualMethodReturningFRTOwned{{.*}} : $@convention(cxx_method) (@inout Derived) -> @owned FRTStruct
247247
}
248+
249+
func testDefaultOwnershipAnnotation() {
250+
let _ = DefaultOwnershipConventionOnCXXForegnRefType.returnRefTypeDefaultRetained()
251+
// CHECK: function_ref {{.*}}returnRefTypeDefaultRetained{{.*}} : $@convention(c) () -> @owned DefaultOwnershipConventionOnCXXForegnRefType.RefTypeDefaultRetained
252+
253+
let _ = DefaultOwnershipConventionOnCXXForegnRefType.returnRefTypeDefaultUnretained()
254+
// CHECK: function_ref {{.*}}returnRefTypeDefaultUnretained{{.*}} : $@convention(c) () -> DefaultOwnershipConventionOnCXXForegnRefType.RefTypeDefaultUnretained
255+
256+
let _ = FunctionAnnotationHasPrecedence.returnRefTypeDefaultUnRetained()
257+
// CHECK: function_ref {{.*}}returnRefTypeDefaultUnRetained{{.*}} : $@convention(c) () -> FunctionAnnotationHasPrecedence.RefTypeDefaultUnRetained
258+
259+
let _ = FunctionAnnotationHasPrecedence.returnRefTypeDefaultUnRetainedAnnotatedRetained()
260+
// CHECK: function_ref {{.*}}returnRefTypeDefaultUnRetainedAnnotatedRetained{{.*}} : $@convention(c) () -> @owned FunctionAnnotationHasPrecedence.RefTypeDefaultUnRetained
261+
262+
let _ = FunctionAnnotationHasPrecedence.returnRefTypeDefaultRetained()
263+
// CHECK: function_ref {{.*}}returnRefTypeDefaultRetained{{.*}} : $@convention(c) () -> @owned FunctionAnnotationHasPrecedence.RefTypeDefaultRetained
264+
265+
let _ = FunctionAnnotationHasPrecedence.returnRefTypeDefaultRetainedAnnotatedUnRetained()
266+
// CHECK: function_ref {{.*}}returnRefTypeDefaultRetainedAnnotatedUnRetained{{.*}} : $@convention(c) () -> FunctionAnnotationHasPrecedence.RefTypeDefaultRetained
267+
}

0 commit comments

Comments
 (0)