Skip to content

Commit 58b714b

Browse files
committed
Introduce a new suppressible experimental feature to guard @_lifetime
1 parent a9b8317 commit 58b714b

File tree

9 files changed

+73
-17
lines changed

9 files changed

+73
-17
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ struct PrintOptions {
355355
/// as public
356356
bool SuppressIsolatedDeinit = false;
357357

358+
/// Suppress @_lifetime attribute and emit @lifetime instead.
359+
bool SuppressLifetimes = false;
360+
358361
/// Whether to print the \c{/*not inherited*/} comment on factory initializers.
359362
bool PrintFactoryInitializerComment = true;
360363

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,9 @@ EXPERIMENTAL_FEATURE(CopyBlockOptimization, true)
526526
/// in a file scope.
527527
EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false)
528528

529+
/// Enable @_lifetime attribute
530+
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)
531+
529532
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
530533
#undef EXPERIMENTAL_FEATURE
531534
#undef UPCOMING_FEATURE

include/swift/Parse/Parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,8 @@ class Parser {
11581158

11591159
bool isParameterSpecifier() {
11601160
if (Tok.is(tok::kw_inout)) return true;
1161-
if (Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
1161+
if ((Context.LangOpts.hasFeature(Feature::LifetimeDependence) ||
1162+
Context.LangOpts.hasFeature(Feature::Lifetimes)) &&
11621163
isSILLifetimeDependenceToken())
11631164
return true;
11641165
if (!canHaveParameterSpecifierContextualKeyword()) return false;

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,6 +3258,13 @@ suppressingFeatureIsolatedDeinit(PrintOptions &options,
32583258
action();
32593259
}
32603260

3261+
static void
3262+
suppressingFeatureLifetimes(PrintOptions &options,
3263+
llvm::function_ref<void()> action) {
3264+
llvm::SaveAndRestore<bool> scope(options.SuppressLifetimes, true);
3265+
action();
3266+
}
3267+
32613268
namespace {
32623269
struct ExcludeAttrRAII {
32633270
std::vector<AnyAttrKind> &ExcludeAttrList;

lib/AST/Attr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
16831683

16841684
case DeclAttrKind::Lifetime: {
16851685
auto *attr = cast<LifetimeAttr>(this);
1686-
Printer << attr->getString();
1686+
if (!attr->isUnderscored() || Options.SuppressLifetimes) {
1687+
Printer << "@lifetime" << attr->getLifetimeEntry()->getString();
1688+
} else {
1689+
Printer << "@_lifetime" << attr->getLifetimeEntry()->getString();
1690+
}
16871691
break;
16881692
}
16891693

lib/AST/FeatureSet.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,36 @@ static bool usesFeatureSendingArgsAndResults(Decl *decl) {
257257
return false;
258258
}
259259

260+
static bool findUnderscoredLifetimeAttr(Decl *decl) {
261+
auto hasUnderscoredLifetimeAttr = [](Decl *decl) {
262+
if (!decl->getAttrs().hasAttribute<LifetimeAttr>()) {
263+
return false;
264+
}
265+
// Since we ban mixing @lifetime and @_lifetime on the same decl, checking
266+
// any one LifetimeAttr on the decl is sufficient.
267+
// FIXME: Implement the ban.
268+
return decl->getAttrs().getAttribute<LifetimeAttr>()->isUnderscored();
269+
};
270+
271+
switch (decl->getKind()) {
272+
case DeclKind::Var: {
273+
auto *var = cast<VarDecl>(decl);
274+
return llvm::any_of(var->getAllAccessors(), hasUnderscoredLifetimeAttr);
275+
}
276+
default:
277+
return hasUnderscoredLifetimeAttr(decl);
278+
}
279+
}
280+
260281
static bool usesFeatureLifetimeDependence(Decl *decl) {
261282
if (decl->getAttrs().hasAttribute<LifetimeAttr>()) {
283+
if (findUnderscoredLifetimeAttr(decl)) {
284+
// Experimental feature Lifetimes will guard the decl.
285+
return false;
286+
}
262287
return true;
263288
}
289+
264290
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
265291
return afd->getInterfaceType()
266292
->getAs<AnyFunctionType>()
@@ -272,6 +298,10 @@ static bool usesFeatureLifetimeDependence(Decl *decl) {
272298
return false;
273299
}
274300

301+
static bool usesFeatureLifetimes(Decl *decl) {
302+
return findUnderscoredLifetimeAttr(decl);
303+
}
304+
275305
static bool usesFeatureInoutLifetimeDependence(Decl *decl) {
276306
auto hasInoutLifetimeDependence = [](Decl *decl) {
277307
for (auto attr : decl->getAttrs().getAttributes<LifetimeAttr>()) {

lib/AST/LifetimeDependence.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,15 @@ class LifetimeDependenceChecker {
300300
assert(lifetimeDependencies.empty());
301301

302302
// Handle Builtins first because, even though Builtins require
303-
// LifetimeDependence, we don't force Feature::LifetimeDependence
303+
// LifetimeDependence, we don't force the experimental feature
304304
// to be enabled when importing the Builtin module.
305305
if (afd->isImplicit() && afd->getModuleContext()->isBuiltinModule()) {
306306
inferBuiltin();
307307
return currentDependencies();
308308
}
309309

310310
if (!ctx.LangOpts.hasFeature(Feature::LifetimeDependence)
311+
&& !ctx.LangOpts.hasFeature(Feature::Lifetimes)
311312
&& !ctx.SourceMgr.isImportMacroGeneratedLoc(returnLoc)) {
312313

313314
// Infer inout dependencies without requiring a feature flag. On

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5349,7 +5349,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
53495349
}
53505350

53515351
if (P.isSILLifetimeDependenceToken()) {
5352-
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence)) {
5352+
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
5353+
!P.Context.LangOpts.hasFeature(Feature::Lifetimes)) {
53535354
P.diagnose(Tok, diag::requires_experimental_feature,
53545355
"lifetime dependence specifier", false,
53555356
Feature::LifetimeDependence.getName());

lib/Sema/TypeCheckAttr.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8183,19 +8183,25 @@ void AttributeChecker::visitWeakLinkedAttr(WeakLinkedAttr *attr) {
81838183
}
81848184

81858185
void AttributeChecker::visitLifetimeAttr(LifetimeAttr *attr) {
8186-
// Allow @lifetime only in the stdlib, cxx and backward compatibility modules
8187-
if (!attr->isUnderscored() &&
8188-
!(Ctx.MainModule->isStdlibModule() || Ctx.MainModule->isCxxModule() ||
8189-
Ctx.MainModule->getABIName() == Ctx.StdlibModuleName)) {
8190-
Ctx.Diags.diagnose(attr->getLocation(), diag::use_lifetime_underscored);
8191-
}
8192-
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence) &&
8193-
!Ctx.SourceMgr.isImportMacroGeneratedLoc(attr->getLocation())) {
8194-
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8195-
std::string("@") + (attr->isUnderscored()
8196-
? std::string("_lifetime")
8197-
: std::string("lifetime")),
8198-
false, Feature::LifetimeDependence.getName());
8186+
if (!attr->isUnderscored()) {
8187+
// Allow @lifetime only in the stdlib, cxx and backward compatibility
8188+
// modules under -enable-experimental-feature LifetimeDependence
8189+
if (!Ctx.MainModule->isStdlibModule() && !Ctx.MainModule->isCxxModule() &&
8190+
Ctx.MainModule->getABIName() != Ctx.StdlibModuleName) {
8191+
Ctx.Diags.diagnose(attr->getLocation(), diag::use_lifetime_underscored);
8192+
}
8193+
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence)) {
8194+
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8195+
"@lifetime", false, Feature::LifetimeDependence.getName());
8196+
}
8197+
} else {
8198+
// Allow @_lifetime under -enable-experimental-feature Lifetimes
8199+
if (!Ctx.LangOpts.hasFeature(Feature::Lifetimes) &&
8200+
!Ctx.SourceMgr.isImportMacroGeneratedLoc(attr->getLocation())) {
8201+
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8202+
"@_lifetime",
8203+
false, Feature::Lifetimes.getName());
8204+
}
81998205
}
82008206
}
82018207

0 commit comments

Comments
 (0)