Skip to content

Commit c9cd3c5

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 7eeebea commit c9cd3c5

File tree

2 files changed

+55
-12
lines changed

2 files changed

+55
-12
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,12 +2236,14 @@ namespace {
22362236
MoveOnlyAttr(/*Implicit=*/true));
22372237
}
22382238

2239+
bool isNonEscapable = false;
22392240
if (evaluateOrDefault(
22402241
Impl.SwiftContext.evaluator,
22412242
ClangTypeEscapability({decl->getTypeForDecl(), Impl}),
22422243
CxxEscapability::Unknown) == CxxEscapability::NonEscapable) {
22432244
result->getAttrs().add(new (Impl.SwiftContext)
22442245
NonEscapableAttr(/*Implicit=*/true));
2246+
isNonEscapable = true;
22452247
}
22462248

22472249
// FIXME: Figure out what to do with superclasses in C++. One possible
@@ -2386,6 +2388,19 @@ namespace {
23862388
synthesizer.createValueConstructor(result, member,
23872389
/*want param names*/ true,
23882390
/*wantBody=*/true);
2391+
2392+
if (Impl.SwiftContext.LangOpts.hasFeature(
2393+
Feature::LifetimeDependence) &&
2394+
isNonEscapable) {
2395+
valueCtor->getAttrs().add(
2396+
new (Impl.SwiftContext)
2397+
UnsafeNonEscapableResultAttr(/*Implicit=*/true));
2398+
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SafeInterop) &&
2399+
Impl.SwiftContext.LangOpts.hasFeature(
2400+
Feature::AllowUnsafeAttribute))
2401+
valueCtor->getAttrs().add(new (Impl.SwiftContext)
2402+
UnsafeAttr(/*Implicit=*/true));
2403+
}
23892404
ctors.push_back(valueCtor);
23902405
}
23912406
// TODO: we have a problem lazily looking up members of an unnamed
@@ -2410,7 +2425,13 @@ namespace {
24102425
(!cxxRecordDecl->hasDefaultConstructor() ||
24112426
cxxRecordDecl->ctors().empty());
24122427
}
2413-
if (hasZeroInitializableStorage && needsEmptyInitializer) {
2428+
2429+
// TODO: builtin "zeroInitializer" does not work with non-escapable
2430+
// types yet. Don't generate an initializer.
2431+
if (hasZeroInitializableStorage && needsEmptyInitializer &&
2432+
(!Impl.SwiftContext.LangOpts.hasFeature(
2433+
Feature::LifetimeDependence) ||
2434+
!isNonEscapable)) {
24142435
// Add default constructor for the struct if compiling in C mode.
24152436
// If we're compiling for C++:
24162437
// 1. If a default constructor is declared, don't synthesize one.
@@ -2423,7 +2444,6 @@ namespace {
24232444
// constructor available in Swift.
24242445
ConstructorDecl *defaultCtor =
24252446
synthesizer.createDefaultConstructor(result);
2426-
ctors.push_back(defaultCtor);
24272447
if (cxxRecordDecl) {
24282448
auto attr = AvailableAttr::createUniversallyDeprecated(
24292449
defaultCtor->getASTContext(),
@@ -2433,6 +2453,7 @@ namespace {
24332453
"");
24342454
defaultCtor->getAttrs().add(attr);
24352455
}
2456+
ctors.push_back(defaultCtor);
24362457
}
24372458

24382459
bool forceMemberwiseInitializer = false;
@@ -2462,6 +2483,19 @@ namespace {
24622483
if (!hasUnreferenceableStorage)
24632484
valueCtor->setIsMemberwiseInitializer();
24642485

2486+
if (Impl.SwiftContext.LangOpts.hasFeature(
2487+
Feature::LifetimeDependence) &&
2488+
isNonEscapable) {
2489+
valueCtor->getAttrs().add(
2490+
new (Impl.SwiftContext)
2491+
UnsafeNonEscapableResultAttr(/*Implicit=*/true));
2492+
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SafeInterop) &&
2493+
Impl.SwiftContext.LangOpts.hasFeature(
2494+
Feature::AllowUnsafeAttribute))
2495+
valueCtor->getAttrs().add(new (Impl.SwiftContext)
2496+
UnsafeAttr(/*Implicit=*/true));
2497+
}
2498+
24652499
ctors.push_back(valueCtor);
24662500
}
24672501

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)