Skip to content

Commit b6fce85

Browse files
author
Gabor Horvath
committed
[cxx-interop] Fix spurious lifetime dependence errors
ClangImporter will generate value and default initializers for certain structs imported from C++. These generated initializers have no associated lifetime dependence information so they will trigger spurious errors for non-escapable types. This patch makes sure these are marked as unsafe so the type checker will not generate errors for them. Moreover, the generated default initializer would trigger a crash for non-escapable types as the builtin to zero initialize an object does not support non-escapable types yet. rdar://143040862
1 parent 4d24b7d commit b6fce85

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,18 @@ namespace {
20412041
return semanticsKind == CxxRecordSemanticsKind::MoveOnly;
20422042
}
20432043

2044+
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
2045+
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::LifetimeDependence)) {
2046+
fd->getAttrs().add(new (Impl.SwiftContext)
2047+
UnsafeNonEscapableResultAttr(/*Implicit=*/true));
2048+
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SafeInterop) &&
2049+
Impl.SwiftContext.LangOpts.hasFeature(
2050+
Feature::AllowUnsafeAttribute))
2051+
fd->getAttrs().add(new (Impl.SwiftContext)
2052+
UnsafeAttr(/*Implicit=*/true));
2053+
}
2054+
}
2055+
20442056
Decl *VisitRecordDecl(const clang::RecordDecl *decl) {
20452057
// Track whether this record contains fields we can't reference in Swift
20462058
// as stored properties.
@@ -2236,12 +2248,14 @@ namespace {
22362248
MoveOnlyAttr(/*Implicit=*/true));
22372249
}
22382250

2251+
bool isNonEscapable = false;
22392252
if (evaluateOrDefault(
22402253
Impl.SwiftContext.evaluator,
22412254
ClangTypeEscapability({decl->getTypeForDecl(), Impl}),
22422255
CxxEscapability::Unknown) == CxxEscapability::NonEscapable) {
22432256
result->getAttrs().add(new (Impl.SwiftContext)
22442257
NonEscapableAttr(/*Implicit=*/true));
2258+
isNonEscapable = true;
22452259
}
22462260

