@@ -740,6 +740,151 @@ static bool ParseCASArgs(CASOptions &Opts, ArgList &Args,
740740 return false ;
741741}
742742
743+ static bool ParseEnabledFeatureArgs (LangOptions &Opts, ArgList &Args,
744+ DiagnosticEngine &Diags,
745+ const FrontendOptions &FrontendOpts) {
746+ using namespace options ;
747+
748+ bool HadError = false ;
749+
750+ // Enable feature upcoming/experimental features if requested. However, leave
751+ // a feature disabled if an -enable-upcoming-feature flag is superseded by a
752+ // -disable-upcoming-feature flag. Since only the last flag specified is
753+ // honored, we iterate over them in reverse order.
754+ std::vector<StringRef> psuedoFeatures;
755+ llvm::SmallSet<Feature, 8 > seenFeatures;
756+ for (const Arg *A : Args.filtered_reverse (
757+ OPT_enable_experimental_feature, OPT_disable_experimental_feature,
758+ OPT_enable_upcoming_feature, OPT_disable_upcoming_feature)) {
759+ auto &option = A->getOption ();
760+ StringRef value = A->getValue ();
761+ bool enableUpcoming = option.matches (OPT_enable_upcoming_feature);
762+ bool enableFeature =
763+ enableUpcoming || option.matches (OPT_enable_experimental_feature);
764+
765+ // Collect some special case pseudo-features which should be processed
766+ // separately.
767+ if (value.starts_with (" StrictConcurrency" ) ||
768+ value.starts_with (" AvailabilityMacro=" )) {
769+ if (enableFeature)
770+ psuedoFeatures.push_back (value);
771+ continue ;
772+ }
773+
774+ // If this was specified as an "upcoming feature", it must be recognized
775+ // as one.
776+ auto feature = getUpcomingFeature (value);
777+ if (enableUpcoming || option.matches (OPT_disable_upcoming_feature)) {
778+ if (!feature)
779+ continue ;
780+ }
781+
782+ // If it's not recognized as either an upcoming feature or an experimental
783+ // feature, skip it.
784+ if (!feature) {
785+ feature = getExperimentalFeature (value);
786+ if (!feature)
787+ continue ;
788+ }
789+
790+ // Skip features that are already enabled or disabled.
791+ if (!seenFeatures.insert (*feature).second )
792+ continue ;
793+
794+ // If the the current language mode enables the feature by default then
795+ // diagnose and skip it.
796+ if (auto firstVersion = getFeatureLanguageVersion (*feature)) {
797+ if (Opts.isSwiftVersionAtLeast (*firstVersion)) {
798+ Diags
799+ .diagnose (SourceLoc (), diag::error_upcoming_feature_on_by_default,
800+ getFeatureName (*feature), *firstVersion)
801+ .limitBehaviorIf (!enableUpcoming, DiagnosticBehavior::Warning);
802+ if (enableUpcoming)
803+ HadError = true ;
804+
805+ continue ;
806+ }
807+ }
808+
809+ // If this is a known experimental feature, allow it in +Asserts
810+ // (non-release) builds for testing purposes.
811+ if (Opts.RestrictNonProductionExperimentalFeatures &&
812+ !isFeatureAvailableInProduction (*feature)) {
813+ Diags.diagnose (SourceLoc (),
814+ diag::experimental_not_supported_in_production, value);
815+ HadError = true ;
816+ continue ;
817+ }
818+
819+ // Enable the feature if requested.
820+ if (enableFeature)
821+ Opts.enableFeature (*feature);
822+ }
823+
824+ // Since pseudo-features don't have a boolean on/off state, process them in
825+ // the order they were specified on the command line.
826+ for (auto featureName = psuedoFeatures.rbegin (), end = psuedoFeatures.rend ();
827+ featureName != end; ++featureName) {
828+
829+ // Allow StrictConcurrency to have a value that corresponds to the
830+ // -strict-concurrency=<blah> settings.
831+ if (featureName->starts_with (" StrictConcurrency" )) {
832+ auto decomposed = featureName->split (" =" );
833+ if (decomposed.first == " StrictConcurrency" ) {
834+ if (decomposed.second == " " ) {
835+ Opts.StrictConcurrencyLevel = StrictConcurrency::Complete;
836+ } else if (auto level = parseStrictConcurrency (decomposed.second )) {
837+ Opts.StrictConcurrencyLevel = *level;
838+ }
839+ }
840+ continue ;
841+ }
842+
843+ // Hack: In order to support using availability macros in SPM packages, we
844+ // need to be able to use:
845+ // .enableExperimentalFeature("AvailabilityMacro='...'")
846+ // within the package manifest and the feature recognizer can't recognize
847+ // this form of feature, so specially handle it here until features can
848+ // maybe have extra arguments in the future.
849+ if (featureName->starts_with (" AvailabilityMacro=" )) {
850+ auto availability = featureName->split (" =" ).second ;
851+ Opts.AvailabilityMacros .push_back (availability.str ());
852+ continue ;
853+ }
854+ }
855+
856+ // Map historical flags over to experimental features. We do this for all
857+ // compilers because that's how existing experimental feature flags work.
858+ if (Args.hasArg (OPT_enable_experimental_static_assert))
859+ Opts.enableFeature (Feature::StaticAssert);
860+ if (Args.hasArg (OPT_enable_experimental_named_opaque_types))
861+ Opts.enableFeature (Feature::NamedOpaqueTypes);
862+ if (Args.hasArg (OPT_enable_experimental_flow_sensitive_concurrent_captures))
863+ Opts.enableFeature (Feature::FlowSensitiveConcurrencyCaptures);
864+ if (Args.hasArg (OPT_enable_experimental_move_only)) {
865+ // FIXME: drop addition of Feature::MoveOnly once its queries are gone.
866+ Opts.enableFeature (Feature::MoveOnly);
867+ Opts.enableFeature (Feature::NoImplicitCopy);
868+ Opts.enableFeature (Feature::OldOwnershipOperatorSpellings);
869+ }
870+ if (Args.hasArg (OPT_experimental_one_way_closure_params))
871+ Opts.enableFeature (Feature::OneWayClosureParameters);
872+ if (Args.hasArg (OPT_enable_experimental_forward_mode_differentiation))
873+ Opts.enableFeature (Feature::ForwardModeDifferentiation);
874+ if (Args.hasArg (OPT_enable_experimental_additive_arithmetic_derivation))
875+ Opts.enableFeature (Feature::AdditiveArithmeticDerivedConformances);
876+
877+ if (Args.hasArg (OPT_enable_experimental_opaque_type_erasure))
878+ Opts.enableFeature (Feature::OpaqueTypeErasure);
879+
880+ if (Args.hasArg (OPT_enable_builtin_module))
881+ Opts.enableFeature (Feature::BuiltinModule);
882+
883+ Opts.enableFeature (Feature::LayoutPrespecialization);
884+
885+ return HadError;
886+ }
887+
743888static bool ParseLangArgs (LangOptions &Opts, ArgList &Args,
744889 DiagnosticEngine &Diags,
745890 const FrontendOptions &FrontendOpts) {
@@ -1012,113 +1157,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10121157 Opts.EnableExperimentalStringProcessing = true ;
10131158 }
10141159
1015- auto enableUpcomingFeature = [&Opts, &Diags](Feature feature,
1016- bool downgradeDiag) -> bool {
1017- // Check if this feature was introduced already in this language version.
1018- if (auto firstVersion = getFeatureLanguageVersion (feature)) {
1019- if (Opts.isSwiftVersionAtLeast (*firstVersion)) {
1020- Diags
1021- .diagnose (SourceLoc (), diag::error_upcoming_feature_on_by_default,
1022- getFeatureName (feature), *firstVersion)
1023- .limitBehaviorIf (downgradeDiag, DiagnosticBehavior::Warning);
1024- return !downgradeDiag;
1025- }
1026- }
1027-
1028- Opts.enableFeature (feature);
1029- return false ;
1030- };
1031-
1032- // Enable experimental features.
1033- for (const Arg *A : Args.filtered (OPT_enable_experimental_feature)) {
1034- // Allow StrictConcurrency to have a value that corresponds to the
1035- // -strict-concurrency=<blah> settings.
1036- StringRef value = A->getValue ();
1037- if (value.starts_with (" StrictConcurrency" )) {
1038- auto decomposed = value.split (" =" );
1039- if (decomposed.first == " StrictConcurrency" ) {
1040- if (decomposed.second == " " ) {
1041- Opts.StrictConcurrencyLevel = StrictConcurrency::Complete;
1042- } else if (auto level = parseStrictConcurrency (decomposed.second )) {
1043- Opts.StrictConcurrencyLevel = *level;
1044- }
1045- }
1046- }
1047-
1048- // If this is a known experimental feature, allow it in +Asserts
1049- // (non-release) builds for testing purposes.
1050- if (auto feature = getExperimentalFeature (value)) {
1051- if (Opts.RestrictNonProductionExperimentalFeatures &&
1052- !isFeatureAvailableInProduction (*feature)) {
1053- Diags.diagnose (SourceLoc (), diag::experimental_not_supported_in_production,
1054- A->getValue ());
1055- HadError = true ;
1056- } else {
1057- Opts.enableFeature (*feature);
1058- }
1059- }
1060-
1061- // For compatibility, upcoming features can be enabled with the
1062- // -enable-experimental-feature flag too since the feature may have
1063- // graduated from being experimental.
1064- if (auto feature = getUpcomingFeature (value)) {
1065- if (enableUpcomingFeature (*feature, /* downgradeDiag=*/ true ))
1066- HadError = true ;
1067- }
1068-
1069- // Hack: In order to support using availability macros in SPM packages, we
1070- // need to be able to use:
1071- // .enableExperimentalFeature("AvailabilityMacro='...'")
1072- // within the package manifest and the feature recognizer can't recognize
1073- // this form of feature, so specially handle it here until features can
1074- // maybe have extra arguments in the future.
1075- auto strRef = StringRef (A->getValue ());
1076- if (strRef.starts_with (" AvailabilityMacro=" )) {
1077- auto availability = strRef.split (" =" ).second ;
1078-
1079- Opts.AvailabilityMacros .push_back (availability.str ());
1080- }
1081- }
1082-
1083- // Enable upcoming features.
1084- for (const Arg *A : Args.filtered (OPT_enable_upcoming_feature)) {
1085- // Ignore unknown features.
1086- auto feature = getUpcomingFeature (A->getValue ());
1087- if (!feature)
1088- continue ;
1089-
1090- if (enableUpcomingFeature (*feature, /* downgradeDiag=*/ false ))
1091- HadError = true ;
1092- }
1093-
1094- // Map historical flags over to experimental features. We do this for all
1095- // compilers because that's how existing experimental feature flags work.
1096- if (Args.hasArg (OPT_enable_experimental_static_assert))
1097- Opts.enableFeature (Feature::StaticAssert);
1098- if (Args.hasArg (OPT_enable_experimental_named_opaque_types))
1099- Opts.enableFeature (Feature::NamedOpaqueTypes);
1100- if (Args.hasArg (OPT_enable_experimental_flow_sensitive_concurrent_captures))
1101- Opts.enableFeature (Feature::FlowSensitiveConcurrencyCaptures);
1102- if (Args.hasArg (OPT_enable_experimental_move_only)) {
1103- // FIXME: drop addition of Feature::MoveOnly once its queries are gone.
1104- Opts.enableFeature (Feature::MoveOnly);
1105- Opts.enableFeature (Feature::NoImplicitCopy);
1106- Opts.enableFeature (Feature::OldOwnershipOperatorSpellings);
1107- }
1108- if (Args.hasArg (OPT_experimental_one_way_closure_params))
1109- Opts.enableFeature (Feature::OneWayClosureParameters);
1110- if (Args.hasArg (OPT_enable_experimental_forward_mode_differentiation))
1111- Opts.enableFeature (Feature::ForwardModeDifferentiation);
1112- if (Args.hasArg (OPT_enable_experimental_additive_arithmetic_derivation))
1113- Opts.enableFeature (Feature::AdditiveArithmeticDerivedConformances);
1114-
1115- if (Args.hasArg (OPT_enable_experimental_opaque_type_erasure))
1116- Opts.enableFeature (Feature::OpaqueTypeErasure);
1117-
1118- if (Args.hasArg (OPT_enable_builtin_module))
1119- Opts.enableFeature (Feature::BuiltinModule);
1120-
1121- Opts.enableFeature (Feature::LayoutPrespecialization);
1160+ if (ParseEnabledFeatureArgs (Opts, Args, Diags, FrontendOpts))
1161+ HadError = true ;
11221162
11231163 Opts.EnableAppExtensionLibraryRestrictions |= Args.hasArg (OPT_enable_app_extension_library);
11241164 Opts.EnableAppExtensionRestrictions |= Args.hasArg (OPT_enable_app_extension);
0 commit comments