Frontend: Allow -enable-experimental-feature to specify upcoming features.

During the lifecycle of a feature, it may start as an experimental feature and
then graduate to become an upcoming feature. To preserve compatibility with
projects that adopted the feature when it was experimental,
`-enable-experimental-feature` ought to be able to enable upcoming features,
too.

Since projects may use `-enable-experimental-feature` for compatibility with an
older toolchain that does not have the feature as an upcoming feature, there is
no warning when the flag is used to enable an upcoming feature.

Note that if the semantics of a feature change when it graduates from
experimental to upcoming, then the feature must be renamed so that projects
using the experimental feature have an opportunity opt-in to the new semantics
of the upcoming feature.

Resolves rdar://134276783.
This commit is contained in:
Allan Shortlidge
2024-08-19 12:17:24 -07:00
parent 4229a917cb
commit ad1acd7f4a
7 changed files with 31 additions and 21 deletions

View File

@@ -1014,6 +1014,21 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableExperimentalStringProcessing = true;
}
auto enableUpcomingFeature = [&Opts, &Diags](Feature feature) -> bool {
// Check if this feature was introduced already in this language version.
if (auto firstVersion = getFeatureLanguageVersion(feature)) {
if (Opts.isSwiftVersionAtLeast(*firstVersion)) {
Diags.diagnose(SourceLoc(), diag::error_upcoming_feature_on_by_default,
getFeatureName(feature), *firstVersion);
return true;
}
}
Opts.enableFeature(feature);
return false;
};
// Enable experimental features.
for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) {
// Allow StrictConcurrency to have a value that corresponds to the
// -strict-concurrency=<blah> settings.
@@ -1040,12 +1055,14 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
} else {
Opts.enableFeature(*feature);
}
}
if (*feature == Feature::NoncopyableGenerics2)
Opts.enableFeature(Feature::NoncopyableGenerics);
if (*feature == Feature::IsolatedAny2)
Opts.enableFeature(Feature::IsolatedAny);
// For compatibility, upcoming features can be enabled with the
// -enable-experimental-feature flag too since the feature may have
// graduated from being experimental.
if (auto feature = getUpcomingFeature(value)) {
if (enableUpcomingFeature(*feature))
HadError = true;
}
// Hack: In order to support using availability macros in SPM packages, we
@@ -1062,24 +1079,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
}
// Map historical flags over to future features.
// Enable upcoming features.
for (const Arg *A : Args.filtered(OPT_enable_upcoming_feature)) {
// Ignore unknown features.
auto feature = getUpcomingFeature(A->getValue());
if (!feature)
continue;
// Check if this feature was introduced already in this language version.
if (auto firstVersion = getFeatureLanguageVersion(*feature)) {
if (Opts.isSwiftVersionAtLeast(*firstVersion)) {
Diags.diagnose(SourceLoc(), diag::error_upcoming_feature_on_by_default,
A->getValue(), *firstVersion);
continue;
}
}
// Add the feature.
Opts.enableFeature(*feature);
if (enableUpcomingFeature(*feature))
HadError = true;
}
// Map historical flags over to experimental features. We do this for all