Skip to content

Commit f52ef8b

Browse files
committed
Inferring SWIFT_RETURNS_(UN)RETAINED_BY_DEFAULT annotations in C++ inheritance
1 parent b0fbff0 commit f52ef8b

File tree

5 files changed

+143
-2
lines changed

5 files changed

+143
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -3618,6 +3618,31 @@ namespace {
36183618
return std::nullopt;
36193619
}
36203620

3621+
template <typename T>
3622+
std::optional<T> matchSwiftAttrConsideringInheritance(
3623+
const clang::Decl *decl,
3624+
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
3625+
if (!decl)
3626+
return std::nullopt;
3627+
3628+
if (auto match = matchSwiftAttr<T>(decl, patterns))
3629+
return match;
3630+
3631+
if (const auto *recordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
3632+
for (const auto &baseSpecifier : recordDecl->bases()) {
3633+
const clang::CXXRecordDecl *baseDecl =
3634+
baseSpecifier.getType()->getAsCXXRecordDecl();
3635+
if (!baseDecl)
3636+
continue;
3637+
if (auto match =
3638+
matchSwiftAttrConsideringInheritance<T>(baseDecl, patterns))
3639+
return match;
3640+
}
3641+
}
3642+
3643+
return std::nullopt;
3644+
}
3645+
36213646
/// Emit diagnostics for incorrect usage of SWIFT_RETURNS_RETAINED and
36223647
/// SWIFT_RETURNS_UNRETAINED
36233648
void checkBridgingAttrs(const clang::NamedDecl *decl) {
@@ -3686,7 +3711,7 @@ namespace {
36863711
if (const auto *returnPtrTy = retType->getAs<clang::PointerType>()) {
36873712
if (clang::RecordDecl *returnRecordDecl =
36883713
returnPtrTy->getPointeeType()->getAsRecordDecl()) {
3689-
if (auto match = matchSwiftAttr<bool>(
3714+
if (auto match = matchSwiftAttrConsideringInheritance<bool>(
36903715
returnRecordDecl,
36913716
{
36923717
{"returns_retained_by_default", true},

lib/SIL/IR/SILFunctionType.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,31 @@ matchSwiftAttr(const clang::Decl *decl,
12701270
return std::nullopt;
12711271
}
12721272

1273+
template <typename T>
1274+
std::optional<T> matchSwiftAttrConsideringInheritance(
1275+
const clang::Decl *decl,
1276+
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
1277+
if (!decl)
1278+
return std::nullopt;
1279+
1280+
if (auto match = matchSwiftAttr<T>(decl, patterns))
1281+
return match;
1282+
1283+
if (const auto *recordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
1284+
for (const auto &baseSpecifier : recordDecl->bases()) {
1285+
const clang::CXXRecordDecl *baseDecl =
1286+
baseSpecifier.getType()->getAsCXXRecordDecl();
1287+
if (!baseDecl)
1288+
continue;
1289+
if (auto match =
1290+
matchSwiftAttrConsideringInheritance<T>(baseDecl, patterns))
1291+
return match;
1292+
}
1293+
}
1294+
1295+
return std::nullopt;
1296+
}
1297+
12731298
class Conventions {
12741299
ConventionsKind kind;
12751300

@@ -1393,7 +1418,7 @@ class Conventions {
13931418
llvm::dyn_cast<clang::PointerType>(desugaredReturnTy)) {
13941419
if (clang::RecordDecl *clangRecordDecl =
13951420
ptrType->getPointeeType()->getAsRecordDecl())
1396-
return matchSwiftAttr<ResultConvention>(
1421+
return matchSwiftAttrConsideringInheritance<ResultConvention>(
13971422
clangRecordDecl,
13981423
{{"returns_unretained_by_default", ResultConvention::Unowned},
13991424
{"returns_retained_by_default", ResultConvention::Owned}});

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

+68
Original file line numberDiff line numberDiff line change
@@ -430,4 +430,72 @@ void drelease(
430430
DefaultOwnershipSuppressUnannotatedAPIWarning::RefTypeDefaultRetained *v) {
431431
};
432432

433+
namespace DefaultOwnershipInheritance {
434+
435+
struct __attribute__((swift_attr("import_reference")))
436+
__attribute__((swift_attr("retain:baseRetain")))
437+
__attribute__((swift_attr("release:baseRelease")))
438+
__attribute__((swift_attr("returns_retained_by_default"))) BaseType {};
439+
440+
struct __attribute__((swift_attr("import_reference")))
441+
__attribute__((swift_attr("retain:derivedRetain")))
442+
__attribute__((swift_attr("release:derivedRelease"))) DerivedType
443+
: public BaseType {};
444+
445+
struct __attribute__((swift_attr("import_reference")))
446+
__attribute__((swift_attr("retain:derivedRetain2")))
447+
__attribute__((swift_attr("release:derivedRelease2"))) DerivedType2
448+
: public DerivedType {};
449+
450+
struct __attribute__((swift_attr("import_reference")))
451+
__attribute__((swift_attr("retain:derivedRetain3")))
452+
__attribute__((swift_attr("release:derivedRelease3"))) __attribute__((
453+
swift_attr("returns_unretained_by_default"))) DerivedTypeOverrideDefault
454+
: public DerivedType {};
455+
456+
BaseType *returnBaseType() { return new BaseType(); }
457+
DerivedType *returnDerivedType() { return new DerivedType(); }
458+
DerivedType2 *returnDerivedType2() { return new DerivedType2(); }
459+
DerivedTypeOverrideDefault *returnDerivedTypeOverrideDefault() {
460+
return new DerivedTypeOverrideDefault();
461+
}
462+
463+
struct __attribute__((swift_attr("import_reference")))
464+
__attribute__((swift_attr("retain:bRetain")))
465+
__attribute__((swift_attr("release:bRelease"))) BaseTypeNonDefault {};
466+
467+
struct __attribute__((swift_attr("import_reference")))
468+
__attribute__((swift_attr("retain:dRetain")))
469+
__attribute__((swift_attr("release:dRelease"))) DerivedTypeNonDefault
470+
: public BaseTypeNonDefault {};
471+
472+
BaseTypeNonDefault *returnBaseTypeNonDefault() { // expected-warning {{'returnBaseTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
473+
return new BaseTypeNonDefault();
474+
}
475+
DerivedTypeNonDefault *returnDerivedTypeNonDefault() { // expected-warning {{'returnDerivedTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
476+
return new DerivedTypeNonDefault();
477+
}
478+
479+
} // namespace DefaultOwnershipInheritance
480+
481+
void baseRetain(DefaultOwnershipInheritance::BaseType *v) {};
482+
void baseRelease(DefaultOwnershipInheritance::BaseType *v) {};
483+
484+
void derivedRetain(DefaultOwnershipInheritance::DerivedType *v) {};
485+
void derivedRelease(DefaultOwnershipInheritance::DerivedType *v) {};
486+
487+
void derivedRetain2(DefaultOwnershipInheritance::DerivedType2 *v) {};
488+
void derivedRelease2(DefaultOwnershipInheritance::DerivedType2 *v) {};
489+
490+
void derivedRetain3(
491+
DefaultOwnershipInheritance::DerivedTypeOverrideDefault *v) {};
492+
void derivedRelease3(
493+
DefaultOwnershipInheritance::DerivedTypeOverrideDefault *v) {};
494+
495+
void bRetain(DefaultOwnershipInheritance::BaseTypeNonDefault *v) {};
496+
void bRelease(DefaultOwnershipInheritance::BaseTypeNonDefault *v) {};
497+
498+
void dRetain(DefaultOwnershipInheritance::DerivedTypeNonDefault *v) {};
499+
void dRelease(DefaultOwnershipInheritance::DerivedTypeNonDefault *v) {};
500+
433501
SWIFT_END_NULLABILITY_ANNOTATIONS

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

+5
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ let nonFrt = NonFRTStruct()
3434
let nonFrtLocalVar1 = global_function_returning_templated_retrun_frt_owned(nonFrt)
3535
let _ = DefaultOwnershipSuppressUnannotatedAPIWarning.returnRefType()
3636
let _ = DefaultOwnershipSuppressUnannotatedAPIWarning.returnRefTypeDefaultRetained()
37+
let _ = DefaultOwnershipInheritance.returnBaseType()
38+
let _ = DefaultOwnershipInheritance.returnDerivedType()
39+
let _ = DefaultOwnershipInheritance.returnDerivedType2()
40+
let _ = DefaultOwnershipInheritance.returnBaseTypeNonDefault()
41+
let _ = DefaultOwnershipInheritance.returnDerivedTypeNonDefault()

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

+18
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,22 @@ func testDefaultOwnershipAnnotation() {
266266

267267
let _ = FunctionAnnotationHasPrecedence.returnRefTypeDefaultRetainedAnnotatedUnRetained()
268268
// CHECK: function_ref {{.*}}returnRefTypeDefaultRetainedAnnotatedUnRetained{{.*}} : $@convention(c) () -> FunctionAnnotationHasPrecedence.RefTypeDefaultRetained
269+
270+
let _ = DefaultOwnershipInheritance.returnBaseType()
271+
// CHECK: function_ref {{.*}}returnBaseType{{.*}} : $@convention(c) () -> @owned DefaultOwnershipInheritance.BaseType
272+
273+
let _ = DefaultOwnershipInheritance.returnDerivedType()
274+
// CHECK: function_ref {{.*}}returnDerivedType{{.*}} : $@convention(c) () -> @owned DefaultOwnershipInheritance.DerivedType
275+
276+
let _ = DefaultOwnershipInheritance.returnDerivedType2()
277+
// CHECK: function_ref {{.*}}returnDerivedType2{{.*}} : $@convention(c) () -> @owned DefaultOwnershipInheritance.DerivedType2
278+
279+
let _ = DefaultOwnershipInheritance.returnDerivedTypeOverrideDefault()
280+
// CHECK: function_ref {{.*}}returnDerivedTypeOverrideDefault{{.*}} : $@convention(c) () -> DefaultOwnershipInheritance.DerivedTypeOverrideDefault
281+
282+
let _ = DefaultOwnershipInheritance.returnBaseTypeNonDefault()
283+
// CHECK: function_ref {{.*}}returnBaseTypeNonDefault{{.*}} : $@convention(c) () -> DefaultOwnershipInheritance.BaseTypeNonDefault
284+
285+
let _ = DefaultOwnershipInheritance.returnDerivedTypeNonDefault()
286+
// CHECK: function_ref {{.*}}returnDerivedTypeNonDefault{{.*}} : $@convention(c) () -> DefaultOwnershipInheritance.DerivedTypeNonDefault
269287
}

0 commit comments

Comments
 (0)