Skip to content

Commit d2e0f66

Browse files
authored
Merge pull request #78458 from fahadnayyar/returns-retained-objc-diagnostics
[cxx-interop] Diagnose ObjC APIs returning SWIFT_SHARED_REFERENCE types
2 parents df8a4c8 + 69332f7 commit d2e0f66

File tree

3 files changed

+48
-10
lines changed

3 files changed

+48
-10
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+
? cast<clang::FunctionDecl>(decl)->getReturnType()
3402+
: 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: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,42 @@ 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

1517
@interface Bridge : NSObject
1618

17-
+ (struct CxxRefType *)objCMethodReturningFRTUnannotated;
19+
+ (struct CxxRefType *)objCMethodReturningFRTUnannotated; // expected-warning {{'objCMethodReturningFRTUnannotated' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
1820
+ (struct CxxRefType *)objCMethodReturningFRTUnowned
1921
__attribute__((swift_attr("returns_unretained")));
2022
+ (struct CxxRefType *)objCMethodReturningFRTOwned
2123
__attribute__((swift_attr("returns_retained")));
24+
+ (struct CxxRefType *)objCMethodReturningFRTBothAnnotations // expected-error {{'objCMethodReturningFRTBothAnnotations' cannot be annotated with both SWIFT_RETURNS_RETAINED and SWIFT_RETURNS_UNRETAINED}}
25+
__attribute__((swift_attr("returns_unretained")))
26+
__attribute__((swift_attr("returns_retained")));
27+
+ (struct CxxValType *)objCMethodReturningNonCxxFrtAnannotated // expected-error {{'objCMethodReturningNonCxxFrtAnannotated' cannot be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED because it is not returning a SWIFT_SHARED_REFERENCE type}}
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: rm -rf %t
2+
// RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs %s -cxx-interoperability-mode=upcoming-swift -verify-additional-file %S/Inputs/cxx-frt.h -Xcc -Wno-return-type
3+
4+
import CxxForeignRef
5+
6+
// REQUIRES: objc_interop
7+
func testObjCMethods() {
8+
_ = Bridge.objCMethodReturningFRTBothAnnotations()
9+
_ = Bridge.objCMethodReturningNonCxxFrtAnannotated()
10+
_ = Bridge.objCMethodReturningFRTUnannotated()
11+
}

0 commit comments

Comments
 (0)