Skip to content

Commit eba183a

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

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3376,7 +3376,11 @@ namespace {
33763376

33773377
/// Emit diagnostics for incorrect usage of SWIFT_RETURNS_RETAINED and
33783378
/// SWIFT_RETURNS_UNRETAINED
3379-
void checkBridgingAttrs(const clang::FunctionDecl *decl) {
3379+
void checkBridgingAttrs(const clang::NamedDecl *decl) {
3380+
assert(isa<clang::FunctionDecl>(decl) ||
3381+
isa<clang::ObjCMethodDecl>(decl) &&
3382+
"checkBridgingAttrs called with a clang::NamedDecl which is "
3383+
"neither clang::FunctionDecl nor clang::ObjCMethodDecl");
33803384
bool returnsRetainedAttrIsPresent = false;
33813385
bool returnsUnretainedAttrIsPresent = false;
33823386
if (decl->hasAttrs()) {
@@ -3392,14 +3396,19 @@ namespace {
33923396
}
33933397

33943398
HeaderLoc loc(decl->getLocation());
3395-
if (isForeignReferenceTypeWithoutImmortalAttrs(decl->getReturnType())) {
3399+
const auto retType =
3400+
isa<clang::FunctionDecl>(decl)
3401+
? dyn_cast<clang::FunctionDecl>(decl)->getReturnType()
3402+
: dyn_cast<clang::ObjCMethodDecl>(decl)->getReturnType();
3403+
if (isForeignReferenceTypeWithoutImmortalAttrs(retType)) {
33963404
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
33973405
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
33983406
decl);
33993407
} else if (!returnsRetainedAttrIsPresent &&
34003408
!returnsUnretainedAttrIsPresent) {
3401-
bool unannotatedCxxAPIWarningNeeded = false;
3402-
if (!isa<clang::CXXDeductionGuideDecl>(decl)) {
3409+
bool unannotatedAPIWarningNeeded = false;
3410+
if (isa<clang::FunctionDecl>(decl) &&
3411+
!isa<clang::CXXDeductionGuideDecl>(decl)) {
34033412
if (const auto *methodDecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
34043413
// FIXME: In the future we should support SWIFT_RETURNS_RETAINED
34053414
// and SWIFT_RETURNS_UNRETAINED for overloaded C++ operators
@@ -3409,15 +3418,17 @@ namespace {
34093418
!methodDecl->isOverloadedOperator() &&
34103419
methodDecl->isUserProvided()) {
34113420
// normal c++ member method
3412-
unannotatedCxxAPIWarningNeeded = true;
3421+
unannotatedAPIWarningNeeded = true;
34133422
}
34143423
} else {
3415-
// global or top-level function
3416-
unannotatedCxxAPIWarningNeeded = true;
3424+
// global or top-level C/C++ function
3425+
unannotatedAPIWarningNeeded = true;
34173426
}
3427+
} else if (isa<clang::ObjCMethodDecl>(decl)) {
3428+
unannotatedAPIWarningNeeded = true;
34183429
}
34193430

3420-
if (unannotatedCxxAPIWarningNeeded) {
3431+
if (unannotatedAPIWarningNeeded) {
34213432
HeaderLoc loc(decl->getLocation());
34223433
Impl.diagnose(loc, diag::no_returns_retained_returns_unretained,
34233434
decl);
@@ -4560,6 +4571,8 @@ namespace {
45604571
if (!dc)
45614572
return nullptr;
45624573

4574+
checkBridgingAttrs(decl);
4575+
45634576
// While importing the DeclContext, we might have imported the decl
45644577
// itself.
45654578
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)