mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Introduce a new suppressible experimental feature to guard @_lifetime
This commit is contained in:
@@ -395,6 +395,9 @@ public:
|
||||
/// as public
|
||||
bool SuppressIsolatedDeinit = false;
|
||||
|
||||
/// Suppress @_lifetime attribute and emit @lifetime instead.
|
||||
bool SuppressLifetimes = false;
|
||||
|
||||
/// Whether to print the \c{/*not inherited*/} comment on factory initializers.
|
||||
bool PrintFactoryInitializerComment = true;
|
||||
|
||||
|
||||
@@ -525,6 +525,9 @@ EXPERIMENTAL_FEATURE(ModuleSelector, false)
|
||||
/// in a file scope.
|
||||
EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false)
|
||||
|
||||
/// Enable @_lifetime attribute
|
||||
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
|
||||
@@ -1158,7 +1158,8 @@ public:
|
||||
|
||||
bool isParameterSpecifier() {
|
||||
if (Tok.is(tok::kw_inout)) return true;
|
||||
if (Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
|
||||
if ((Context.LangOpts.hasFeature(Feature::LifetimeDependence) ||
|
||||
Context.LangOpts.hasFeature(Feature::Lifetimes)) &&
|
||||
isSILLifetimeDependenceToken())
|
||||
return true;
|
||||
if (!canHaveParameterSpecifierContextualKeyword()) return false;
|
||||
|
||||
@@ -3261,6 +3261,13 @@ suppressingFeatureIsolatedDeinit(PrintOptions &options,
|
||||
action();
|
||||
}
|
||||
|
||||
static void
|
||||
suppressingFeatureLifetimes(PrintOptions &options,
|
||||
llvm::function_ref<void()> action) {
|
||||
llvm::SaveAndRestore<bool> scope(options.SuppressLifetimes, true);
|
||||
action();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ExcludeAttrRAII {
|
||||
std::vector<AnyAttrKind> &ExcludeAttrList;
|
||||
|
||||
@@ -1690,7 +1690,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
|
||||
|
||||
case DeclAttrKind::Lifetime: {
|
||||
auto *attr = cast<LifetimeAttr>(this);
|
||||
Printer << attr->getString();
|
||||
if (!attr->isUnderscored() || Options.SuppressLifetimes) {
|
||||
Printer << "@lifetime" << attr->getLifetimeEntry()->getString();
|
||||
} else {
|
||||
Printer << "@_lifetime" << attr->getLifetimeEntry()->getString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -258,10 +258,36 @@ static bool usesFeatureSendingArgsAndResults(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool findUnderscoredLifetimeAttr(Decl *decl) {
|
||||
auto hasUnderscoredLifetimeAttr = [](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();
|
||||
};
|
||||
|
||||
switch (decl->getKind()) {
|
||||
case DeclKind::Var: {
|
||||
auto *var = cast<VarDecl>(decl);
|
||||
return llvm::any_of(var->getAllAccessors(), hasUnderscoredLifetimeAttr);
|
||||
}
|
||||
default:
|
||||
return hasUnderscoredLifetimeAttr(decl);
|
||||
}
|
||||
}
|
||||
|
||||
static bool usesFeatureLifetimeDependence(Decl *decl) {
|
||||
if (decl->getAttrs().hasAttribute<LifetimeAttr>()) {
|
||||
if (findUnderscoredLifetimeAttr(decl)) {
|
||||
// Experimental feature Lifetimes will guard the decl.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
|
||||
return afd->getInterfaceType()
|
||||
->getAs<AnyFunctionType>()
|
||||
@@ -273,6 +299,10 @@ static bool usesFeatureLifetimeDependence(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool usesFeatureLifetimes(Decl *decl) {
|
||||
return findUnderscoredLifetimeAttr(decl);
|
||||
}
|
||||
|
||||
static bool usesFeatureInoutLifetimeDependence(Decl *decl) {
|
||||
auto hasInoutLifetimeDependence = [](Decl *decl) {
|
||||
for (auto attr : decl->getAttrs().getAttributes<LifetimeAttr>()) {
|
||||
|
||||
@@ -300,7 +300,7 @@ public:
|
||||
assert(lifetimeDependencies.empty());
|
||||
|
||||
// Handle Builtins first because, even though Builtins require
|
||||
// LifetimeDependence, we don't force Feature::LifetimeDependence
|
||||
// LifetimeDependence, we don't force the experimental feature
|
||||
// to be enabled when importing the Builtin module.
|
||||
if (afd->isImplicit() && afd->getModuleContext()->isBuiltinModule()) {
|
||||
inferBuiltin();
|
||||
@@ -308,6 +308,7 @@ public:
|
||||
}
|
||||
|
||||
if (!ctx.LangOpts.hasFeature(Feature::LifetimeDependence)
|
||||
&& !ctx.LangOpts.hasFeature(Feature::Lifetimes)
|
||||
&& !ctx.SourceMgr.isImportMacroGeneratedLoc(returnLoc)) {
|
||||
|
||||
// Infer inout dependencies without requiring a feature flag. On
|
||||
|
||||
@@ -5374,7 +5374,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
|
||||
}
|
||||
|
||||
if (P.isSILLifetimeDependenceToken()) {
|
||||
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence)) {
|
||||
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
|
||||
!P.Context.LangOpts.hasFeature(Feature::Lifetimes)) {
|
||||
P.diagnose(Tok, diag::requires_experimental_feature,
|
||||
"lifetime dependence specifier", false,
|
||||
Feature::LifetimeDependence.getName());
|
||||
|
||||
@@ -8226,19 +8226,25 @@ void AttributeChecker::visitWeakLinkedAttr(WeakLinkedAttr *attr) {
|
||||
}
|
||||
|
||||
void AttributeChecker::visitLifetimeAttr(LifetimeAttr *attr) {
|
||||
// Allow @lifetime only in the stdlib, cxx and backward compatibility modules
|
||||
if (!attr->isUnderscored() &&
|
||||
!(Ctx.MainModule->isStdlibModule() || Ctx.MainModule->isCxxModule() ||
|
||||
Ctx.MainModule->getABIName() == Ctx.StdlibModuleName)) {
|
||||
if (!attr->isUnderscored()) {
|
||||
// Allow @lifetime only in the stdlib, cxx and backward compatibility
|
||||
// modules under -enable-experimental-feature LifetimeDependence
|
||||
if (!Ctx.MainModule->isStdlibModule() && !Ctx.MainModule->isCxxModule() &&
|
||||
Ctx.MainModule->getABIName() != Ctx.StdlibModuleName) {
|
||||
Ctx.Diags.diagnose(attr->getLocation(), diag::use_lifetime_underscored);
|
||||
}
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence) &&
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::LifetimeDependence)) {
|
||||
diagnose(attr->getLocation(), diag::requires_experimental_feature,
|
||||
"@lifetime", false, Feature::LifetimeDependence.getName());
|
||||
}
|
||||
} else {
|
||||
// Allow @_lifetime under -enable-experimental-feature Lifetimes
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::Lifetimes) &&
|
||||
!Ctx.SourceMgr.isImportMacroGeneratedLoc(attr->getLocation())) {
|
||||
diagnose(attr->getLocation(), diag::requires_experimental_feature,
|
||||
std::string("@") + (attr->isUnderscored()
|
||||
? std::string("_lifetime")
|
||||
: std::string("lifetime")),
|
||||
false, Feature::LifetimeDependence.getName());
|
||||
"@_lifetime",
|
||||
false, Feature::Lifetimes.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user