diff --git a/include/swift/Basic/Feature.h b/include/swift/Basic/Feature.h index b346eae64a0f3..ae008236b9340 100644 --- a/include/swift/Basic/Feature.h +++ b/include/swift/Basic/Feature.h @@ -13,6 +13,7 @@ #ifndef SWIFT_BASIC_FEATURES_H #define SWIFT_BASIC_FEATURES_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" namespace swift { @@ -51,10 +52,17 @@ inline bool featureImpliesFeature(Feature feature, Feature implied) { return (unsigned) feature < (unsigned) implied; } +/// Get the feature corresponding to this "future" feature, if there is one. +llvm::Optional getFutureFeature(llvm::StringRef name); + /// Get the feature corresponding to this "experimental" feature, if there is /// one. llvm::Optional getExperimentalFeature(llvm::StringRef name); +/// Get the major language version in which this feature was introduced, or +/// \c None if it does not have such a version. +llvm::Optional getFeatureLanguageVersion(Feature feature); + } #endif // SWIFT_BASIC_FEATURES_H diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 0715cde915a6d..e93bd5b317d22 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -48,6 +48,12 @@ LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) #endif +#ifndef FUTURE_FEATURE +# define FUTURE_FEATURE(FeatureName, SENumber, Version) \ + LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName, \ + langOpts.hasFeature(#FeatureName)) +#endif + #ifndef EXPERIMENTAL_FEATURE # define EXPERIMENTAL_FEATURE(FeatureName) \ LANGUAGE_FEATURE(FeatureName, 0, #FeatureName, \ @@ -83,6 +89,10 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes2, 346, "Primary associated SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true) SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true) +FUTURE_FEATURE(ConciseMagicFile, 274, 6) +FUTURE_FEATURE(ForwardTrailingClosures, 286, 6) +FUTURE_FEATURE(BareSlashRegexLiterals, 354, 6) + EXPERIMENTAL_FEATURE(StaticAssert) EXPERIMENTAL_FEATURE(VariadicGenerics) EXPERIMENTAL_FEATURE(NamedOpaqueTypes) @@ -92,5 +102,6 @@ EXPERIMENTAL_FEATURE(OneWayClosureParameters) EXPERIMENTAL_FEATURE(TypeWitnessSystemInference) #undef EXPERIMENTAL_FEATURE +#undef FUTURE_FEATURE #undef SUPPRESSIBLE_LANGUAGE_FEATURE #undef LANGUAGE_FEATURE diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 14b23b149bb31..dab82f17d52ec 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -354,6 +354,9 @@ namespace swift { /// The set of features that have been enabled. llvm::SmallSet Features; + /// Temporary flag to support LLDB's transition to using \c Features. + bool EnableBareSlashRegexLiterals = false; + /// Use Clang function types for computing canonical types. /// If this option is false, the clang function types will still be computed /// but will not be used for checking type equality. @@ -529,10 +532,6 @@ namespace swift { /// Enables dumping type witness systems from associated type inference. bool DumpTypeWitnessSystems = false; - /// Enables `/.../` syntax regular-expression literals. This requires - /// experimental string processing. Note this does not affect `#/.../#`. - bool EnableBareSlashRegexLiterals = false; - /// Sets the target we are building for and updates platform conditions /// to match. /// diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index e46533b632d35..775785d68e793 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2999,6 +2999,18 @@ static bool usesFeatureNoAsyncAvailability(Decl *decl) { return decl->getAttrs().getNoAsync(decl->getASTContext()) != nullptr; } +static bool usesFeatureConciseMagicFile(Decl *decl) { + return false; +} + +static bool usesFeatureForwardTrailingClosures(Decl *decl) { + return false; +} + +static bool usesFeatureBareSlashRegexLiterals(Decl *decl) { + return false; +} + static bool usesFeatureVariadicGenerics(Decl *decl) { return false; } diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 39217ad2b2a7f..a2c832da04028 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -23,6 +23,7 @@ #include "swift/Config.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include @@ -228,10 +229,20 @@ bool LangOptions::hasFeature(Feature feature) const { if (Features.contains(feature)) return true; + if (feature == Feature::BareSlashRegexLiterals && + EnableBareSlashRegexLiterals) + return true; + + if (auto version = getFeatureLanguageVersion(feature)) + return isSwiftVersionAtLeast(*version); + return false; } bool LangOptions::hasFeature(llvm::StringRef featureName) const { + if (auto feature = getFutureFeature(featureName)) + return hasFeature(*feature); + if (auto feature = getExperimentalFeature(featureName)) return hasFeature(*feature); @@ -423,6 +434,15 @@ bool swift::isSuppressibleFeature(Feature feature) { llvm_unreachable("covered switch"); } +llvm::Optional swift::getFutureFeature(llvm::StringRef name) { + return llvm::StringSwitch>(name) +#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) +#define FUTURE_FEATURE(FeatureName, SENumber, Version) \ + .Case(#FeatureName, Feature::FeatureName) +#include "swift/Basic/Features.def" + .Default(None); +} + llvm::Optional swift::getExperimentalFeature(llvm::StringRef name) { return llvm::StringSwitch>(name) #define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) @@ -432,6 +452,16 @@ llvm::Optional swift::getExperimentalFeature(llvm::StringRef name) { .Default(None); } +llvm::Optional swift::getFeatureLanguageVersion(Feature feature) { + switch (feature) { +#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) +#define FUTURE_FEATURE(FeatureName, SENumber, Version) \ + case Feature::FeatureName: return Version; +#include "swift/Basic/Features.def" + default: return None; + } +} + DiagnosticBehavior LangOptions::getAccessNoteFailureLimit() const { switch (AccessNoteBehavior) { case AccessNoteDiagnosticBehavior::Ignore: diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 9d9b52422dc51..6e8a1f574ddfc 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -486,25 +486,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, = A->getOption().matches(OPT_enable_deserialization_recovery); } - // Whether '/.../' regex literals are enabled. This implies experimental - // string processing. - if (Args.hasArg(OPT_enable_bare_slash_regex)) { - Opts.EnableBareSlashRegexLiterals = true; - Opts.EnableExperimentalStringProcessing = true; - } - - // Experimental string processing. - if (auto A = Args.getLastArg(OPT_enable_experimental_string_processing, - OPT_disable_experimental_string_processing)) { - Opts.EnableExperimentalStringProcessing = - A->getOption().matches(OPT_enable_experimental_string_processing); - - // When experimental string processing is explicitly disabled, also disable - // forward slash regex `/.../`. - if (!Opts.EnableExperimentalStringProcessing) - Opts.EnableBareSlashRegexLiterals = false; - } - Opts.EnableExperimentalBoundGenericExtensions |= Args.hasArg(OPT_enable_experimental_bound_generic_extensions); @@ -632,6 +613,29 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.addCustomConditionalCompilationFlag(A->getValue()); } + // Determine whether string processing is enabled + Opts.EnableExperimentalStringProcessing = + Args.hasFlag(OPT_enable_experimental_string_processing, + OPT_disable_experimental_string_processing, + Args.hasArg(OPT_enable_bare_slash_regex)); + + // Add a future feature if it is not already implied by the language version. + auto addFutureFeatureIfNotImplied = [&](Feature feature) { + // Check if this feature was introduced already in this language version. + if (auto firstVersion = getFeatureLanguageVersion(feature)) { + if (Opts.isSwiftVersionAtLeast(*firstVersion)) + return; + } + + Opts.Features.insert(feature); + }; + + // Map historical flags over to future features. + if (Args.hasArg(OPT_enable_experimental_concise_pound_file)) + addFutureFeatureIfNotImplied(Feature::ConciseMagicFile); + if (Args.hasArg(OPT_enable_bare_slash_regex)) + addFutureFeatureIfNotImplied(Feature::BareSlashRegexLiterals); + for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) { // If this is a known experimental feature, allow it in +Asserts // (non-release) builds for testing purposes. @@ -759,10 +763,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, A->getAsString(Args), A->getValue()); } - Opts.EnableConcisePoundFile = - Args.hasArg(OPT_enable_experimental_concise_pound_file) || - Opts.EffectiveLanguageVersion.isVersionAtLeast(6); - Opts.EnableCrossImportOverlays = Args.hasFlag(OPT_enable_cross_import_overlays, OPT_disable_cross_import_overlays, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4b4fc6690ea2f..bba711385c720 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -881,7 +881,8 @@ UnresolvedDeclRefExpr *Parser::parseExprOperator() { } void Parser::tryLexRegexLiteral(bool forUnappliedOperator) { - if (!Context.LangOpts.EnableBareSlashRegexLiterals) + if (!Context.LangOpts.hasFeature(Feature::BareSlashRegexLiterals) || + !Context.LangOpts.EnableExperimentalStringProcessing) return; // Check to see if we have a regex literal `/.../`, optionally with a prefix @@ -1114,7 +1115,7 @@ getMagicIdentifierLiteralKind(tok Kind, const LangOptions &Opts) { switch (Kind) { case tok::pound_file: // TODO: Enable by default at the next source break. (SR-13199) - return Opts.EnableConcisePoundFile + return Opts.hasFeature(Feature::ConciseMagicFile) ? MagicIdentifierLiteralExpr::FileIDSpelledAsFile : MagicIdentifierLiteralExpr::FilePathSpelledAsFile; #define MAGIC_IDENTIFIER_TOKEN(NAME, TOKEN) \ diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 565f3b715f607..8bf9923ddd178 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -472,7 +472,7 @@ static bool matchCallArgumentsImpl( // way to successfully match arguments to parameters. if (!parameterRequiresArgument(params, paramInfo, paramIdx) && !param.getPlainType()->getASTContext().LangOpts - .isSwiftVersionAtLeast(6) && + .hasFeature(Feature::ForwardTrailingClosures) && anyParameterRequiresArgument( params, paramInfo, paramIdx + 1, nextArgIdx + 1 < numArgs @@ -934,7 +934,7 @@ static bool requiresBothTrailingClosureDirections( // If backward matching is disabled, only scan forward. ASTContext &ctx = params.front().getPlainType()->getASTContext(); - if (ctx.LangOpts.isSwiftVersionAtLeast(6)) + if (ctx.LangOpts.hasFeature(Feature::ForwardTrailingClosures)) return false; // If there are at least two parameters that meet the backward scan's diff --git a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp index 06fbade762b77..d5f0025f52dad 100644 --- a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp +++ b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp @@ -512,9 +512,7 @@ swiftparse_client_node_t SynParser::parse(const char *source, size_t len) { // Always enable bare /.../ regex literal in syntax parser. langOpts.EnableExperimentalStringProcessing = true; - if (EnableBareSlashRegexLiteral && *EnableBareSlashRegexLiteral) { - langOpts.EnableBareSlashRegexLiterals = true; - } + langOpts.Features.insert(Feature::BareSlashRegexLiterals); if (EffectiveLanguageVersion) { langOpts.EffectiveLanguageVersion = *EffectiveLanguageVersion; } diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 66b6f41eec1d5..3371c8fdc9ee8 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -4305,7 +4305,7 @@ int main(int argc, char *argv[]) { InitInvok.getLangOptions().EnableExperimentalStringProcessing = true; } if (options::EnableBareSlashRegexLiterals) { - InitInvok.getLangOptions().EnableBareSlashRegexLiterals = true; + InitInvok.getLangOptions().Features.insert(Feature::BareSlashRegexLiterals); InitInvok.getLangOptions().EnableExperimentalStringProcessing = true; } diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp index 0d37ad0ec3c12..e1d133f17aa70 100644 --- a/tools/swift-syntax-test/swift-syntax-test.cpp +++ b/tools/swift-syntax-test/swift-syntax-test.cpp @@ -592,7 +592,7 @@ int parseFile( Invocation.getLangOptions().VerifySyntaxTree = options::VerifySyntaxTree; Invocation.getLangOptions().DisablePoundIfEvaluation = true; Invocation.getLangOptions().EnableExperimentalStringProcessing = true; - Invocation.getLangOptions().EnableBareSlashRegexLiterals = true; + Invocation.getLangOptions().Features.insert(Feature::BareSlashRegexLiterals); Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(InputFileName);