2020#include " swift/Basic/Assertions.h"
2121#include " swift/Basic/Feature.h"
2222#include " swift/Basic/Platform.h"
23+ #include " swift/Basic/Version.h"
2324#include " swift/Option/Options.h"
2425#include " swift/Option/SanitizerOptions.h"
2526#include " swift/Parse/Lexer.h"
@@ -92,20 +93,6 @@ void CompilerInvocation::setMainExecutablePath(StringRef Path) {
9293 llvm::sys::path::remove_filename (clangPath);
9394 llvm::sys::path::append (clangPath, " clang" );
9495 ClangImporterOpts.clangPath = std::string (clangPath);
95-
96- llvm::SmallString<128 > DiagnosticDocsPath (Path);
97- llvm::sys::path::remove_filename (DiagnosticDocsPath); // Remove /swift
98- llvm::sys::path::remove_filename (DiagnosticDocsPath); // Remove /bin
99- llvm::sys::path::append (DiagnosticDocsPath, " share" , " doc" , " swift" ,
100- " diagnostics" );
101- DiagnosticOpts.DiagnosticDocumentationPath = std::string (DiagnosticDocsPath.str ());
102-
103- // Compute the path to the diagnostic translations in the toolchain/build.
104- llvm::SmallString<128 > DiagnosticMessagesDir (Path);
105- llvm::sys::path::remove_filename (DiagnosticMessagesDir); // Remove /swift
106- llvm::sys::path::remove_filename (DiagnosticMessagesDir); // Remove /bin
107- llvm::sys::path::append (DiagnosticMessagesDir, " share" , " swift" , " diagnostics" );
108- DiagnosticOpts.LocalizationPath = std::string (DiagnosticMessagesDir.str ());
10996}
11097
11198static std::string
@@ -758,6 +745,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
758745 auto &option = A->getOption ();
759746 StringRef value = A->getValue ();
760747 bool enableUpcoming = option.matches (OPT_enable_upcoming_feature);
748+ bool isUpcomingFlag =
749+ enableUpcoming || option.matches (OPT_disable_upcoming_feature);
761750 bool enableFeature =
762751 enableUpcoming || option.matches (OPT_enable_experimental_feature);
763752
@@ -770,20 +759,28 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
770759 continue ;
771760 }
772761
773- // If this was specified as an "upcoming feature", it must be recognized
774- // as one.
775762 auto feature = getUpcomingFeature (value);
776- if (enableUpcoming || option.matches (OPT_disable_upcoming_feature)) {
777- if (!feature)
763+ if (feature) {
764+ // Diagnose upcoming features enabled with -enable-experimental-feature.
765+ if (!isUpcomingFlag)
766+ Diags.diagnose (SourceLoc (), diag::feature_not_experimental, value,
767+ enableFeature);
768+ } else {
769+ // If -enable-upcoming-feature was used and an upcoming feature was not
770+ // found, diagnose and continue.
771+ if (isUpcomingFlag) {
772+ Diags.diagnose (SourceLoc (), diag::unrecognized_feature, value,
773+ /* upcoming=*/ true );
778774 continue ;
779- }
775+ }
780776
781- // If it's not recognized as either an upcoming feature or an experimental
782- // feature, skip it.
783- if (!feature) {
777+ // If the feature is also not a recognized experimental feature, skip it.
784778 feature = getExperimentalFeature (value);
785- if (!feature)
779+ if (!feature) {
780+ Diags.diagnose (SourceLoc (), diag::unrecognized_feature, value,
781+ /* upcoming=*/ false );
786782 continue ;
783+ }
787784 }
788785
789786 // Skip features that are already enabled or disabled.
@@ -2369,6 +2366,9 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
23692366
23702367static bool ParseDiagnosticArgs (DiagnosticOptions &Opts, ArgList &Args,
23712368 DiagnosticEngine &Diags) {
2369+ // NOTE: This executes at the beginning of parsing the command line and cannot
2370+ // depend on the results of parsing other options.
2371+
23722372 using namespace options ;
23732373
23742374 if (Args.hasArg (OPT_verify))
@@ -2492,6 +2492,56 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
24922492 return false ;
24932493}
24942494
2495+ static void configureDiagnosticEngine (
2496+ const DiagnosticOptions &Options,
2497+ std::optional<version::Version> effectiveLanguageVersion,
2498+ StringRef mainExecutablePath, DiagnosticEngine &Diagnostics) {
2499+ if (Options.ShowDiagnosticsAfterFatalError ) {
2500+ Diagnostics.setShowDiagnosticsAfterFatalError ();
2501+ }
2502+ if (Options.SuppressWarnings ) {
2503+ Diagnostics.setSuppressWarnings (true );
2504+ }
2505+ if (Options.SuppressRemarks ) {
2506+ Diagnostics.setSuppressRemarks (true );
2507+ }
2508+ Diagnostics.setWarningsAsErrorsRules (Options.WarningsAsErrorsRules );
2509+ Diagnostics.setPrintDiagnosticNamesMode (Options.PrintDiagnosticNames );
2510+
2511+ std::string docsPath = Options.DiagnosticDocumentationPath ;
2512+ if (docsPath.empty ()) {
2513+ // Default to a location relative to the compiler.
2514+ llvm::SmallString<128 > docsPathBuffer (mainExecutablePath);
2515+ llvm::sys::path::remove_filename (docsPathBuffer); // Remove /swift
2516+ llvm::sys::path::remove_filename (docsPathBuffer); // Remove /bin
2517+ llvm::sys::path::append (docsPathBuffer, " share" , " doc" , " swift" ,
2518+ " diagnostics" );
2519+ docsPath = docsPathBuffer.str ();
2520+ }
2521+ Diagnostics.setDiagnosticDocumentationPath (docsPath);
2522+
2523+ if (!Options.LocalizationCode .empty ()) {
2524+ std::string locPath = Options.LocalizationPath ;
2525+ if (locPath.empty ()) {
2526+ llvm::SmallString<128 > locPathBuffer (mainExecutablePath);
2527+ llvm::sys::path::remove_filename (locPathBuffer); // Remove /swift
2528+ llvm::sys::path::remove_filename (locPathBuffer); // Remove /bin
2529+ llvm::sys::path::append (locPathBuffer, " share" , " swift" , " diagnostics" );
2530+ locPath = locPathBuffer.str ();
2531+ }
2532+ Diagnostics.setLocalization (Options.LocalizationCode , locPath);
2533+ }
2534+
2535+ if (effectiveLanguageVersion)
2536+ Diagnostics.setLanguageVersion (*effectiveLanguageVersion);
2537+ }
2538+
2539+ // / Configures the diagnostic engine for the invocation's options.
2540+ void CompilerInvocation::setUpDiagnosticEngine (DiagnosticEngine &diags) {
2541+ configureDiagnosticEngine (DiagnosticOpts, LangOpts.EffectiveLanguageVersion ,
2542+ FrontendOpts.MainExecutablePath , diags);
2543+ }
2544+
24952545// / Parse -enforce-exclusivity=... options
24962546void parseExclusivityEnforcementOptions (const llvm::opt::Arg *A,
24972547 SILOptions &Opts,
@@ -3742,6 +3792,16 @@ bool CompilerInvocation::parseArgs(
37423792 return true ;
37433793 }
37443794
3795+ // Parse options that control diagnostic behavior as early as possible, so
3796+ // that they can influence the behavior of diagnostics emitted during the
3797+ // rest of parsing.
3798+ if (ParseDiagnosticArgs (DiagnosticOpts, ParsedArgs, Diags)) {
3799+ return true ;
3800+ }
3801+ configureDiagnosticEngine (DiagnosticOpts,
3802+ /* effectiveLanguageVersion=*/ std::nullopt ,
3803+ mainExecutablePath, Diags);
3804+
37453805 ParseAssertionArgs (ParsedArgs);
37463806
37473807 if (ParseFrontendArgs (FrontendOpts, ParsedArgs, Diags,
@@ -3796,10 +3856,6 @@ bool CompilerInvocation::parseArgs(
37963856 return true ;
37973857 }
37983858
3799- if (ParseDiagnosticArgs (DiagnosticOpts, ParsedArgs, Diags)) {
3800- return true ;
3801- }
3802-
38033859 if (ParseMigratorArgs (MigratorOpts, LangOpts, FrontendOpts,
38043860 SearchPathOpts.RuntimeResourcePath , ParsedArgs, Diags)) {
38053861 return true ;
0 commit comments