Skip to content

Commit dcf072f

Browse files
committed
Introduce a new suppressible experimental feature to guard @_lifetime
1 parent 0dfa1fc commit dcf072f

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
@@ -395,6 +395,9 @@ struct PrintOptions {
395395
/// as public
396396
bool SuppressIsolatedDeinit = false;
397397

398+
/// Suppress @_lifetime attribute and emit @lifetime instead.
399+
bool SuppressLifetimes = false;
400+
398401
/// Whether to print the \c{/*not inherited*/} comment on factory initializers.
399402
bool PrintFactoryInitializerComment = true;
400403

include/swift/Basic/Features.def

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

528+
/// Enable @_lifetime attribute
529+
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)
530+
528531
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
529532
#undef EXPERIMENTAL_FEATURE
530533
#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
@@ -3261,6 +3261,13 @@ suppressingFeatureIsolatedDeinit(PrintOptions &options,
32613261
action();
32623262
}
32633263

3264+
static void
3265+
suppressingFeatureLifetimes(PrintOptions &options,
3266+
llvm::function_ref<void()> action) {
3267+
llvm::SaveAndRestore<bool> scope(options.SuppressLifetimes, true);
3268+
action();
3269+
}
3270+
32643271
namespace {
32653272
struct ExcludeAttrRAII {
32663273
std::vector<AnyAttrKind> &ExcludeAttrList;

lib/AST/Attr.cpp

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

16911691
case DeclAttrKind::Lifetime: {
16921692
auto *attr = cast<LifetimeAttr>(this);
1693-
Printer << attr->getString();
1693+
if (!attr->isUnderscored() || Options.SuppressLifetimes) {
1694+
Printer << "@lifetime" << attr->getLifetimeEntry()->getString();
1695+
} else {
1696+
Printer << "@_lifetime" << attr->getLifetimeEntry()->getString();
1697+
}
16941698
break;
16951699
}
16961700

lib/AST/FeatureSet.cpp

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

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

302+
static bool usesFeatureLifetimes(Decl *decl) {
303+
return findUnderscoredLifetimeAttr(decl);
304+
}
305+
276306
static bool usesFeatureInoutLifetimeDependence(Decl *decl) {
277307
auto hasInoutLifetimeDependence = [](Decl *decl) {
278308
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
@@ -5374,7 +5374,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
53745374
}
53755375

53765376
if (P.isSILLifetimeDependenceToken()) {
5377-
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence)) {
5377+
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
5378+
!P.Context.LangOpts.hasFeature(Feature::Lifetimes)) {
53785379
P.diagnose(Tok, diag::requires_experimental_feature,
53795380
"lifetime dependence specifier", false,
53805381
Feature::LifetimeDependence.getName());

lib/Sema/TypeCheckAttr.cpp

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

82288228
void AttributeChecker::visitLifetimeAttr(LifetimeAttr *attr) {
8229-
// Allow @lifetime only in the stdlib, cxx and backward compatibility modules
8230-
if (!attr->isUnderscored() &&
8231-
!(Ctx.MainModule->isStdlibModule() || Ctx.MainModule->isCxxModule() ||
8232-
Ctx.MainModule->getABIName() == Ctx.StdlibModuleName)) {
8233-
Ctx.Diags.diagnose(attr->getLocation(), diag::use_lifetime_underscored);
8234-
}
8235-
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence) &&
8236-
!Ctx.SourceMgr.isImportMacroGeneratedLoc(attr->getLocation())) {
8237-
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8238-
std::string("@") + (attr->isUnderscored()
8239-
? std::string("_lifetime")
8240-
: std::string("lifetime")),
8241-
false, Feature::LifetimeDependence.getName());
8229+
if (!attr->isUnderscored()) {
8230+
// Allow @lifetime only in the stdlib, cxx and backward compatibility
8231+
// modules under -enable-experimental-feature LifetimeDependence
8232+
if (!Ctx.MainModule->isStdlibModule() && !Ctx.MainModule->isCxxModule() &&
8233+
Ctx.MainModule->getABIName() != Ctx.StdlibModuleName) {
8234+
Ctx.Diags.diagnose(attr->getLocation(), diag::use_lifetime_underscored);
8235+
}
8236+
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence)) {
8237+
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8238+
"@lifetime", false, Feature::LifetimeDependence.getName());
8239+
}
8240+
} else {
8241+
// Allow @_lifetime under -enable-experimental-feature Lifetimes
8242+
if (!Ctx.LangOpts.hasFeature(Feature::Lifetimes) &&
8243+
!Ctx.SourceMgr.isImportMacroGeneratedLoc(attr->getLocation())) {
8244+
diagnose(attr->getLocation(), diag::requires_experimental_feature,
8245+
"@_lifetime",
8246+
false, Feature::Lifetimes.getName());
8247+
}
82428248
}
82438249
}
82448250

0 commit comments

Comments
 (0)