22472261
// FIXME: Figure out what to do with superclasses in C++. One possible
@@ -2386,6 +2400,9 @@ namespace {
23862400
synthesizer.createValueConstructor(result, member,
23872401
/*want param names*/ true,
23882402
/*wantBody=*/true);
2403+
2404+
if (isNonEscapable)
2405+
markReturnsUnsafeNonescapable(valueCtor);
23892406
ctors.push_back(valueCtor);
23902407
}
23912408
// TODO: we have a problem lazily looking up members of an unnamed
@@ -2410,7 +2427,13 @@ namespace {
24102427
(!cxxRecordDecl->hasDefaultConstructor() ||
24112428
cxxRecordDecl->ctors().empty());
24122429
}
2413-
if (hasZeroInitializableStorage && needsEmptyInitializer) {
2430+
2431+
// TODO: builtin "zeroInitializer" does not work with non-escapable
2432+
// types yet. Don't generate an initializer.
2433+
if (hasZeroInitializableStorage && needsEmptyInitializer &&
2434+
(!Impl.SwiftContext.LangOpts.hasFeature(
2435+
Feature::LifetimeDependence) ||
2436+
!isNonEscapable)) {
24142437
// Add default constructor for the struct if compiling in C mode.
24152438
// If we're compiling for C++:
24162439
// 1. If a default constructor is declared, don't synthesize one.
@@ -2423,7 +2446,6 @@ namespace {
24232446
// constructor available in Swift.
24242447
ConstructorDecl *defaultCtor =
24252448
synthesizer.createDefaultConstructor(result);
2426-
ctors.push_back(defaultCtor);
24272449
if (cxxRecordDecl) {
24282450
auto attr = AvailableAttr::createUniversallyDeprecated(
24292451
defaultCtor->getASTContext(),
@@ -2433,6 +2455,7 @@ namespace {
24332455
"");
24342456
defaultCtor->getAttrs().add(attr);
24352457
}
2458+
ctors.push_back(defaultCtor);
24362459
}
24372460

24382461
bool forceMemberwiseInitializer = false;
@@ -2462,6 +2485,9 @@ namespace {
24622485
if (!hasUnreferenceableStorage)
24632486
valueCtor->setIsMemberwiseInitializer();
24642487

2488+
if (isNonEscapable)
2489+
markReturnsUnsafeNonescapable(valueCtor);
2490+
24652491
ctors.push_back(valueCtor);
24662492
}
24672493

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ private:
2323
};
2424

2525
struct SWIFT_NONESCAPABLE OtherView {
26-
OtherView() : member(nullptr) {}
2726
OtherView(View v [[clang::lifetimebound]]) : member(v.member) {}
2827
OtherView(const OtherView&) = default;
2928
private:
@@ -105,6 +104,10 @@ CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
105104
return CaptureView(View{&owner.data});
106105
}
107106

107+
struct SWIFT_NONESCAPABLE AggregateView {
108+
const int *member;
109+
};
110+
108111
// CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner
109112
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
110113
// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
@@ -120,18 +123,20 @@ CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
120123
// CHECK: sil [clang CaptureView.captureView] {{.*}} : $@convention(cxx_method) (View, @lifetime(copy 0) @inout CaptureView) -> ()
121124
// CHECK: sil [clang CaptureView.handOut] {{.*}} : $@convention(cxx_method) (@lifetime(copy 1) @inout View, @in_guaranteed CaptureView) -> ()
122125

123-
// CHECK-NO-LIFETIMES: nonescapable.h:36:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
124-
// CHECK-NO-LIFETIMES: nonescapable.h:40:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
125-
// CHECK-NO-LIFETIMES: nonescapable.h:46:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
126-
// CHECK-NO-LIFETIMES: nonescapable.h:53:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
127-
// CHECK-NO-LIFETIMES: nonescapable.h:23:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
128-
// CHECK-NO-LIFETIMES: nonescapable.h:27:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
126+
// CHECK-NO-LIFETIMES: nonescapable.h:35:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
127+
// CHECK-NO-LIFETIMES: nonescapable.h:39:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
128+
// CHECK-NO-LIFETIMES: nonescapable.h:45:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
129+
// CHECK-NO-LIFETIMES: nonescapable.h:52:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
130+
// CHECK-NO-LIFETIMES: nonescapable.h:22:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
131+
// CHECK-NO-LIFETIMES: nonescapable.h:26:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
129132
// CHECK-NO-LIFETIMES: nonescapable.h:4:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
130133
// CHECK-NO-LIFETIMES: nonescapable.h:5:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
131134
// CHECK-NO-LIFETIMES: nonescapable.h:13:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
132-
// CHECK-NO-LIFETIMES: nonescapable.h:14:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
133-
// CHECK-NO-LIFETIMES: nonescapable.h:68:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
134-
// CHECK-NO-LIFETIMES: nonescapable.h:91:13: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
135+
// CHECK-NO-LIFETIMES: nonescapable.h:12:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
136+
// CHECK-NO-LIFETIMES: nonescapable.h:67:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
137+
// CHECK-NO-LIFETIMES: nonescapable.h:90:13: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
138+
// CHECK-NO-LIFETIMES: nonescapable.h:94:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
139+
// CHECK-NO-LIFETIMES: nonescapable.h:94:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
135140
// CHECK-NO-LIFETIMES-NOT: error
136141

137142
//--- test.swift
@@ -155,3 +160,7 @@ public func test() {
155160
cv.captureView(v1)
156161
cv.handOut(&v1)
157162
}
163+
164+
public func test2(_ x: AggregateView) {
165+
let _ = AggregateView(member: x.member)
166+
}

0 commit comments

Comments
 (0)