Index: include/clang/Basic/Diagnostic.h =================================================================== --- include/clang/Basic/Diagnostic.h +++ include/clang/Basic/Diagnostic.h @@ -22,9 +22,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/SMLoc.h" #include #include #include @@ -36,6 +37,11 @@ #include #include +namespace llvm { + +class SourceMgr; +} + namespace clang { class DeclContext; @@ -435,6 +441,12 @@ SourceMgr = SrcMgr; } + bool hasLLVMSourceManager() const { return CurDiagSM != nullptr; } + const llvm::SourceMgr *getLLVMSourceManager() const { + assert(CurDiagSM && "LLVMSourceManager not provided!"); + return CurDiagSM; + } + //===--------------------------------------------------------------------===// // DiagnosticsEngine characterization methods, used by a client to customize // how diagnostics are emitted. @@ -730,6 +742,8 @@ /// which can be an invalid location if no position information is available. inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID); inline DiagnosticBuilder Report(unsigned DiagID); + inline DiagnosticBuilder Report(const llvm::SourceMgr *SM, llvm::SMLoc Loc, + unsigned DiagID); void Report(const StoredDiagnostic &storedDiag); @@ -761,7 +775,11 @@ StringRef Arg2 = ""); /// \brief Clear out the current diagnostic. - void Clear() { CurDiagID = ~0U; } + void Clear() { + CurDiagID = ~0U; + CurDiagSMLoc = llvm::SMLoc(); + CurDiagSM = nullptr; + } /// \brief Return the value associated with this diagnostic flag. StringRef getFlagValue() const { return FlagValue; } @@ -790,6 +808,9 @@ /// This is set to ~0U when there is no diagnostic in flight. unsigned CurDiagID; + llvm::SMLoc CurDiagSMLoc = llvm::SMLoc(); + const llvm::SourceMgr *CurDiagSM = nullptr; + enum { /// \brief The maximum number of arguments we can hold. /// @@ -1177,6 +1198,8 @@ inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, unsigned DiagID) { assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); + CurDiagSMLoc = llvm::SMLoc(); + CurDiagSM = nullptr; CurDiagLoc = Loc; CurDiagID = DiagID; FlagValue.clear(); @@ -1187,6 +1210,15 @@ return Report(SourceLocation(), DiagID); } +inline DiagnosticBuilder DiagnosticsEngine::Report(const llvm::SourceMgr *SM, + llvm::SMLoc Loc, + unsigned DiagID) { + auto DB = Report(DiagID); + CurDiagSM = SM; + CurDiagSMLoc = Loc; + return DB; +} + //===----------------------------------------------------------------------===// // Diagnostic //===----------------------------------------------------------------------===// @@ -1209,6 +1241,12 @@ bool hasSourceManager() const { return DiagObj->hasSourceManager(); } SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} + llvm::SMLoc getLLVMLocation() const { return DiagObj->CurDiagSMLoc; } + bool hasLLVMSourceManager() const { return DiagObj->hasLLVMSourceManager(); } + const llvm::SourceMgr *getLLVMSourceManager() const { + return DiagObj->getLLVMSourceManager(); + } + unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } /// \brief Return the kind of the specified index. Index: include/clang/Driver/Options.h =================================================================== --- include/clang/Driver/Options.h +++ include/clang/Driver/Options.h @@ -15,10 +15,13 @@ namespace llvm { namespace opt { class OptTable; +class ArgList; } } namespace clang { +class DiagnosticOptions; +class DiagnosticsEngine; namespace driver { namespace options { @@ -49,6 +52,19 @@ std::unique_ptr createDriverOptTable(); } + +/// \brief Fill out Opts based on the options given in Args. +/// +/// Args must have been created from the OptTable returned by +/// createCC1OptTable(). +/// +/// When errors are encountered, return false and, if Diags is non-null, +/// report the error(s). +bool ParseDiagnosticArgs(DiagnosticOptions &Opts, + const llvm::opt::ArgList &Args, + DiagnosticsEngine *Diags = nullptr, + bool DefaultDiagColor = true, + bool DefaultShowOpt = true); } #endif Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -431,7 +431,7 @@ MetaVarName<"">, Group; def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group, Flags<[CC1Option, HelpHidden]>; def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group, Flags<[CC1Option, HelpHidden]>; -def W_Joined : Joined<["-"], "W">, Group, Flags<[CC1Option, CoreOption]>, +def W_Joined : Joined<["-"], "W">, Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, MetaVarName<"">, HelpText<"Enable the specified warning">; def Xanalyzer : Separate<["-"], "Xanalyzer">, HelpText<"Pass to the static analyzer">, MetaVarName<"">, @@ -683,7 +683,7 @@ def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group; def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group; def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group, - Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">; + Flags<[CoreOption, CC1Option, CC1AsOption]>, HelpText<"Use colors in diagnostics">; def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group, Flags<[CoreOption, DriverOption]>; def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group; @@ -2203,7 +2203,7 @@ def weak__reference__mismatches : Separate<["-"], "weak_reference_mismatches">; def whatsloaded : Flag<["-"], "whatsloaded">; def whyload : Flag<["-"], "whyload">; -def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option]>; +def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option,CC1AsOption]>; def x : JoinedOrSeparate<["-"], "x">, Flags<[DriverOption,CC1Option]>, HelpText<"Treat subsequent input files as having type ">, MetaVarName<"">; Index: include/clang/Frontend/CompilerInvocation.h =================================================================== --- include/clang/Frontend/CompilerInvocation.h +++ include/clang/Frontend/CompilerInvocation.h @@ -39,18 +39,6 @@ class CompilerInvocation; class DiagnosticsEngine; -/// \brief Fill out Opts based on the options given in Args. -/// -/// Args must have been created from the OptTable returned by -/// createCC1OptTable(). -/// -/// When errors are encountered, return false and, if Diags is non-null, -/// report the error(s). -bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, - DiagnosticsEngine *Diags = nullptr, - bool DefaultDiagColor = true, - bool DefaultShowOpt = true); - class CompilerInvocationBase { void operator=(const CompilerInvocationBase &) = delete; Index: include/clang/Frontend/DiagnosticRenderer.h =================================================================== --- include/clang/Frontend/DiagnosticRenderer.h +++ include/clang/Frontend/DiagnosticRenderer.h @@ -53,7 +53,14 @@ /// diagnostic location, or that location itself is invalid or comes from /// a different source manager than SM. SourceLocation LastLoc; - + + /// \brief The location of the previous llvm diagnostic if known. + /// + /// This will be invalid in cases where there is no (known) previous + /// diagnostic location, or that location itself is invalid or comes from + /// a different source manager than LLVM SM. + llvm::SMLoc LastSMLoc; + /// \brief The location of the last include whose stack was printed if known. /// /// Same restriction as LastLoc essentially, but tracking include stack @@ -77,18 +84,29 @@ ArrayRef Ranges, const SourceManager *SM, DiagOrStoredDiag Info) = 0; - + virtual void emitDiagnosticMessage(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + StringRef Message, + const llvm::SourceMgr *SM, + DiagOrStoredDiag Info) {} + virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef Ranges, const SourceManager &SM) = 0; + virtual void emitDiagnosticLoc(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM){}; + virtual void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl& Ranges, ArrayRef Hints, const SourceManager &SM) = 0; - + virtual void emitCodeContext(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM){}; + virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) = 0; virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, @@ -116,6 +134,9 @@ void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, ArrayRef Ranges, ArrayRef Hints, const SourceManager &SM); + + void emitCaret(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM); void emitSingleMacroExpansion(SourceLocation Loc, DiagnosticsEngine::Level Level, ArrayRef Ranges, @@ -145,6 +166,9 @@ ArrayRef FixItHints, const SourceManager *SM, DiagOrStoredDiag D = (Diagnostic *)nullptr); + void emitDiagnostic(llvm::SMLoc, DiagnosticsEngine::Level Level, + StringRef Message, const llvm::SourceMgr *SM, + DiagOrStoredDiag D = (Diagnostic *)nullptr); void emitStoredDiagnostic(StoredDiagnostic &Diag); }; Index: include/clang/Frontend/TextDiagnostic.h =================================================================== --- include/clang/Frontend/TextDiagnostic.h +++ include/clang/Frontend/TextDiagnostic.h @@ -81,11 +81,16 @@ ArrayRef Ranges, const SourceManager *SM, DiagOrStoredDiag D) override; + void emitDiagnosticMessage(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + StringRef Message, const llvm::SourceMgr *SM, + DiagOrStoredDiag Info) override; void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef Ranges, const SourceManager &SM) override; + void emitDiagnosticLoc(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM) override; void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, @@ -95,6 +100,11 @@ emitSnippetAndCaret(Loc, Level, Ranges, Hints, SM); } + void emitCodeContext(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM) override { + emitSnippetAndCaret(Loc, Level, SM); + } + void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) override; @@ -108,11 +118,13 @@ private: void emitFilename(StringRef Filename, const SourceManager &SM); - + void emitFilename(StringRef Filename, const llvm::SourceMgr *SM); void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl& Ranges, ArrayRef Hints, const SourceManager &SM); + void emitSnippetAndCaret(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM); void emitSnippet(StringRef SourceLine); Index: lib/Driver/DriverOptions.cpp =================================================================== --- lib/Driver/DriverOptions.cpp +++ lib/Driver/DriverOptions.cpp @@ -7,10 +7,17 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Frontend/Utils.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" +#include "llvm/Support/Process.h" using namespace clang::driver; using namespace clang::driver::options; @@ -42,3 +49,207 @@ std::unique_ptr clang::driver::createDriverOptTable() { return llvm::make_unique(); } + +namespace { +using namespace clang; + +static void addDiagnosticArgs(const ArgList &Args, OptSpecifier Group, + OptSpecifier GroupWithValue, + std::vector &Diagnostics) { + for (Arg *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. + Diagnostics.push_back(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. + Diagnostics.push_back(A->getOption().getName().drop_front(1).rtrim("=-")); + } else { + // Otherwise, add its value (for OPT_W_Joined and similar). + for (const char *Arg : A->getValues()) + Diagnostics.emplace_back(Arg); + } + } +} + +static bool parseDiagnosticLevelMask(StringRef FlagName, + const std::vector &Levels, + DiagnosticsEngine *Diags, + DiagnosticLevelMask &M) { + bool Success = true; + for (const auto &Level : Levels) { + DiagnosticLevelMask const PM = + llvm::StringSwitch(Level) + .Case("note", DiagnosticLevelMask::Note) + .Case("remark", DiagnosticLevelMask::Remark) + .Case("warning", DiagnosticLevelMask::Warning) + .Case("error", DiagnosticLevelMask::Error) + .Default(DiagnosticLevelMask::None); + if (PM == DiagnosticLevelMask::None) { + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) << FlagName << Level; + } + M = M | PM; + } + return Success; +} + +static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { + // Color diagnostics default to auto ("on" if terminal supports) in the driver + // but default to off in cc1, needing an explicit OPT_fdiagnostics_color. + // Support both clang's -f[no-]color-diagnostics and gcc's + // -f[no-]diagnostics-colors[=never|always|auto]. + enum { + Colors_On, + Colors_Off, + Colors_Auto + } ShowColors = DefaultColor ? Colors_Auto : Colors_Off; + for (Arg *A : Args) { + const Option &O = A->getOption(); + if (O.matches(options::OPT_fcolor_diagnostics) || + O.matches(options::OPT_fdiagnostics_color)) { + ShowColors = Colors_On; + } else if (O.matches(options::OPT_fno_color_diagnostics) || + O.matches(options::OPT_fno_diagnostics_color)) { + ShowColors = Colors_Off; + } else if (O.matches(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value == "always") + ShowColors = Colors_On; + else if (Value == "never") + ShowColors = Colors_Off; + else if (Value == "auto") + ShowColors = Colors_Auto; + } + } + return ShowColors == Colors_On || + (ShowColors == Colors_Auto && + llvm::sys::Process::StandardErrHasColors()); +} +} + +bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, + const llvm::opt::ArgList &Args, + DiagnosticsEngine *Diags, bool DefaultDiagColor, + bool DefaultShowOpt) { + using namespace options; + bool Success = true; + + Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); + if (Arg *A = + Args.getLastArg(OPT_diagnostic_serialized_file, OPT__serialize_diags)) + Opts.DiagnosticSerializationFile = A->getValue(); + Opts.IgnoreWarnings = Args.hasArg(OPT_w); + Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); + Opts.Pedantic = Args.hasArg(OPT_pedantic); + Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); + Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); + Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor); + Opts.ShowColumn = Args.hasFlag(OPT_fshow_column, OPT_fno_show_column, + /*Default=*/true); + Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); + Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); + Opts.AbsolutePath = Args.hasArg(OPT_fdiagnostics_absolute_paths); + Opts.ShowOptionNames = + Args.hasFlag(OPT_fdiagnostics_show_option, + OPT_fno_diagnostics_show_option, DefaultShowOpt); + + llvm::sys::Process::UseANSIEscapeCodes(Args.hasArg(OPT_fansi_escape_codes)); + + // Default behavior is to not to show note include stacks. + Opts.ShowNoteIncludeStack = false; + if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack, + OPT_fno_diagnostics_show_note_include_stack)) + if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) + Opts.ShowNoteIncludeStack = true; + + StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); + if (ShowOverloads == "best") + Opts.setShowOverloads(Ovl_Best); + else if (ShowOverloads == "all") + Opts.setShowOverloads(Ovl_All); + else { + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) + << ShowOverloads; + } + + StringRef ShowCategory = + Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); + if (ShowCategory == "none") + Opts.ShowCategories = 0; + else if (ShowCategory == "id") + Opts.ShowCategories = 1; + else if (ShowCategory == "name") + Opts.ShowCategories = 2; + else { + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) + << ShowCategory; + } + + StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); + if (Format == "clang") + Opts.setFormat(DiagnosticOptions::Clang); + else if (Format == "msvc") + Opts.setFormat(DiagnosticOptions::MSVC); + else if (Format == "msvc-fallback") { + Opts.setFormat(DiagnosticOptions::MSVC); + Opts.CLFallbackMode = true; + } else if (Format == "vi") + Opts.setFormat(DiagnosticOptions::Vi); + else { + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args) + << Format; + } + + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); + Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); + Opts.ShowPresumedLoc = + !Args.hasArg(OPT_fno_diagnostics_use_presumed_location); + Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None; + Success &= parseDiagnosticLevelMask( + "-verify-ignore-unexpected=", + Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), Diags, DiagMask); + if (Args.hasArg(OPT_verify_ignore_unexpected)) + DiagMask = DiagnosticLevelMask::All; + Opts.setVerifyIgnoreUnexpected(DiagMask); + Opts.ElideType = !Args.hasArg(OPT_fno_elide_type); + Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree); + Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags); + Opts.MacroBacktraceLimit = + getLastArgIntValue(Args, OPT_fmacro_backtrace_limit, + DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); + Opts.TemplateBacktraceLimit = getLastArgIntValue( + Args, OPT_ftemplate_backtrace_limit, + DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); + Opts.ConstexprBacktraceLimit = getLastArgIntValue( + Args, OPT_fconstexpr_backtrace_limit, + DiagnosticOptions::DefaultConstexprBacktraceLimit, Diags); + Opts.SpellCheckingLimit = + getLastArgIntValue(Args, OPT_fspell_checking_limit, + DiagnosticOptions::DefaultSpellCheckingLimit, Diags); + Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, + DiagnosticOptions::DefaultTabStop, Diags); + if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { + Opts.TabStop = DiagnosticOptions::DefaultTabStop; + if (Diags) + Diags->Report(diag::warn_ignoring_ftabstop_value) + << Opts.TabStop << DiagnosticOptions::DefaultTabStop; + } + Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); + addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); + addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks); + + return Success; +} Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -28,6 +28,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/XRayArgs.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" @@ -4857,9 +4858,7 @@ const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const std::string &TripleStr = Triple.getTriple(); - // Don't warn about "clang -w -c foo.s" - Args.ClaimAllArgs(options::OPT_w); - // and "clang -emit-llvm -c foo.s" + // Don't warn about "clang -emit-llvm -c foo.s" Args.ClaimAllArgs(options::OPT_emit_llvm); claimNoWarnArgs(Args); @@ -4998,12 +4997,35 @@ break; } - // Consume all the warning flags. Usually this would be handled more - // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as - // doesn't handle that so rather than warning about unused flags that are - // actually used, we'll lie by omission instead. - // FIXME: Stop lying and consume only the appropriate driver flags - Args.ClaimAllArgs(options::OPT_W_Group); + // Pass all warning flags to -cc1as. + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) + CmdArgs.push_back("-pedantic"); + Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); + Args.AddLastArg(CmdArgs, options::OPT_w); + + // Color diagnostics are parsed by the driver directly from argv + // and later re-parsed to construct this job; claim any possible + // color diagnostic here to avoid warn_drv_unused_argument and + // diagnose bad OPT_fdiagnostics_color_EQ values. + for (Arg *A : Args) { + const Option &O = A->getOption(); + if (!O.matches(options::OPT_fcolor_diagnostics) && + !O.matches(options::OPT_fdiagnostics_color) && + !O.matches(options::OPT_fno_color_diagnostics) && + !O.matches(options::OPT_fno_diagnostics_color) && + !O.matches(options::OPT_fdiagnostics_color_EQ)) + continue; + if (O.matches(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << ("-fdiagnostics-color=" + Value).str(); + } + A->claim(); + } + if (getToolChain().getDriver().getDiags().getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); CollectArgsForIntegratedAssembler(C, Args, CmdArgs, getToolChain().getDriver()); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -122,25 +122,6 @@ return 0; } -static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, - OptSpecifier GroupWithValue, - std::vector &Diagnostics) { - for (Arg *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. - Diagnostics.push_back(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. - Diagnostics.push_back(A->getOption().getName().drop_front(1).rtrim("=-")); - } else { - // Otherwise, add its value (for OPT_W_Joined and similar). - for (const char *Arg : A->getValues()) - Diagnostics.emplace_back(Arg); - } - } -} - static void getAllNoBuiltinFuncValues(ArgList &Args, std::vector &Funcs) { SmallVector Values; @@ -346,28 +327,6 @@ return Pattern; } -static bool parseDiagnosticLevelMask(StringRef FlagName, - const std::vector &Levels, - DiagnosticsEngine *Diags, - DiagnosticLevelMask &M) { - bool Success = true; - for (const auto &Level : Levels) { - DiagnosticLevelMask const PM = - llvm::StringSwitch(Level) - .Case("note", DiagnosticLevelMask::Note) - .Case("remark", DiagnosticLevelMask::Remark) - .Case("warning", DiagnosticLevelMask::Warning) - .Case("error", DiagnosticLevelMask::Error) - .Default(DiagnosticLevelMask::None); - if (PM == DiagnosticLevelMask::None) { - Success = false; - if (Diags) - Diags->Report(diag::err_drv_invalid_value) << FlagName << Level; - } - M = M | PM; - } - return Success; -} static void parseSanitizerKinds(StringRef FlagName, const std::vector &Sanitizers, @@ -928,163 +887,6 @@ ModuleFiles.end()); } -static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { - // Color diagnostics default to auto ("on" if terminal supports) in the driver - // but default to off in cc1, needing an explicit OPT_fdiagnostics_color. - // Support both clang's -f[no-]color-diagnostics and gcc's - // -f[no-]diagnostics-colors[=never|always|auto]. - enum { - Colors_On, - Colors_Off, - Colors_Auto - } ShowColors = DefaultColor ? Colors_Auto : Colors_Off; - for (Arg *A : Args) { - const Option &O = A->getOption(); - if (O.matches(options::OPT_fcolor_diagnostics) || - O.matches(options::OPT_fdiagnostics_color)) { - ShowColors = Colors_On; - } else if (O.matches(options::OPT_fno_color_diagnostics) || - O.matches(options::OPT_fno_diagnostics_color)) { - ShowColors = Colors_Off; - } else if (O.matches(options::OPT_fdiagnostics_color_EQ)) { - StringRef Value(A->getValue()); - if (Value == "always") - ShowColors = Colors_On; - else if (Value == "never") - ShowColors = Colors_Off; - else if (Value == "auto") - ShowColors = Colors_Auto; - } - } - return ShowColors == Colors_On || - (ShowColors == Colors_Auto && - llvm::sys::Process::StandardErrHasColors()); -} - -bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, - DiagnosticsEngine *Diags, - bool DefaultDiagColor, bool DefaultShowOpt) { - using namespace options; - bool Success = true; - - Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); - if (Arg *A = - Args.getLastArg(OPT_diagnostic_serialized_file, OPT__serialize_diags)) - Opts.DiagnosticSerializationFile = A->getValue(); - Opts.IgnoreWarnings = Args.hasArg(OPT_w); - Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); - Opts.Pedantic = Args.hasArg(OPT_pedantic); - Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); - Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); - Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor); - Opts.ShowColumn = Args.hasFlag(OPT_fshow_column, - OPT_fno_show_column, - /*Default=*/true); - Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); - Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); - Opts.AbsolutePath = Args.hasArg(OPT_fdiagnostics_absolute_paths); - Opts.ShowOptionNames = - Args.hasFlag(OPT_fdiagnostics_show_option, - OPT_fno_diagnostics_show_option, DefaultShowOpt); - - llvm::sys::Process::UseANSIEscapeCodes(Args.hasArg(OPT_fansi_escape_codes)); - - // Default behavior is to not to show note include stacks. - Opts.ShowNoteIncludeStack = false; - if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack, - OPT_fno_diagnostics_show_note_include_stack)) - if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) - Opts.ShowNoteIncludeStack = true; - - StringRef ShowOverloads = - Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); - if (ShowOverloads == "best") - Opts.setShowOverloads(Ovl_Best); - else if (ShowOverloads == "all") - Opts.setShowOverloads(Ovl_All); - else { - Success = false; - if (Diags) - Diags->Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) - << ShowOverloads; - } - - StringRef ShowCategory = - Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); - if (ShowCategory == "none") - Opts.ShowCategories = 0; - else if (ShowCategory == "id") - Opts.ShowCategories = 1; - else if (ShowCategory == "name") - Opts.ShowCategories = 2; - else { - Success = false; - if (Diags) - Diags->Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) - << ShowCategory; - } - - StringRef Format = - Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); - if (Format == "clang") - Opts.setFormat(DiagnosticOptions::Clang); - else if (Format == "msvc") - Opts.setFormat(DiagnosticOptions::MSVC); - else if (Format == "msvc-fallback") { - Opts.setFormat(DiagnosticOptions::MSVC); - Opts.CLFallbackMode = true; - } else if (Format == "vi") - Opts.setFormat(DiagnosticOptions::Vi); - else { - Success = false; - if (Diags) - Diags->Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args) - << Format; - } - - Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); - Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); - Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location); - Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); - DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None; - Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=", - Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), - Diags, DiagMask); - if (Args.hasArg(OPT_verify_ignore_unexpected)) - DiagMask = DiagnosticLevelMask::All; - Opts.setVerifyIgnoreUnexpected(DiagMask); - Opts.ElideType = !Args.hasArg(OPT_fno_elide_type); - Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree); - Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags); - Opts.MacroBacktraceLimit = - getLastArgIntValue(Args, OPT_fmacro_backtrace_limit, - DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); - Opts.TemplateBacktraceLimit = getLastArgIntValue( - Args, OPT_ftemplate_backtrace_limit, - DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); - Opts.ConstexprBacktraceLimit = getLastArgIntValue( - Args, OPT_fconstexpr_backtrace_limit, - DiagnosticOptions::DefaultConstexprBacktraceLimit, Diags); - Opts.SpellCheckingLimit = getLastArgIntValue( - Args, OPT_fspell_checking_limit, - DiagnosticOptions::DefaultSpellCheckingLimit, Diags); - Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, - DiagnosticOptions::DefaultTabStop, Diags); - if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { - Opts.TabStop = DiagnosticOptions::DefaultTabStop; - if (Diags) - Diags->Report(diag::warn_ignoring_ftabstop_value) - << Opts.TabStop << DiagnosticOptions::DefaultTabStop; - } - Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); - addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); - addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks); - - return Success; -} static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory); Index: lib/Frontend/DiagnosticRenderer.cpp =================================================================== --- lib/Frontend/DiagnosticRenderer.cpp +++ lib/Frontend/DiagnosticRenderer.cpp @@ -135,6 +135,28 @@ endDiagnostic(D, Level); } +void DiagnosticRenderer::emitDiagnostic(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + StringRef Message, + const llvm::SourceMgr *SM, + DiagOrStoredDiag D) { + assert(SM || !Loc.isValid()); + + beginDiagnostic(D, Level); + + if (!Loc.isValid()) { + emitDiagnosticMessage(SourceLocation(), PresumedLoc(), Level, Message, + ArrayRef(), nullptr, D); + } else { + emitDiagnosticMessage(Loc, Level, Message, SM, D); + emitCaret(Loc, Level, SM); + } + + LastSMLoc = Loc; + LastLevel = Level; + + endDiagnostic(D, Level); +} void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), @@ -414,6 +436,12 @@ emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); } +void DiagnosticRenderer::emitCaret(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM) { + emitCodeContext(Loc, Level, SM); +} + /// \brief A helper function for emitMacroExpansion to print the /// macro expansion message void DiagnosticRenderer::emitSingleMacroExpansion( Index: lib/Frontend/TextDiagnostic.cpp =================================================================== --- lib/Frontend/TextDiagnostic.cpp +++ lib/Frontend/TextDiagnostic.cpp @@ -697,6 +697,28 @@ DiagOpts->MessageLength, DiagOpts->ShowColors); } +void TextDiagnostic::emitDiagnosticMessage(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + StringRef Message, + const llvm::SourceMgr *SM, + DiagOrStoredDiag D) { + uint64_t StartOfLocationInfo = OS.tell(); + + // Emit the location of this particular diagnostic. + if (Loc.isValid()) + emitDiagnosticLoc(Loc, Level, SM); + + if (DiagOpts->ShowColors) + OS.resetColor(); + + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors, + DiagOpts->CLFallbackMode); + printDiagnosticMessage(OS, + /*IsSupplemental*/ Level == DiagnosticsEngine::Note, + Message, OS.tell() - StartOfLocationInfo, + DiagOpts->MessageLength, DiagOpts->ShowColors); +} + /*static*/ void TextDiagnostic::printDiagnosticLevel(raw_ostream &OS, DiagnosticsEngine::Level Level, @@ -781,6 +803,74 @@ OS << Filename; } +void TextDiagnostic::emitFilename(StringRef Filename, const llvm::SourceMgr *) { + // FIXME: Use the llvm::SourceMgr to support DiagOpts->AbsolutePath. + + OS << Filename; +} + +void TextDiagnostic::emitDiagnosticLoc(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM) { + unsigned LineNo, ColNo; + std::tie(LineNo, ColNo) = SM->getLineAndColumn(Loc); + + if (!DiagOpts->ShowLocation) + return; + + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); + + unsigned CurBuf = SM->FindBufferContainingLoc(Loc); + assert(CurBuf && "Invalid or unspecified location!"); + + const llvm::MemoryBuffer *CurMB = SM->getMemoryBuffer(CurBuf); + emitFilename(CurMB->getBufferIdentifier(), SM); + + switch (DiagOpts->getFormat()) { + case DiagnosticOptions::Clang: + OS << ':' << LineNo; + break; + case DiagnosticOptions::MSVC: + OS << '(' << LineNo; + break; + case DiagnosticOptions::Vi: + OS << " +" << LineNo; + break; + } + + if (DiagOpts->ShowColumn) + // Compute the column number. + if (ColNo) { + if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) { + OS << ','; + // Visual Studio 2010 or earlier expects column number to be off by one + if (LangOpts.MSCompatibilityVersion && + !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012)) + ColNo--; + } else + OS << ':'; + OS << ColNo; + } + switch (DiagOpts->getFormat()) { + case DiagnosticOptions::Clang: + case DiagnosticOptions::Vi: + OS << ':'; + break; + case DiagnosticOptions::MSVC: + // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the + // space and prints 'file(4): error'. + OS << ')'; + if (LangOpts.MSCompatibilityVersion && + !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + OS << ' '; + OS << ": "; + break; + } + + OS << ' '; +} + /// \brief Print out the file/line/column information and include trace. /// /// This method handlen the emission of the diagnostic location information. @@ -1073,6 +1163,96 @@ return FixItInsertionLine; } +void TextDiagnostic::emitSnippetAndCaret(llvm::SMLoc Loc, + DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM) { + assert(Loc.isValid() && "must have a valid source location here"); + + // If caret diagnostics are enabled and we have location, we want to + // emit the caret. However, we only do this if the location moved + // from the last diagnostic, if the last diagnostic was a note that + // was part of a different warning or error diagnostic, or if the + // diagnostic has ranges. We don't want to emit the same caret + // multiple times if one loc has multiple diagnostics. + if (!DiagOpts->ShowCarets) + return; + if (Loc == LastSMLoc /*&& Ranges.empty() && Hints.empty()*/ && + (LastLevel != DiagnosticsEngine::Note || Level == LastLevel)) + return; + + unsigned BufID = SM->FindBufferContainingLoc(Loc); + const llvm::MemoryBuffer *Buf = SM->getMemoryBuffer(BufID); + + if (!Buf) + return; + + const char *BufEnd = Buf->getBufferEnd(); + + unsigned LineNo, ColNo; + std::tie(LineNo, ColNo) = SM->getLineAndColumn(Loc); + + // Arbitrarily stop showing snippets when the line is too long. + static const size_t MaxLineLengthToPrint = 4096; + if (ColNo > MaxLineLengthToPrint) + return; + + // Rewind from the current position to the start of the line. + const char *TokPtr = Loc.getPointer(); + const char *LineStart = TokPtr - ColNo + 1; // Column # is 1-based. + + // Compute the line end. Scan forward from the error position to the end of + // the line. + const char *LineEnd = TokPtr; + while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) + ++LineEnd; + + // Arbitrarily stop showing snippets when the line is too long. + if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) + return; + + // Trim trailing null-bytes. + StringRef Line(LineStart, LineEnd - LineStart); + while (Line.size() > ColNo && Line.back() == '\0') + Line = Line.drop_back(); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(Line.begin(), Line.end()); + + // Build the byte to column map. + const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + + // Create a line for the caret that is filled with spaces that is the same + // number of columns as the line of source code. + std::string CaretLine(sourceColMap.columns(), ' '); + + ColNo = sourceColMap.byteToContainingColumn(ColNo - 1); + if (CaretLine.size() < ColNo + 1) + CaretLine.resize(ColNo + 1, ' '); + CaretLine[ColNo] = '^'; + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying + // to produce easily machine parsable output. Add a space before the + // source line and the caret to make it trivial to tell the main diagnostic + // line from what the user is intended to see. + if (DiagOpts->ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } + + // Finally, remove any blank spaces from the end of CaretLine. + while (CaretLine[CaretLine.size() - 1] == ' ') + CaretLine.erase(CaretLine.end() - 1); + + // Emit what we have computed. + emitSnippet(SourceLine); + + if (DiagOpts->ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); +} + /// \brief Emit a code snippet and caret line. /// /// This routine emits a single line's code snippet and caret line.. Index: lib/Frontend/TextDiagnosticPrinter.cpp =================================================================== --- lib/Frontend/TextDiagnosticPrinter.cpp +++ lib/Frontend/TextDiagnosticPrinter.cpp @@ -133,7 +133,7 @@ // This is important as if the location is missing, we may be emitting // diagnostics in a context that lacks language options, a source manager, or // other infrastructure necessary when emitting more rich diagnostics. - if (!Info.getLocation().isValid()) { + if (!Info.getLocation().isValid() && !Info.getLLVMLocation().isValid()) { TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors, DiagOpts->CLFallbackMode); TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(), @@ -146,14 +146,24 @@ // Assert that the rest of our infrastructure is setup properly. assert(DiagOpts && "Unexpected diagnostic without options set"); - assert(Info.hasSourceManager() && - "Unexpected diagnostic with no source manager"); assert(TextDiag && "Unexpected diagnostic outside source file processing"); - TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), - Info.getRanges(), - Info.getFixItHints(), - &Info.getSourceManager()); + if (Info.getLocation().isValid()) { + assert(Info.hasSourceManager() && + "Unexpected diagnostic with no source manager"); + + TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), + Info.getRanges(), Info.getFixItHints(), + &Info.getSourceManager()); + OS.flush(); + return; + } + + assert(Info.hasLLVMSourceManager() && + "Unexpected diagnostic with no source manager"); + TextDiag->emitDiagnostic(Info.getLLVMLocation(), Level, + DiagMessageStream.str(), + Info.getLLVMSourceManager()); OS.flush(); } Index: tools/driver/cc1as_main.cpp =================================================================== --- tools/driver/cc1as_main.cpp +++ tools/driver/cc1as_main.cpp @@ -14,6 +14,10 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -45,6 +49,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -209,6 +214,8 @@ Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); + ParseDiagnosticArgs(Diags.getDiagnosticOptions(), Args, &Diags, false, false); + // Frontend Options if (Args.hasArg(OPT_INPUT)) { bool First = true; @@ -281,6 +288,29 @@ return Out; } +struct DiagsHandlerContext { + DiagnosticsEngine &Diags; + const SourceMgr *SrcMgr; +}; + +static void AssemblerDiagsHandler(const SMDiagnostic &D, void *Context) { + auto &Diags = *static_cast(Context); + unsigned DiagID; + switch (D.getKind()) { + case llvm::SourceMgr::DK_Error: + DiagID = diag::err_fe_inline_asm; + break; + case llvm::SourceMgr::DK_Warning: + DiagID = diag::warn_fe_inline_asm; + break; + case llvm::SourceMgr::DK_Note: + DiagID = diag::note_fe_inline_asm; + break; + } + + Diags.Report(D.getSourceMgr(), D.getLoc(), DiagID) << D.getMessage(); +} + static bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) { // Get the target specific parser. @@ -306,6 +336,8 @@ // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); + SrcMgr.setDiagHandler(AssemblerDiagsHandler, &Diags); + std::unique_ptr MRI(TheTarget->createMCRegInfo(Opts.Triple)); assert(MRI && "Unable to create target register info!"); @@ -472,7 +504,7 @@ IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(errs(), &*DiagOpts); - DiagClient->setPrefix("clang -cc1as"); + // DiagClient->setPrefix("clang -cc1as"); IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); @@ -514,9 +546,35 @@ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args); } + ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), true); + + LangOptions LangOpts; + DiagClient->BeginSourceFile(LangOpts, nullptr); + // Execute the invocation, unless there were parsing errors. bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags); + DiagClient->EndSourceFile(); + + // Notify the diagnostic client that all files were processed. + Diags.getClient()->finish(); + + if (Diags.getDiagnosticOptions().ShowCarets) { + // We can have multiple diagnostics sharing one diagnostic client. + // Get the total number of warnings/errors from the client. + unsigned NumWarnings = Diags.getClient()->getNumWarnings(); + unsigned NumErrors = Diags.getClient()->getNumErrors(); + + if (NumWarnings) + errs() << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); + if (NumWarnings && NumErrors) + errs() << " and "; + if (NumErrors) + errs() << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); + if (NumWarnings || NumErrors) + errs() << " generated.\n"; + } + // If any timers were active but haven't been destroyed yet, print their // results now. TimerGroup::printAll(errs());