diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4816,8 +4816,7 @@ def verify_EQ : CommaJoined<["-"], "verify=">, MetaVarName<"">, HelpText<"Verify diagnostic output using comment directives that start with" - " prefixes in the comma-separated sequence ">, - MarshallingInfoStringVector>; + " prefixes in the comma-separated sequence ">; def verify : Flag<["-"], "verify">, HelpText<"Equivalent to -verify=expected">; def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">, diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -248,6 +248,18 @@ bool parseSimpleArgs(const llvm::opt::ArgList &Args, DiagnosticsEngine &Diags); + /// Parse command line options from DiagnosticOptions. + static bool ParseDiagnosticArgsRoundTrip(CompilerInvocation &Res, + DiagnosticOptions &Opts, + llvm::opt::ArgList &Args, + DiagnosticsEngine *Diags = nullptr, + bool DefaultDiagColor = true); + + /// Generate command line options from DiagnosticOptions. + static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts, + SmallVectorImpl &Args, + StringAllocator SA, bool DefaultDiagColor); + /// Parse command line options that map to LangOptions. static bool ParseLangArgsImpl(LangOptions &Opts, llvm::opt::ArgList &Args, InputKind IK, const llvm::Triple &T, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -731,17 +731,17 @@ for (auto *A : Args.filtered(Group)) { if (A->getOption().getKind() == Option::FlagClass) { // The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add - // its name (minus the "W" or "R" at the beginning) to the warning list. + // its name (minus the "W" or "R" at the beginning) to the diagnostics. Diagnostics.push_back( std::string(A->getOption().getName().drop_front(1))); } else if (A->getOption().matches(GroupWithValue)) { - // This is -Wfoo= or -Rfoo=, where foo is the name of the diagnostic group. + // This is -Wfoo= or -Rfoo=, where foo is the name of the diagnostic + // group. Add only the group name to the diagnostics. Diagnostics.push_back( std::string(A->getOption().getName().drop_front(1).rtrim("=-"))); } else { // Otherwise, add its value (for OPT_W_Joined and similar). - for (const auto *Arg : A->getValues()) - Diagnostics.emplace_back(Arg); + Diagnostics.push_back(A->getValue()); } } } @@ -2174,6 +2174,63 @@ return Success; } +void CompilerInvocation::GenerateDiagnosticArgs( + const DiagnosticOptions &Opts, SmallVectorImpl &Args, + StringAllocator SA, bool DefaultDiagColor) { + const DiagnosticOptions *DiagnosticOpts = &Opts; +#define DIAG_OPTION_WITH_MARSHALLING( \ + PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ + DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ + MERGER, EXTRACTOR, TABLE_INDEX) \ + GENERATE_OPTION_WITH_MARSHALLING( \ + Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ + IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#include "clang/Driver/Options.inc" +#undef DIAG_OPTION_WITH_MARSHALLING + + if (!Opts.DiagnosticSerializationFile.empty()) + GenerateArg(Args, OPT_diagnostic_serialized_file, + Opts.DiagnosticSerializationFile, SA); + + if (Opts.ShowColors) + GenerateArg(Args, OPT_fcolor_diagnostics, SA); + + if (Opts.VerifyDiagnostics && + llvm::is_contained(Opts.VerifyPrefixes, "expected")) + GenerateArg(Args, OPT_verify, SA); + + for (const auto &Prefix : Opts.VerifyPrefixes) + if (Prefix != "expected") + GenerateArg(Args, OPT_verify_EQ, Prefix, SA); + + DiagnosticLevelMask VIU = Opts.getVerifyIgnoreUnexpected(); + if (VIU == DiagnosticLevelMask::None) { + // This is the default, don't generate anything. + } else if (VIU == DiagnosticLevelMask::All) { + GenerateArg(Args, OPT_verify_ignore_unexpected, SA); + } else { + if (static_cast(VIU & DiagnosticLevelMask::Note) != 0) + GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "note", SA); + if (static_cast(VIU & DiagnosticLevelMask::Remark) != 0) + GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "remark", SA); + if (static_cast(VIU & DiagnosticLevelMask::Warning) != 0) + GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "warning", SA); + if (static_cast(VIU & DiagnosticLevelMask::Error) != 0) + GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "error", SA); + } + + for (const auto &Warning : Opts.Warnings) { + // This option is automatically generated from UndefPrefixes. + if (Warning == "undef-prefix") + continue; + Args.push_back(SA(StringRef("-W") + Warning)); + } + + for (const auto &Remark : Opts.Remarks) + Args.push_back(SA(StringRef("-R") + Remark)); +} + bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor) { @@ -2209,6 +2266,7 @@ Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ); + Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ); if (Args.hasArg(OPT_verify)) Opts.VerifyPrefixes.push_back("expected"); // Keep VerifyPrefixes in its original order for the sake of diagnostics, and @@ -2238,6 +2296,45 @@ return Success; } +bool CompilerInvocation::ParseDiagnosticArgsRoundTrip(CompilerInvocation &Res, + DiagnosticOptions &Opts, + ArgList &Args, + DiagnosticsEngine *Diags, + bool DefaultDiagColor) { + IntrusiveRefCntPtr DummyOpts(new DiagnosticOptions); + + return RoundTrip( + [DefaultDiagColor](CompilerInvocation &Res, ArgList &Args, + DiagnosticsEngine &Diags) { + // Query the options might not get queried properly during parsing, but + // should be generated from DiagnosticOptions. + + Args.getLastArg(OPT_fcolor_diagnostics); + Args.getLastArg(OPT_fno_color_diagnostics); + Args.getLastArg(OPT_fdiagnostics_color); + Args.getLastArg(OPT_fno_diagnostics_color); + Args.getLastArg(OPT_fdiagnostics_color_EQ); + + for (auto *A : Args.filtered(OPT_W_Group)) + Args.getLastArg(A->getOption().getID()); + for (auto *A : Args.filtered(OPT_R_Group)) + Args.getLastArg(A->getOption().getID()); + + return clang::ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags, + DefaultDiagColor); + }, + [DefaultDiagColor](CompilerInvocation &Res, + SmallVectorImpl &Args, + CompilerInvocation::StringAllocator SA) { + GenerateDiagnosticArgs(Res.getDiagnosticOpts(), Args, SA, + DefaultDiagColor); + }, + [&DummyOpts](CompilerInvocation &Res) { + Res.DiagnosticOpts.swap(DummyOpts); + }, + Res, Args, *Diags, "DiagnosticOptions"); +} + /// Parse the argument to the -ftest-module-file-extension /// command-line argument. /// @@ -4393,8 +4490,9 @@ Success &= Res.parseSimpleArgs(Args, Diags); Success &= ParseAnalyzerArgs(Res, *Res.getAnalyzerOpts(), Args, Diags); - Success &= ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags, - /*DefaultDiagColor=*/false); + Success &= + ParseDiagnosticArgsRoundTrip(Res, Res.getDiagnosticOpts(), Args, &Diags, + /*DefaultDiagColor=*/false); Success &= ParseFrontendArgs(Res, Res.getFrontendOpts(), Args, Diags, LangOpts.IsHeaderFile); // FIXME: We shouldn't have to pass the DashX option around here @@ -4613,17 +4711,13 @@ ALWAYS_EMIT, this->KEYPATH, DEFAULT_VALUE, \ IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, \ EXTRACTOR, TABLE_INDEX) - -#define DIAG_OPTION_WITH_MARSHALLING OPTION_WITH_MARSHALLING - #include "clang/Driver/Options.inc" - -#undef DIAG_OPTION_WITH_MARSHALLING #undef OPTION_WITH_MARSHALLING llvm::Triple T(TargetOpts->Triple); GenerateAnalyzerArgs(*AnalyzerOpts, Args, SA); + GenerateDiagnosticArgs(*DiagnosticOpts, Args, SA, false); GenerateFrontendArgs(FrontendOpts, Args, SA, LangOpts->IsHeaderFile); GenerateTargetArgs(*TargetOpts, Args, SA); GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);