Merge pull request #78807 from swiftlang/gaborh/generated-ctors

[cxx-interop] Fix spurious lifetime dependence errors
This commit is contained in:
Gábor Horváth
2025-01-29 17:59:03 +00:00
committed by GitHub
2 changed files with 47 additions and 12 deletions

View File

@@ -2033,6 +2033,18 @@ namespace {
return semanticsKind == CxxRecordSemanticsKind::MoveOnly;
}
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::LifetimeDependence)) {
fd->getAttrs().add(new (Impl.SwiftContext)
UnsafeNonEscapableResultAttr(/*Implicit=*/true));
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SafeInterop) &&
Impl.SwiftContext.LangOpts.hasFeature(
Feature::AllowUnsafeAttribute))
fd->getAttrs().add(new (Impl.SwiftContext)
UnsafeAttr(/*Implicit=*/true));
}
}
Decl *VisitRecordDecl(const clang::RecordDecl *decl) {
// Track whether this record contains fields we can't reference in Swift
// as stored properties.
@@ -2228,12 +2240,14 @@ namespace {
MoveOnlyAttr(/*Implicit=*/true));
}
bool isNonEscapable = false;
if (evaluateOrDefault(
Impl.SwiftContext.evaluator,
ClangTypeEscapability({decl->getTypeForDecl(), Impl}),
CxxEscapability::Unknown) == CxxEscapability::NonEscapable) {
result->getAttrs().add(new (Impl.SwiftContext)
NonEscapableAttr(/*Implicit=*/true));
isNonEscapable = true;
}
// FIXME: Figure out what to do with superclasses in C++. One possible
@@ -2378,6 +2392,9 @@ namespace {
synthesizer.createValueConstructor(result, member,
/*want param names*/ true,
/*wantBody=*/true);
if (isNonEscapable)
markReturnsUnsafeNonescapable(valueCtor);
ctors.push_back(valueCtor);
}
// TODO: we have a problem lazily looking up members of an unnamed
@@ -2402,7 +2419,13 @@ namespace {
(!cxxRecordDecl->hasDefaultConstructor() ||
cxxRecordDecl->ctors().empty());
}
if (hasZeroInitializableStorage && needsEmptyInitializer) {
// TODO: builtin "zeroInitializer" does not work with non-escapable
// types yet. Don't generate an initializer.
if (hasZeroInitializableStorage && needsEmptyInitializer &&
(!Impl.SwiftContext.LangOpts.hasFeature(
Feature::LifetimeDependence) ||
!isNonEscapable)) {
// Add default constructor for the struct if compiling in C mode.
// If we're compiling for C++:
// 1. If a default constructor is declared, don't synthesize one.
@@ -2415,7 +2438,6 @@ namespace {
// constructor available in Swift.
ConstructorDecl *defaultCtor =
synthesizer.createDefaultConstructor(result);
ctors.push_back(defaultCtor);
if (cxxRecordDecl) {
auto attr = AvailableAttr::createUniversallyDeprecated(
defaultCtor->getASTContext(),
@@ -2425,6 +2447,7 @@ namespace {
"");
defaultCtor->getAttrs().add(attr);
}
ctors.push_back(defaultCtor);
}
bool forceMemberwiseInitializer = false;
@@ -2454,6 +2477,9 @@ namespace {
if (!hasUnreferenceableStorage)
valueCtor->setIsMemberwiseInitializer();
if (isNonEscapable)
markReturnsUnsafeNonescapable(valueCtor);
ctors.push_back(valueCtor);
}

View File

@@ -23,7 +23,6 @@ private:
};
struct SWIFT_NONESCAPABLE OtherView {
OtherView() : member(nullptr) {}
OtherView(View v [[clang::lifetimebound]]) : member(v.member) {}
OtherView(const OtherView&) = default;
private:
@@ -105,6 +104,10 @@ CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
return CaptureView(View{&owner.data});
}
struct SWIFT_NONESCAPABLE AggregateView {
const int *member;
};
// CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// 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]]) {
// CHECK: sil [clang CaptureView.captureView] {{.*}} : $@convention(cxx_method) (View, @lifetime(copy 0) @inout CaptureView) -> ()
// CHECK: sil [clang CaptureView.handOut] {{.*}} : $@convention(cxx_method) (@lifetime(copy 1) @inout View, @in_guaranteed CaptureView) -> ()
// CHECK-NO-LIFETIMES: nonescapable.h:36:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:40:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:46:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:53:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:23:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:27:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:35:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:39:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:45:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:52:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:22:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:26:10: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:4:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:5:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:13:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:14:5: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:68:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:91:13: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:12:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:67:6: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:90:13: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:94:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES: nonescapable.h:94:27: error: returning ~Escapable type requires '-enable-experimental-feature LifetimeDependence'
// CHECK-NO-LIFETIMES-NOT: error
//--- test.swift
@@ -155,3 +160,7 @@ public func test() {
cv.captureView(v1)
cv.handOut(&v1)
}
public func test2(_ x: AggregateView) {
let _ = AggregateView(member: x.member)
}