diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h --- a/clang/include/clang/Basic/DiagnosticOptions.h +++ b/clang/include/clang/Basic/DiagnosticOptions.h @@ -109,6 +109,8 @@ /// The list of -W... options used to alter the diagnostic mappings, with the /// prefixes removed. std::vector Warnings; + /// The list of -W... options as they were written on the command line. + std::vector WarningsAsWritten; /// The list of prefixes from -Wundef-prefix=... used to generate warnings /// for undefined macros. @@ -117,6 +119,8 @@ /// The list of -R... options used to alter the diagnostic mappings, with the /// prefixes removed. std::vector Remarks; + /// The list of -R... options as they were written on the command line. + std::vector RemarksAsWritten; /// The prefixes for comment directives sought by -verify ("expected" by /// default). 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 @@ -4779,8 +4779,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 @@ -722,7 +722,10 @@ static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, OptSpecifier GroupWithValue, - std::vector &Diagnostics) { + std::vector &Diagnostics, + std::vector &DiagnosticsAsWritten) { + ArgStringList Rendered; + 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 @@ -738,7 +741,13 @@ for (const auto *Arg : A->getValues()) Diagnostics.emplace_back(Arg); } + + A->render(Args, Rendered); } + + DiagnosticsAsWritten.reserve(Rendered.size()); + for (const char *Arg : Rendered) + DiagnosticsAsWritten.emplace_back(Arg); } // Parse the Static Analyzer configuration. If \p Diags is set to nullptr, @@ -2169,6 +2178,68 @@ 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.CLFallbackMode) + GenerateArg(Args, OPT_fdiagnostics_format, "msvc-fallback", 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.WarningsAsWritten) { + // This option also maps to UndefPrefixes that generates it automatically. + if (StringRef(Warning).startswith("-Wundef-prefix=")) + continue; + // TODO: Consider ignoring '-Wno-rewrite-macros' that maps to + // NoRewriteMacros. + Args.push_back(SA(Warning)); + } + + for (const auto &Remark : Opts.RemarksAsWritten) + Args.push_back(SA(Remark)); +} + bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor) { @@ -2207,6 +2278,7 @@ Opts.CLFallbackMode = true; 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 @@ -2230,12 +2302,53 @@ << Opts.TabStop << DiagnosticOptions::DefaultTabStop; } - addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); - addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks); + addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings, + Opts.WarningsAsWritten); + + addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks, + Opts.RemarksAsWritten); 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 we might not have queried properly during parsing, + // but should be generated by us. + 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. /// @@ -4381,8 +4494,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 @@ -4601,17 +4715,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);