Skip to content

Commit 8c4be8a

Browse files
Xazax-hunGabor Horvath
authored andcommitted
[6.2][cxx-interop] Diagnose Escapable C++ types with non-escapable fields
Explanation: In Swift, Escapable types cannot have non-escapable stored properties. Unfortunately, these checks could be circumvented via C++ interop, constructing invalid Swift code. This patch errors out on importing C++ code of this shape. Issue: rdar://148899224 Risk: Low, the fix is fairly targeted to the affected scenario. Testing: Added tests to test suite Original PR: #80671 Reviewer: John Hui
1 parent 608c035 commit 8c4be8a

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,5 +373,9 @@ NOTE(ptr_to_nonescapable,none,
373373
"pointer to non-escapable type %0 cannot be imported",
374374
(const clang::Type*))
375375

376+
NOTE(nonescapable_field_of_escapable, none,
377+
"escapable record %0 cannot have non-escapable field '%1'",
378+
(const clang::NamedDecl *, StringRef))
379+
376380
#define UNDEFINE_DIAGNOSTIC_MACROS
377381
#include "DefineDiagnosticMacros.h"

lib/ClangImporter/ImportDecl.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2359,7 +2359,23 @@ namespace {
23592359
continue;
23602360
}
23612361

2362-
members.push_back(cast<VarDecl>(member));
2362+
auto *vd = cast<VarDecl>(member);
2363+
if (!isNonEscapable) {
2364+
if (const auto *fd = dyn_cast<clang::FieldDecl>(nd))
2365+
if (evaluateOrDefault(
2366+
Impl.SwiftContext.evaluator,
2367+
ClangTypeEscapability({fd->getType().getTypePtr(), &Impl}),
2368+
CxxEscapability::Unknown) ==
2369+
CxxEscapability::NonEscapable) {
2370+
Impl.addImportDiagnostic(
2371+
decl,
2372+
Diagnostic(diag::nonescapable_field_of_escapable, decl,
2373+
nd->getName()),
2374+
decl->getLocation());
2375+
return nullptr;
2376+
}
2377+
}
2378+
members.push_back(vd);
23632379
}
23642380

23652381
bool hasReferenceableFields = !members.empty();

test/Interop/Cxx/class/nonescapable-errors.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,21 @@ const View* usedToCrash(const View* p) {
9595
return p;
9696
}
9797

98+
struct SWIFT_ESCAPABLE Invalid {
99+
View v;
100+
};
101+
98102
//--- test.swift
99103
import Test
100104
import CxxStdlib
101105

106+
// CHECK: error: cannot find type 'Invalid' in scope
107+
// CHECK: note: escapable record 'Invalid' cannot have non-escapable field 'v'
108+
public func importInvalid(_ x: Invalid) {
109+
}
110+
102111
// CHECK: error: a function with a ~Escapable result needs a parameter to depend on
103-
// CHECK-NO-LIFETIMES: test.swift:6:32: error: a function with a ~Escapable result requires '-enable-experimental-feature LifetimeDependence'
112+
// CHECK-NO-LIFETIMES: test.swift:11:32: error: a function with a ~Escapable result requires '-enable-experimental-feature LifetimeDependence'
104113
public func noAnnotations() -> View {
105114
// CHECK: nonescapable.h:16:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies
106115
// CHECK-NO-LIFETIMES: nonescapable.h:16:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies

0 commit comments

Comments
 (0)