Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,36 +150,42 @@ UNINTERESTING_FEATURE(CheckImplementationOnly)
UNINTERESTING_FEATURE(CheckImplementationOnlyStrict)
UNINTERESTING_FEATURE(EnforceSPIOperatorGroup)

static bool findUnderscoredLifetimeAttr(Decl *decl) {
auto hasUnderscoredLifetimeAttr = [](Decl *decl) {
static bool findLifetimeAttr(Decl *decl, bool findUnderscored) {
auto hasLifetimeAttr = [&](Decl *decl) {
if (!decl->getAttrs().hasAttribute<LifetimeAttr>()) {
return false;
}
// Since we ban mixing @lifetime and @_lifetime on the same decl, checking
// any one LifetimeAttr on the decl is sufficient.
// FIXME: Implement the ban.
return decl->getAttrs().getAttribute<LifetimeAttr>()->isUnderscored();
if (findUnderscored) {
return decl->getAttrs().getAttribute<LifetimeAttr>()->isUnderscored();
}
return !decl->getAttrs().getAttribute<LifetimeAttr>()->isUnderscored();
};

switch (decl->getKind()) {
case DeclKind::Var: {
auto *var = cast<VarDecl>(decl);
return llvm::any_of(var->getAllAccessors(), hasUnderscoredLifetimeAttr);
return llvm::any_of(var->getAllAccessors(), hasLifetimeAttr);
}
default:
return hasUnderscoredLifetimeAttr(decl);
return hasLifetimeAttr(decl);
}
}

static bool usesFeatureLifetimeDependence(Decl *decl) {
if (decl->getAttrs().hasAttribute<LifetimeAttr>()) {
if (findUnderscoredLifetimeAttr(decl)) {
// Experimental feature Lifetimes will guard the decl.
return false;
}
if (findLifetimeAttr(decl, /*findUnderscored*/ false)) {
return true;
}

// Guard inferred lifetime dependencies with LifetimeDependence if it was
// enabled.
if (!decl->getASTContext().LangOpts.hasFeature(Feature::LifetimeDependence)) {
return false;
}

// Check for inferred lifetime dependencies
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
return afd->getInterfaceType()
->getAs<AnyFunctionType>()
Expand All @@ -192,7 +198,25 @@ static bool usesFeatureLifetimeDependence(Decl *decl) {
}

static bool usesFeatureLifetimes(Decl *decl) {
return findUnderscoredLifetimeAttr(decl);
if (findLifetimeAttr(decl, /*findUnderscored*/ true)) {
return true;
}

// Guard inferred lifetime dependencies with Lifetimes if it was enabled.
if (!decl->getASTContext().LangOpts.hasFeature(Feature::Lifetimes)) {
return false;
}

// Check for inferred lifetime dependencies
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
return afd->getInterfaceType()
->getAs<AnyFunctionType>()
->hasLifetimeDependencies();
}
if (auto *varDecl = dyn_cast<VarDecl>(decl)) {
return !varDecl->getTypeInContext()->isEscapable();
}
return false;
}

static bool usesFeatureInoutLifetimeDependence(Decl *decl) {
Expand Down
12 changes: 12 additions & 0 deletions test/ModuleInterface/Inputs/lifetime_underscored_dependence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,15 @@ extension Container {
}
}
}

public struct RigidArray : ~Copyable {
@usableFromInline let _ptr: UnsafeRawBufferPointer

public var span: RawSpan {
@_lifetime(borrow self)
get {
return RawSpan(_unsafeBytes: _ptr)
}
}
}

21 changes: 17 additions & 4 deletions test/ModuleInterface/lifetime_underscored_dependence_test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

// RUN: %target-swift-frontend -swift-version 5 -enable-library-evolution -emit-module \
// RUN: -enable-experimental-feature Lifetimes \
// RUN: -enable-experimental-feature Lifetimes \
// RUN: -o %t/lifetime_underscored_dependence.swiftmodule \
// RUN: -emit-module-interface-path %t/lifetime_underscored_dependence.swiftinterface \
// RUN: %S/Inputs/lifetime_underscored_dependence.swift
Expand Down Expand Up @@ -105,8 +104,22 @@ import lifetime_underscored_dependence
// CHECK:}
// CHECK:#endif

// Check that an implicitly dependent variable accessor is guarded by LifetimeDependence.
//
// CHECK: extension lifetime_underscored_dependence.Container {
// CHECK-NEXT: #if compiler(>=5.3) && $LifetimeDependence
// CHECK-NEXT: #if compiler(>=5.3) && $Lifetimes
// CHECK-NEXT: public var storage: lifetime_underscored_dependence.BufferView {

// CHECK: public struct RigidArray : ~Swift.Copyable {
// CHECK: @usableFromInline
// CHECK: internal let _ptr: Swift.UnsafeRawBufferPointer
// CHECK: #if compiler(>=5.3) && $Lifetimes
// CHECK: public var span: Swift.RawSpan {
// CHECK: @_lifetime(borrow self)
// CHECK: get
// CHECK: }
// CHECK: #else
// CHECK: public var span: Swift.RawSpan {
// CHECK: @lifetime(borrow self)
// CHECK: get
// CHECK: }
// CHECK: #endif
// CHECK: }