sanwou01 created this revision. Herald added a subscriber: aemerson. Add initial support for printing assembly diagnostics using the DiagnosticsEngine infrastructure. Add support for -w (no warnings) and -Werror (warnings are errors) and print a summary with the number of errors and warnings. -fcolor-diagnostics handling is implemented as well.
I am looking for feedback on the overall approach and suggestions for a way to split it up into manageable pieces (if necessary). --- The approach is to teach DiagnosticsEngine and underlying classes to emit diagnostics using llvm::SMLocs. Converting from llvm::SMLoc to clang::SourceLocation (and the associated SourceManager and FileManager) is quite infeasible. With these changes in place, it will be relatively easy to convert inline assembly diagnostics to this infrastructure as well. Unfortunately, there is still quite a lot of code duplication which I hope to factor out (or leave as FIXMEs). The plan is to leave the emit*() functions as they are in this patch, but factor common bits into private methods. Some of the diagnostics options handling has already been factored out. Currently missing is support for ranges and hits, but the assembly diagnostics don't seem to generate many of those anyway. Some examples with test.s: .thumb ADD r0, r0, #0xFFFFF001 LDM r0, {r1, r0} $ clang --target=arm-none-eabi -march=armv8-m.main -c test.s test.s:2:12: error: invalid operand for instruction ADD r0,r0,#0xFFFFF001 ^ test.s:3:14: warning: register list not in ascending order LDM r0, {r1, r0} ^ 1 warning and 1 error generated. $ clang --target=arm-none-eabi -march=armv8-m.main -c test.s -Werror test.s:2:12: error: invalid operand for instruction ADD r0,r0,#0xFFFFF001 ^ test.s:3:14: error: register list not in ascending order LDM r0, {r1, r0} ^ 2 errors generated. $ clang --target=arm-none-eabi -march=armv8-m.main -c test.s -w test.s:2:12: error: invalid operand for instruction ADD r0,r0,#0xFFFFF001 ^ 1 error generated. https://reviews.llvm.org/D31501 Files: include/clang/Basic/Diagnostic.h include/clang/Driver/Options.h include/clang/Driver/Options.td include/clang/Frontend/CompilerInvocation.h include/clang/Frontend/DiagnosticRenderer.h include/clang/Frontend/TextDiagnostic.h lib/Driver/DriverOptions.cpp lib/Driver/ToolChains/Clang.cpp lib/Frontend/CompilerInvocation.cpp lib/Frontend/DiagnosticRenderer.cpp lib/Frontend/TextDiagnostic.cpp lib/Frontend/TextDiagnosticPrinter.cpp tools/driver/cc1as_main.cpp
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<DiagnosticsEngine *>(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<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple)); assert(MRI && "Unable to create target register info!"); @@ -472,7 +504,7 @@ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(errs(), &*DiagOpts); - DiagClient->setPrefix("clang -cc1as"); + // DiagClient->setPrefix("clang -cc1as"); IntrusiveRefCntPtr<DiagnosticIDs> 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()); 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: 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/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<CharSourceRange>(), 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/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<std::string> &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<std::string> &Funcs) { SmallVector<const char *, 8> Values; @@ -346,28 +327,6 @@ return Pattern; } -static bool parseDiagnosticLevelMask(StringRef FlagName, - const std::vector<std::string> &Levels, - DiagnosticsEngine *Diags, - DiagnosticLevelMask &M) { - bool Success = true; - for (const auto &Level : Levels) { - DiagnosticLevelMask const PM = - llvm::StringSwitch<DiagnosticLevelMask>(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<std::string> &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/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/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<OptTable> clang::driver::createDriverOptTable() { return llvm::make_unique<DriverOptTable>(); } + +namespace { +using namespace clang; + +static void addDiagnosticArgs(const ArgList &Args, OptSpecifier Group, + OptSpecifier GroupWithValue, + std::vector<std::string> &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<std::string> &Levels, + DiagnosticsEngine *Diags, + DiagnosticLevelMask &M) { + bool Success = true; + for (const auto &Level : Levels) { + DiagnosticLevelMask const PM = + llvm::StringSwitch<DiagnosticLevelMask>(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: include/clang/Frontend/TextDiagnostic.h =================================================================== --- include/clang/Frontend/TextDiagnostic.h +++ include/clang/Frontend/TextDiagnostic.h @@ -81,11 +81,16 @@ ArrayRef<CharSourceRange> 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<CharSourceRange> 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<CharSourceRange>& Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM); + void emitSnippetAndCaret(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM); void emitSnippet(StringRef SourceLine); 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<CharSourceRange> 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<CharSourceRange> 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<CharSourceRange>& Ranges, ArrayRef<FixItHint> 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<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM); + + void emitCaret(llvm::SMLoc Loc, DiagnosticsEngine::Level Level, + const llvm::SourceMgr *SM); void emitSingleMacroExpansion(SourceLocation Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, @@ -145,6 +166,9 @@ ArrayRef<FixItHint> 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/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/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -431,7 +431,7 @@ MetaVarName<"<arg>">, Group<Preprocessor_Group>; def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>; def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>; -def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CoreOption]>, +def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>, MetaVarName<"<warning>">, HelpText<"Enable the specified warning">; def Xanalyzer : Separate<["-"], "Xanalyzer">, HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">, @@ -683,7 +683,7 @@ def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>; def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>; def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_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<f_Group>, Flags<[CoreOption, DriverOption]>; def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_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 <language>">, MetaVarName<"<language>">; 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<llvm::opt::OptTable> 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/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 <algorithm> #include <cassert> #include <cstdint> @@ -36,6 +37,11 @@ #include <utility> #include <vector> +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.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits