Skip to content

Commit 42a2e0e

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

File tree

5 files changed

+122
-2
lines changed

5 files changed

+122
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 26 additions & 1 deletion
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

Lines changed: 26 additions & 1 deletion
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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,4 +430,54 @@ 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+
BaseType *returnBaseType() { return new BaseType(); }
451+
DerivedType *returnDerivedType() { return new DerivedType(); }
452+
DerivedType2 *returnDerivedType2() { return new DerivedType2(); }
453+
454+
struct __attribute__((swift_attr("import_reference")))
455+
__attribute__((swift_attr("retain:bRetain")))
456+
__attribute__((swift_attr("release:bRelease"))) BaseTypeNonDefault {};
457+
458+
struct __attribute__((swift_attr("import_reference")))
459+
__attribute__((swift_attr("retain:dRetain")))
460+
__attribute__((swift_attr("release:dRelease"))) DerivedTypeNonDefault
461+
: public BaseTypeNonDefault {};
462+
463+
BaseTypeNonDefault *returnBaseTypeNonDefault() { return new BaseTypeNonDefault(); } // expected-warning {{'returnBaseTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
464+
DerivedTypeNonDefault *returnDerivedTypeNonDefault() { return new DerivedTypeNonDefault(); } // expected-warning {{'returnDerivedTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
465+
466+
} // namespace DefaultOwnershipInheritance
467+
468+
void baseRetain(DefaultOwnershipInheritance::BaseType *v) {};
469+
void baseRelease(DefaultOwnershipInheritance::BaseType *v) {};
470+
471+
void derivedRetain(DefaultOwnershipInheritance::DerivedType *v) {};
472+
void derivedRelease(DefaultOwnershipInheritance::DerivedType *v) {};
473+
474+
void derivedRetain2(DefaultOwnershipInheritance::DerivedType2 *v) {};
475+
void derivedRelease2(DefaultOwnershipInheritance::DerivedType2 *v) {};
476+
477+
void bRetain(DefaultOwnershipInheritance::BaseTypeNonDefault *v) {};
478+
void bRelease(DefaultOwnershipInheritance::BaseTypeNonDefault *v) {};
479+
480+
void dRetain(DefaultOwnershipInheritance::DerivedTypeNonDefault *v) {};
481+
void dRelease(DefaultOwnershipInheritance::DerivedTypeNonDefault *v) {};
482+
433483
SWIFT_END_NULLABILITY_ANNOTATIONS

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

Lines changed: 5 additions & 0 deletions
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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,19 @@ 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.returnBaseTypeNonDefault()
280+
// CHECK: function_ref {{.*}}returnBaseTypeNonDefault{{.*}} : $@convention(c) () -> DefaultOwnershipInheritance.BaseTypeNonDefault
281+
282+
let _ = DefaultOwnershipInheritance.returnDerivedTypeNonDefault()
283+
// CHECK: function_ref {{.*}}returnDerivedTypeNonDefault{{.*}} : $@convention(c) () -> DefaultOwnershipInheritance.DerivedTypeNonDefault
269284
}

0 commit comments

Comments
 (0)