Skip to content

Commit 8db53ac

Browse files
committed
[cxx-interop] Diagnose ObjC APIs returning SWIFT_SHARED_REFERENCE types
rdar://142500663
1 parent 426d471 commit 8db53ac

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3370,7 +3370,11 @@ namespace {
33703370

33713371
/// Emit diagnostics for incorrect usage of SWIFT_RETURNS_RETAINED and
33723372
/// SWIFT_RETURNS_UNRETAINED
3373-
void checkBridgingAttrs(const clang::FunctionDecl *decl) {
3373+
void checkBridgingAttrs(const clang::NamedDecl *decl) {
3374+
assert(isa<clang::FunctionDecl>(decl) ||
3375+
isa<clang::ObjCMethodDecl>(decl) &&
3376+
"checkBridgingAttrs called with a clang::NamedDecl which is "
3377+
"neither clang::FunctionDecl nor clang::ObjCMethodDecl");
33743378
bool returnsRetainedAttrIsPresent = false;
33753379
bool returnsUnretainedAttrIsPresent = false;
33763380
if (decl->hasAttrs()) {
@@ -3386,14 +3390,29 @@ namespace {
33863390
}
33873391

33883392
HeaderLoc loc(decl->getLocation());
3389-
if (isForeignReferenceTypeWithoutImmortalAttrs(decl->getReturnType())) {
3393+
bool isForeignReferenceReturnType = false;
3394+
if (const auto *funcDecl = dyn_cast<clang::FunctionDecl>(decl)) {
3395+
if (isForeignReferenceTypeWithoutImmortalAttrs(
3396+
funcDecl->getReturnType())) {
3397+
isForeignReferenceReturnType = true;
3398+
}
3399+
} else if (const auto *objCMethodDecl =
3400+
dyn_cast<clang::ObjCMethodDecl>(decl)) {
3401+
if (isForeignReferenceTypeWithoutImmortalAttrs(
3402+
objCMethodDecl->getReturnType())) {
3403+
isForeignReferenceReturnType = true;
3404+
}
3405+
}
3406+
3407+
if (isForeignReferenceReturnType) {
33903408
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
33913409
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
33923410
decl);
33933411
} else if (!returnsRetainedAttrIsPresent &&
33943412
!returnsUnretainedAttrIsPresent) {
3395-
bool unannotatedCxxAPIWarningNeeded = false;
3396-
if (!isa<clang::CXXDeductionGuideDecl>(decl)) {
3413+
bool unannotatedAPIWarningNeeded = false;
3414+
if (isa<clang::FunctionDecl>(decl) &&
3415+
!isa<clang::CXXDeductionGuideDecl>(decl)) {
33973416
if (const auto *methodDecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
33983417
// FIXME: In the future we should support SWIFT_RETURNS_RETAINED
33993418
// and SWIFT_RETURNS_UNRETAINED for overloaded C++ operators
@@ -3403,15 +3422,17 @@ namespace {
34033422
!methodDecl->isOverloadedOperator() &&
34043423
methodDecl->isUserProvided()) {
34053424
// normal c++ member method
3406-
unannotatedCxxAPIWarningNeeded = true;
3425+
unannotatedAPIWarningNeeded = true;
34073426
}
34083427
} else {
3409-
// global or top-level function
3410-
unannotatedCxxAPIWarningNeeded = true;
3428+
// global or top-level C/C++ function
3429+
unannotatedAPIWarningNeeded = true;
34113430
}
3431+
} else if (isa<clang::ObjCMethodDecl>(decl)) {
3432+
unannotatedAPIWarningNeeded = true;
34123433
}
34133434

3414-
if (unannotatedCxxAPIWarningNeeded) {
3435+
if (unannotatedAPIWarningNeeded) {
34153436
HeaderLoc loc(decl->getLocation());
34163437
Impl.diagnose(loc, diag::no_returns_retained_returns_unretained,
34173438
decl);
@@ -4510,6 +4531,8 @@ namespace {
45104531
if (!dc)
45114532
return nullptr;
45124533

4534+
checkBridgingAttrs(decl);
4535+
45134536
// While importing the DeclContext, we might have imported the decl
45144537
// itself.
45154538
auto Known = Impl.importDeclCached(decl, getVersion());

test/Interop/Cxx/objc-correctness/Inputs/cxx-frt.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ struct CxxRefType {
99
__attribute__((swift_attr("retain:retainCxxRefType")))
1010
__attribute__((swift_attr("release:releaseCxxRefType")));
1111

12+
struct CxxValType {};
13+
1214
void retainCxxRefType(CxxRefType *_Nonnull b) {}
1315
void releaseCxxRefType(CxxRefType *_Nonnull b) {}
1416

@@ -19,18 +21,30 @@ void releaseCxxRefType(CxxRefType *_Nonnull b) {}
1921
__attribute__((swift_attr("returns_unretained")));
2022
+ (struct CxxRefType *)objCMethodReturningFRTOwned
2123
__attribute__((swift_attr("returns_retained")));
24+
+ (struct CxxRefType *)objCMethodReturningFRTBothAnnotations
25+
__attribute__((swift_attr("returns_unretained")))
26+
__attribute__((swift_attr("returns_retained")));
27+
+ (struct CxxValType *)objCMethodReturningNonCxxFrtAnannotated
28+
__attribute__((swift_attr("returns_retained")));
2229

2330
@end
2431

2532
@implementation Bridge
2633
+ (struct CxxRefType *)objCMethodReturningFRTUnannotated {
27-
};
34+
}
2835
+ (struct CxxRefType *)objCMethodReturningFRTUnowned
2936
__attribute__((swift_attr("returns_unretained"))) {
3037
}
3138
+ (struct CxxRefType *)objCMethodReturningFRTOwned
3239
__attribute__((swift_attr("returns_retained"))) {
3340
}
41+
+ (struct CxxRefType *)objCMethodReturningFRTBothAnnotations
42+
__attribute__((swift_attr("returns_unretained")))
43+
__attribute__((swift_attr("returns_retained"))) {
44+
}
45+
+ (struct CxxValType *)objCMethodReturningNonCxxFrtAnannotated
46+
__attribute__((swift_attr("returns_retained"))) {
47+
}
3448

3549
@end
3650

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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 CxxForeignRef
5+
6+
// REQUIRES: objc_interop
7+
// TODO: figure out why the test no fail on wrong error messages
8+
func testObjCMethods() {
9+
_ = Bridge.objCMethodReturningFRTBothAnnotations()
10+
// CHECK: error: 'objCMethodReturningFRTBothAnnotations' cannot be annotated with both SWIFT_RETURNS_RETAINED and SWIFT_RETURNS_UNRETAINED
11+
12+
_ = Bridge.objCMethodReturningNonCxxFrtAnannotated()
13+
// CHECK: error: 'objCMethodReturningNonCxxFrtAnannotated' cannot be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED because it is not returning a SWIFT_SHARED_REFERENCE type
14+
15+
_ = Bridge.objCMethodReturningFRTUnannotated()
16+
// CHECK: warning: 'objCMethodReturningFRTUnannotated' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE
17+
}

0 commit comments

Comments
 (0)