Skip to content

Commit ca1094c

Browse files
committed
[cxx-interop] Warning unannotated C++ APIs returning SWIFT_SHARED_REFERENCE types
1 parent e362264 commit ca1094c

File tree

4 files changed

+61
-9
lines changed

4 files changed

+61
-9
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,16 @@ ERROR(failed_base_method_call_synthesis,none,
258258
"failed to synthesize call to the base method %0 of type %0",
259259
(ValueDecl *, ValueDecl *))
260260

261-
ERROR(both_returns_retained_returns_unretained,none,
262-
"%0 cannot be annotated with both swift_attr('returns_retained') and swift_attr('returns_unretained') attributes", (const clang::NamedDecl*))
261+
ERROR(both_returns_retained_returns_unretained, none,
262+
"%0 cannot be annotated with both swift_attr('returns_retained') and "
263+
"swift_attr('returns_unretained') attributes",
264+
(const clang::NamedDecl *))
265+
266+
WARNING(no_returns_retained_returns_unretained, none,
267+
"%0 is returning a 'SWIFT_SHARED_REFERENCE' type but is not annotated "
268+
"with either swift_attr('returns_retained') or "
269+
"swift_attr('returns_unretained') attributes",
270+
(const clang::NamedDecl *))
263271

264272
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
265273
NOTE(record_field_not_imported, none, "field %0 unavailable (cannot import)", (const clang::NamedDecl*))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2685,7 +2685,7 @@ namespace {
26852685
Impl.diagnoseTopLevelValue(
26862686
DeclName(Impl.SwiftContext.getIdentifier(releaseOperation.name)));
26872687
}
2688-
}else if (releaseOperation.kind ==
2688+
} else if (releaseOperation.kind ==
26892689
CustomRefCountingOperationResult::tooManyFound) {
26902690
HeaderLoc loc(decl->getLocation());
26912691
Impl.diagnose(loc,
@@ -3357,9 +3357,9 @@ namespace {
33573357
// swift_attr("returns_unretained") then emit an error in the swift
33583358
// compiler. Note: this error is not emitted in the clang compiler because
33593359
// these attributes are used only for swift interop.
3360+
bool returnsRetainedAttrIsPresent = false;
3361+
bool returnsUnretainedAttrIsPresent = false;
33603362
if (decl->hasAttrs()) {
3361-
bool returnsRetainedAttrIsPresent = false;
3362-
bool returnsUnretainedAttrIsPresent = false;
33633363
for (const auto *attr : decl->getAttrs()) {
33643364
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
33653365
if (swiftAttr->getAttribute() == "returns_unretained") {
@@ -3369,18 +3369,48 @@ namespace {
33693369
}
33703370
}
33713371
}
3372+
}
3373+
3374+
HeaderLoc loc(decl->getLocation());
3375+
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
3376+
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
3377+
decl);
3378+
}
33723379

3373-
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
3374-
HeaderLoc loc(decl->getLocation());
3375-
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
3376-
decl);
3380+
if ((!returnsRetainedAttrIsPresent) && (!returnsUnretainedAttrIsPresent)) {
3381+
if (isForeignReferenceType(decl->getReturnType())) {
3382+
Impl.diagnose(loc, diag::no_returns_retained_returns_unretained,
3383+
decl);
33773384
}
33783385
}
33793386

33803387
return importFunctionDecl(decl, importedName, correctSwiftName,
33813388
std::nullopt);
33823389
}
33833390

3391+
static bool isForeignReferenceType(const clang::QualType type) {
3392+
if (!type->isPointerType())
3393+
return false;
3394+
3395+
auto pointeeType =
3396+
dyn_cast<clang::RecordType>(type->getPointeeType().getCanonicalType());
3397+
if (pointeeType == nullptr)
3398+
return false;
3399+
3400+
return hasImportAsRefAttr(pointeeType->getDecl());
3401+
}
3402+
3403+
static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
3404+
return decl->hasAttrs() && llvm::any_of(decl->getAttrs(), [](auto *attr) {
3405+
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
3406+
return swiftAttr->getAttribute() == "import_reference" ||
3407+
// TODO: Remove this once libSwift hosttools no longer
3408+
// requires it.
3409+
swiftAttr->getAttribute() == "import_as_ref";
3410+
return false;
3411+
});
3412+
}
3413+
33843414
/// Handles special functions such as subscripts and dereference operators.
33853415
bool
33863416
processSpecialImportedFunc(FuncDecl *func, ImportedName importedName,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ struct
158158
__attribute__((swift_attr("returns_unretained")));
159159
};
160160

161+
// C++ APIs returning FRTs but not having annotations
162+
struct
163+
StructWithoutReturnsAnnotations {
164+
static FRTStruct *_Nonnull StaticMethodReturningFRT();
165+
};
166+
167+
FRTStruct *_Nonnull global_function_returning_FRT_WithoutReturnsAnnotations();
168+
161169
struct NonFRTStruct {};
162170

163171
// Global/free C++ functions returning non-FRT

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ let frtLocalVar1 = global_function_returning_FRT_with_both_attrs_returns_retaine
88

99
let frtLocalVar2 = StructWithStaticMethodsReturningFRTWithBothAttributesReturnsRetainedAndReturnsUnretained.StaticMethodReturningFRT()
1010
// CHECK: error: 'StaticMethodReturningFRT' cannot be annotated with both swift_attr('returns_retained') and swift_attr('returns_unretained') attributes
11+
12+
let frtLocalVar3 = global_function_returning_FRT_WithoutReturnsAnnotations()
13+
// CHECK: warning: 'global_function_returning_FRT_WithoutReturnsAnnotations' is returning a 'SWIFT_SHARED_REFERENCE' type but is not annotated with either swift_attr('returns_retained') or swift_attr('returns_unretained') attributes
14+
15+
let frtLocalVar4 = StructWithoutReturnsAnnotations.StaticMethodReturningFRT()
16+
// CHECK: warning: 'StaticMethodReturningFRT' is returning a 'SWIFT_SHARED_REFERENCE' type but is not annotated with either swift_attr('returns_retained') or swift_attr('returns_unretained') attributes

0 commit comments

Comments
 (0)