Skip to content

Commit 2bc6ed0

Browse files
committed
[cxx-interop] Warning unannotated C++ APIs returning SWIFT_SHARED_REFERENCE types
1 parent d1b380f commit 2bc6ed0

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
@@ -2684,7 +2684,7 @@ namespace {
26842684
Impl.diagnoseTopLevelValue(
26852685
DeclName(Impl.SwiftContext.getIdentifier(releaseOperation.name)));
26862686
}
2687-
}else if (releaseOperation.kind ==
2687+
} else if (releaseOperation.kind ==
26882688
CustomRefCountingOperationResult::tooManyFound) {
26892689
HeaderLoc loc(decl->getLocation());
26902690
Impl.diagnose(loc,
@@ -3356,9 +3356,9 @@ namespace {
33563356
// swift_attr("returns_unretained") then emit an error in the swift
33573357
// compiler. Note: this error is not emitted in the clang compiler because
33583358
// these attributes are used only for swift interop.
3359+
bool returnsRetainedAttrIsPresent = false;
3360+
bool returnsUnretainedAttrIsPresent = false;
33593361
if (decl->hasAttrs()) {
3360-
bool returnsRetainedAttrIsPresent = false;
3361-
bool returnsUnretainedAttrIsPresent = false;
33623362
for (const auto *attr : decl->getAttrs()) {
33633363
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
33643364
if (swiftAttr->getAttribute() == "returns_unretained") {
@@ -3368,18 +3368,48 @@ namespace {
33683368
}
33693369
}
33703370
}
3371+
}
3372+
3373+
HeaderLoc loc(decl->getLocation());
3374+
if (returnsRetainedAttrIsPresent && returnsUnretainedAttrIsPresent) {
3375+
Impl.diagnose(loc, diag::both_returns_retained_returns_unretained,
3376+
decl);
3377+
}
33713378

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

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

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