https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/202441
>From d05babe55a51c9d93be79e501fbb386e84e925c4 Mon Sep 17 00:00:00 2001 From: Joseph Huber <[email protected]> Date: Tue, 23 Jun 2026 13:54:08 -0500 Subject: [PATCH] [Clang] Refactor and consolidate color diagnostic handling Summary: This PR tries to consolidate the color output handling in Clang. The motivation was noticing that `-Xclang -ast-dump` would not behave like `-fcolor-diagnostics` and would output ANSI codes to a file when I tried to pipe it. This PR primarily turns the handling into a tri-state enum keyed off of `-f[no]-color-diagnostics`. The default/auto case will be if the target stream supports colors. Getting this to work required a lot of seemingly unrelated plumbing. Co-authored-by: Cursor <[email protected]> --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 9 +++-- clang-tools-extra/clangd/Compiler.cpp | 2 +- .../include/clang/Basic/DiagnosticOptions.def | 2 +- clang/include/clang/Basic/DiagnosticOptions.h | 23 +++++++++++ clang/include/clang/Options/Options.td | 2 +- clang/lib/AST/ASTDumper.cpp | 28 +++++++------ clang/lib/Basic/Warnings.cpp | 6 ++- clang/lib/Driver/ToolChains/CommonArgs.cpp | 10 ++++- clang/lib/Frontend/CompilerInvocation.cpp | 39 ++++++++++--------- clang/lib/Frontend/FrontendActions.cpp | 3 +- clang/lib/Frontend/TextDiagnostic.cpp | 23 +++++------ clang/lib/Frontend/TextDiagnosticPrinter.cpp | 5 ++- .../Misc/diagnostic-color-output-stream.cpp | 25 ++++++++++++ clang/unittests/Tooling/ToolingTest.cpp | 8 ++-- flang/lib/Frontend/CompilerInvocation.cpp | 9 +++-- flang/lib/Frontend/TextDiagnosticPrinter.cpp | 8 ++-- flang/test/Driver/color-diagnostics.f90 | 3 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 13 +++++-- 18 files changed, 151 insertions(+), 67 deletions(-) create mode 100644 clang/test/Misc/diagnostic-color-output-stream.cpp diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 05c8fd02fe86a..24cbd0940226d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -105,10 +105,13 @@ class ErrorReporter { DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)), Diags(DiagnosticIDs::create(), DiagOpts, DiagPrinter), SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) { - DiagOpts.ShowColors = Context.getOptions().UseColor.value_or( - llvm::sys::Process::StandardOutHasColors()); + DiagOpts.setShowColors(Context.getOptions().UseColor.value_or( + llvm::sys::Process::StandardOutHasColors()) + ? ShowColorsKind::On + : ShowColorsKind::Off); DiagPrinter->BeginSourceFile(LangOpts); - if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) + if (DiagOpts.showColors(llvm::sys::Process::StandardOutHasColors()) && + !llvm::sys::Process::StandardOutIsDisplayed()) llvm::sys::Process::UseANSIEscapeCodes(true); } diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 9ea7df139382a..4644cd75c0833 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -49,7 +49,7 @@ void disableUnsupportedOptions(CompilerInvocation &CI) { // our compiler invocation set-up doesn't seem to work with it (leading // assertions in VerifyDiagnosticConsumer). CI.getDiagnosticOpts().VerifyDiagnostics = false; - CI.getDiagnosticOpts().ShowColors = false; + CI.getDiagnosticOpts().setShowColors(ShowColorsKind::Off); // Disable any dependency outputting, we don't want to generate files or write // to stdout/stderr. diff --git a/clang/include/clang/Basic/DiagnosticOptions.def b/clang/include/clang/Basic/DiagnosticOptions.def index 17d518c2b7fdd..764e2f1fedbdd 100644 --- a/clang/include/clang/Basic/DiagnosticOptions.def +++ b/clang/include/clang/Basic/DiagnosticOptions.def @@ -65,7 +65,7 @@ VALUE_DIAGOPT(ShowCategories, 2, 0) /// Show categories: 0 -> none, 1 -> Number, ENUM_DIAGOPT(Format, TextDiagnosticFormat, 2, Clang) /// Format for diagnostics: -DIAGOPT(ShowColors, 1, 0) /// Show diagnostics with ANSI color sequences. +ENUM_DIAGOPT(ShowColors, ShowColorsKind, 2, ShowColorsKind::Auto) DIAGOPT(UseANSIEscapeCodes, 1, 0) ENUM_DIAGOPT(ShowOverloads, OverloadsShown, 1, Ovl_All) /// Overload candidates to show. diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h index a230022224de5..4cfc636619883 100644 --- a/clang/include/clang/Basic/DiagnosticOptions.h +++ b/clang/include/clang/Basic/DiagnosticOptions.h @@ -23,6 +23,16 @@ class ArgList; namespace clang { class DiagnosticsEngine; +/// Controls whether to show colors in diagnostic output. +enum class ShowColorsKind : unsigned { + /// Emit colors only if the output stream is detected to support them. + Auto, + /// Always emit colors regardless of the output stream. + On, + /// Never emit colors regardless of the output stream. + Off, +}; + /// Specifies which overload candidates to display when overload /// resolution fails. enum OverloadsShown : unsigned { @@ -143,6 +153,19 @@ class DiagnosticOptions { #define ENUM_DIAGOPT(Name, Type, Bits, Default) set##Name(Default); #include "clang/Basic/DiagnosticOptions.def" } + + /// Resolve the color mode against a stream's capability. + bool showColors(bool StreamHasColors) const { + switch (getShowColors()) { + case ShowColorsKind::On: + return true; + case ShowColorsKind::Off: + return false; + case ShowColorsKind::Auto: + return StreamHasColors; + } + return false; + } }; using TextDiagnosticFormat = DiagnosticOptions::TextDiagnosticFormat; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 4fc9f4d4c3472..2815d3a322703 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2093,7 +2093,7 @@ def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, Visibility<[ClangOption, CLOption, DXCOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Enable colors in diagnostics">; def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, + Visibility<[ClangOption, CLOption, DXCOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Disable colors in diagnostics">; def : Flag<["-"], "fdiagnostics-color">, Group<f_Group>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index b3071d83ed51f..146fc5ea5caad 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -16,12 +16,18 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclLookups.h" #include "clang/AST/JSONNodeDumper.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::comments; +static bool showColorsForStream(const ASTContext &Ctx, raw_ostream &OS) { + return Ctx.getDiagnostics().getDiagnosticOptions().showColors( + OS.has_colors()); +} + void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) { NodeDumper.AddChild([=] { if (!DC) { @@ -189,7 +195,7 @@ LLVM_DUMP_METHOD void QualType::dump() const { LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS, const ASTContext &Context) const { - ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, showColorsForStream(Context, OS)); Dumper.Visit(*this); } @@ -210,7 +216,7 @@ LLVM_DUMP_METHOD void TypeLoc::dump() const { LLVM_DUMP_METHOD void TypeLoc::dump(llvm::raw_ostream &OS, const ASTContext &Context) const { - ASTDumper(OS, Context, Context.getDiagnostics().getShowColors()).Visit(*this); + ASTDumper(OS, Context, showColorsForStream(Context, OS)).Visit(*this); } //===----------------------------------------------------------------------===// @@ -230,7 +236,7 @@ LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, (void)Deserialize; // FIXME? P.Visit(this); } else { - ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); + ASTDumper P(OS, Ctx, showColorsForStream(Ctx, OS)); P.setDeserialize(Deserialize); P.Visit(this); } @@ -261,7 +267,7 @@ LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const { // If an ASTContext is not available, a less capable ASTDumper is // constructed for which color diagnostics are, regrettably, disabled. ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx, - Ctx->getDiagnostics().getShowColors()) + showColorsForStream(*Ctx, llvm::errs())) : ASTDumper(llvm::errs(), /*ShowColors*/ false); P.dumpInvalidDeclContext(this); } @@ -278,7 +284,7 @@ LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, while (!DC->isTranslationUnit()) DC = DC->getParent(); const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); - ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); + ASTDumper P(OS, Ctx, showColorsForStream(Ctx, OS)); P.setDeserialize(Deserialize); P.dumpLookups(this, DumpDecls); } @@ -294,7 +300,7 @@ LLVM_DUMP_METHOD void Stmt::dump() const { LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, const ASTContext &Context) const { - ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper P(OS, Context, showColorsForStream(Context, OS)); P.Visit(this); } @@ -320,7 +326,7 @@ LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS, const auto *FC = dyn_cast<FullComment>(this); if (!FC) return; - ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, showColorsForStream(Context, OS)); Dumper.Visit(FC, FC); } @@ -343,7 +349,7 @@ LLVM_DUMP_METHOD void APValue::dump() const { LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS, const ASTContext &Context) const { - ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, showColorsForStream(Context, OS)); Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy)); } @@ -357,7 +363,7 @@ LLVM_DUMP_METHOD void ConceptReference::dump() const { LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const { auto &Ctx = getNamedConcept()->getASTContext(); - ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); + ASTDumper P(OS, Ctx, showColorsForStream(Ctx, OS)); P.Visit(this); } @@ -376,7 +382,7 @@ LLVM_DUMP_METHOD void TemplateName::dump() const { LLVM_DUMP_METHOD void TemplateName::dump(llvm::raw_ostream &OS, const ASTContext &Context) const { - ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, showColorsForStream(Context, OS)); Dumper.Visit(*this); } @@ -391,6 +397,6 @@ LLVM_DUMP_METHOD void TemplateArgument::dump() const { LLVM_DUMP_METHOD void TemplateArgument::dump(llvm::raw_ostream &OS, const ASTContext &Context) const { - ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, showColorsForStream(Context, OS)); Dumper.Visit(*this); } diff --git a/clang/lib/Basic/Warnings.cpp b/clang/lib/Basic/Warnings.cpp index 5f48e0ec81554..c76ef7a5912e4 100644 --- a/clang/lib/Basic/Warnings.cpp +++ b/clang/lib/Basic/Warnings.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/DiagnosticOptions.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/raw_ostream.h" #include <cstring> using namespace clang; @@ -53,7 +54,10 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, Diags.setElideType(Opts.ElideType); Diags.setPrintTemplateTree(Opts.ShowTemplateTree); - Diags.setShowColors(Opts.ShowColors); + // This flag bakes colors into the formatted message (e.g. template diffs), so + // resolve 'auto' against the default diagnostic stream (stderr) rather than + // forcing colors on. This keeps ANSI codes out of redirected or logged output. + Diags.setShowColors(Opts.showColors(llvm::errs().has_colors())); // Handle -ferror-limit if (Opts.ErrorLimit) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index ba4341ed41f1a..dfd13fbe8a4eb 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3317,8 +3317,16 @@ void tools::handleColorDiagnosticsArgs(const Driver &D, const ArgList &Args, << Value << A->getOption().getName(); } - if (D.getDiags().getDiagnosticOptions().ShowColors) + switch (D.getDiags().getDiagnosticOptions().getShowColors()) { + case ShowColorsKind::On: CmdArgs.push_back("-fcolor-diagnostics"); + break; + case ShowColorsKind::Off: + CmdArgs.push_back("-fno-color-diagnostics"); + break; + case ShowColorsKind::Auto: + break; + } } void tools::escapeSpacesAndBackslashes(const char *Arg, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 55b344fc2da26..52d40f70079e4 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2485,35 +2485,31 @@ static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts, return Diags.getNumErrors() == NumErrorsBefore; } -static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { +static ShowColorsKind parseShowColorsMode(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; + ShowColorsKind Mode = + DefaultColor ? ShowColorsKind::Auto : ShowColorsKind::Off; for (auto *A : Args) { const Option &O = A->getOption(); if (O.matches(options::OPT_fcolor_diagnostics)) { - ShowColors = Colors_On; + Mode = ShowColorsKind::On; } else if (O.matches(options::OPT_fno_color_diagnostics)) { - ShowColors = Colors_Off; + Mode = ShowColorsKind::Off; } else if (O.matches(options::OPT_fdiagnostics_color_EQ)) { StringRef Value(A->getValue()); if (Value == "always") - ShowColors = Colors_On; + Mode = ShowColorsKind::On; else if (Value == "never") - ShowColors = Colors_Off; + Mode = ShowColorsKind::Off; else if (Value == "auto") - ShowColors = Colors_Auto; + Mode = ShowColorsKind::Auto; } } - return ShowColors == Colors_On || - (ShowColors == Colors_Auto && - llvm::sys::Process::StandardErrHasColors()); + return Mode; } static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes, @@ -2594,8 +2590,16 @@ void CompilerInvocationBase::GenerateDiagnosticArgs( GenerateArg(Consumer, OPT_diagnostic_serialized_file, Opts.DiagnosticSerializationFile); - if (Opts.ShowColors) + switch (Opts.getShowColors()) { + case ShowColorsKind::On: GenerateArg(Consumer, OPT_fcolor_diagnostics); + break; + case ShowColorsKind::Off: + GenerateArg(Consumer, OPT_fno_color_diagnostics); + break; + case ShowColorsKind::Auto: + break; + } if (Opts.VerifyDiagnostics && llvm::is_contained(Opts.VerifyPrefixes, "expected")) @@ -2704,7 +2708,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, if (Arg *A = Args.getLastArg(OPT_diagnostic_serialized_file, OPT__serialize_diags)) Opts.DiagnosticSerializationFile = A->getValue(); - Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor); + Opts.setShowColors(parseShowColorsMode(Args, DefaultDiagColor)); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ); Opts.VerifyDirectives = Args.hasArg(OPT_verify_directives); @@ -5116,8 +5120,7 @@ bool CompilerInvocation::CreateFromArgsImpl( ParseMigratorArgs(Res.getMigratorOpts(), Args, Diags); ParseAnalyzerArgs(Res.getAnalyzerOpts(), Args, Diags); ParseSSAFArgs(Res.getSSAFOpts(), Args, Diags); - ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags, - /*DefaultDiagColor=*/false); + ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags); ParseFrontendArgs(Res.getFrontendOpts(), Args, Diags, LangOpts.IsHeaderFile); // FIXME: We shouldn't have to pass the DashX option around here InputKind DashX = Res.getFrontendOpts().DashX; diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index ba3487d52e380..f3fce25b78a8c 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -700,7 +700,8 @@ namespace { Out.indent(2) << "Diagnostic options:\n"; #define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts.Name, #Name); #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ - Out.indent(4) << #Name << ": " << DiagOpts.get##Name() << "\n"; + Out.indent(4) << #Name << ": " \ + << static_cast<unsigned>(DiagOpts.get##Name()) << "\n"; #define VALUE_DIAGOPT(Name, Bits, Default) \ Out.indent(4) << #Name << ": " << DiagOpts.Name << "\n"; #include "clang/Basic/DiagnosticOptions.def" diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 3f30709b0447e..01a4d2f6392d3 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -730,15 +730,16 @@ void TextDiagnostic::emitDiagnosticMessage( if (Loc.isValid()) emitDiagnosticLoc(Loc, PLoc, Level, Ranges); - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.resetColor(); if (DiagOpts.ShowLevel) - printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); + printDiagnosticLevel(OS, Level, DiagOpts.showColors(OS.has_colors())); printDiagnosticMessage(OS, /*IsSupplemental*/ Level == DiagnosticsEngine::Note, Message, OS.getColumn() - StartOfLocationInfo, - DiagOpts.MessageLength, DiagOpts.ShowColors); + DiagOpts.MessageLength, + DiagOpts.showColors(OS.has_colors())); // We use a formatted ostream, which does its own buffering. Flush here // so we keep the proper order of output. OS.flush(); @@ -872,7 +873,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, if (!DiagOpts.ShowLocation) return; - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.changeColor(SavedColor, true); emitFilename(PLoc.getFilename(), Loc.getManager()); @@ -1429,7 +1430,7 @@ void TextDiagnostic::emitSnippetAndCaret( // emit, starting from the first line. std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles = highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts, - DiagOpts.ShowColors, FID, SM); + DiagOpts.showColors(OS.has_colors()), FID, SM); SmallVector<LineRange> LineRanges = prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts); @@ -1508,22 +1509,22 @@ void TextDiagnostic::emitSnippetAndCaret( if (!CaretLine.empty()) { indentForLineNumbers(); - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.changeColor(CaretColor, true); OS << CaretLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.resetColor(); } if (!FixItInsertionLine.empty()) { indentForLineNumbers(); - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) // Print fixit line in color OS.changeColor(FixitColor, false); if (DiagOpts.ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.resetColor(); } } @@ -1552,7 +1553,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine, printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop); // Toggle inverted colors on or off for this character. - if (DiagOpts.ShowColors) { + if (DiagOpts.showColors(OS.has_colors())) { if (WasPrintable == PrintReversed) { PrintReversed = !PrintReversed; if (PrintReversed) @@ -1583,7 +1584,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine, OS << Str; } - if (DiagOpts.ShowColors) + if (DiagOpts.showColors(OS.has_colors())) OS.resetColor(); OS << '\n'; diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp index 475f11e36977c..b016aa34cf0b5 100644 --- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -134,11 +134,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, // other infrastructure necessary when emitting more rich diagnostics. if (!Info.getLocation().isValid()) { if (DiagOpts.ShowLevel) - TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); + TextDiagnostic::printDiagnosticLevel( + OS, Level, DiagOpts.showColors(OS.has_colors())); TextDiagnostic::printDiagnosticMessage( OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note, DiagMessageStream.str(), OS.tell() - StartOfLocationInfo, - DiagOpts.MessageLength, DiagOpts.ShowColors); + DiagOpts.MessageLength, DiagOpts.showColors(OS.has_colors())); OS.flush(); return; } diff --git a/clang/test/Misc/diagnostic-color-output-stream.cpp b/clang/test/Misc/diagnostic-color-output-stream.cpp new file mode 100644 index 0000000000000..96da7747348c2 --- /dev/null +++ b/clang/test/Misc/diagnostic-color-output-stream.cpp @@ -0,0 +1,25 @@ +// REQUIRES: ansi-escape-sequences + +// Default ('auto'): a redirected (non-terminal) stderr must not get ANSI codes. +// RUN: not %clang_cc1 -fsyntax-only -std=c++11 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOCOLOR %s + +// Forced off behaves the same. +// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fno-color-diagnostics %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOCOLOR %s + +// Forced on: ANSI codes are emitted even to a non-terminal. +// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics %s 2>&1 \ +// RUN: | FileCheck --check-prefix=COLOR %s + +// A -diagnostic-log-file pointing at a regular file must not contain ANSI. +// RUN: rm -f %t.log +// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -diagnostic-log-file %t.log %s 2>/dev/null +// RUN: FileCheck --check-prefix=NOCOLOR %s < %t.log + +template <typename> struct foo {}; +void func(foo<int>); +void g() { func(foo<double>()); } + +// COLOR: {{.\[0;1;36m}}double{{.\[0m}} +// NOCOLOR-NOT: {{.\[0;1;36m}} diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp index c3b8ffa00924e..0f6cfbd2266bb 100644 --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -651,11 +651,13 @@ struct CheckColoredDiagnosticsAction : public clang::ASTFrontendAction { : ShouldShowColor(ShouldShowColor) {} std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, StringRef) override { - if (Compiler.getDiagnosticOpts().ShowColors != ShouldShowColor) + bool HasColors = + Compiler.getDiagnosticOpts().getShowColors() == + (ShouldShowColor ? ShowColorsKind::On : ShowColorsKind::Off); + if (!HasColors) Compiler.getDiagnostics().Report( Compiler.getDiagnostics().getCustomDiagID( - DiagnosticsEngine::Fatal, - "getDiagnosticOpts().ShowColors != ShouldShowColor")); + DiagnosticsEngine::Fatal, "getShowColors() != expected")); return std::make_unique<ASTConsumer>(); } diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index ab961416441fe..f815084424607 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -122,7 +122,8 @@ static unsigned getOptimizationLevel(llvm::opt::ArgList &args, bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts, llvm::opt::ArgList &args) { - opts.ShowColors = parseShowColorsArgs(args); + opts.setShowColors(parseShowColorsArgs(args) ? clang::ShowColorsKind::On + : clang::ShowColorsKind::Off); return true; } @@ -1097,8 +1098,10 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args, // Default to off for `flang -fc1`. bool showColors{parseShowColorsArgs(args, false)}; - diags.getDiagnosticOptions().ShowColors = showColors; - res.getDiagnosticOpts().ShowColors = showColors; + auto colorsMode = + showColors ? clang::ShowColorsKind::On : clang::ShowColorsKind::Off; + diags.getDiagnosticOptions().setShowColors(colorsMode); + res.getDiagnosticOpts().setShowColors(colorsMode); res.getFrontendOpts().showColors = showColors; return !diags.hasUncompilableErrorOccurred(); } diff --git a/flang/lib/Frontend/TextDiagnosticPrinter.cpp b/flang/lib/Frontend/TextDiagnosticPrinter.cpp index 911b78a109e2e..33d54d9ad0b9c 100644 --- a/flang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/flang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -81,7 +81,7 @@ void TextDiagnosticPrinter::printLocForRemarks( llvm::sys::path::make_preferred(absPath); // Used for changing only the bold attribute - if (diagOpts.ShowColors) + if (diagOpts.showColors(os.has_colors())) os.changeColor(llvm::raw_ostream::SAVEDCOLOR, true); // Print path, file name, line and column @@ -112,12 +112,12 @@ void TextDiagnosticPrinter::HandleDiagnostic( llvm::StringRef diagMsg; printLocForRemarks(diagMessageStream, diagMsg); - Fortran::frontend::TextDiagnostic::printDiagnosticLevel(os, level, - diagOpts.ShowColors); + Fortran::frontend::TextDiagnostic::printDiagnosticLevel( + os, level, diagOpts.showColors(os.has_colors())); Fortran::frontend::TextDiagnostic::printDiagnosticMessage( os, /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, diagMsg, - diagOpts.ShowColors); + diagOpts.showColors(os.has_colors())); os.flush(); } diff --git a/flang/test/Driver/color-diagnostics.f90 b/flang/test/Driver/color-diagnostics.f90 index 7c471e39f923f..0fb4531fb4967 100644 --- a/flang/test/Driver/color-diagnostics.f90 +++ b/flang/test/Driver/color-diagnostics.f90 @@ -9,7 +9,7 @@ ! RUN: not %flang_fc1 %s -fcolor-diagnostics 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK_CD ! RUN: not %flang_fc1 %s -fno-color-diagnostics 2>&1 \ -! RUN: | FileCheck %s --check-prefix=UNSUPPORTED_COLOR_DIAGS +! RUN: | FileCheck %s --check-prefix=CHECK_NCD ! RUN: not %flang %s -fdiagnostics-color 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK_CD @@ -31,7 +31,6 @@ ! CHECK_NCD: Semantic errors in {{.*}}color-diagnostics.f90 -! UNSUPPORTED_COLOR_DIAGS: error: unknown argument: '-fno-color-diagnostics' ! UNSUPPORTED_DIAGS_COLOR: error: unknown argument: '-fdiagnostics-color' ! UNSUPPORTED_NO_DIAGS_COLOR: error: unknown argument: '-fno-diagnostics-color' diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 82fd9844cf96a..2bfa187c009a7 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -8477,14 +8477,19 @@ TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const { namespace { struct ScopedASTColor { ScopedASTColor(clang::ASTContext &ast, bool show_colors) - : ast(ast), old_show_colors(ast.getDiagnostics().getShowColors()) { - ast.getDiagnostics().setShowColors(show_colors); + : ast(ast), + old_show_colors( + ast.getDiagnostics().getDiagnosticOptions().getShowColors()) { + ast.getDiagnostics().getDiagnosticOptions().setShowColors( + show_colors ? clang::ShowColorsKind::On : clang::ShowColorsKind::Off); } - ~ScopedASTColor() { ast.getDiagnostics().setShowColors(old_show_colors); } + ~ScopedASTColor() { + ast.getDiagnostics().getDiagnosticOptions().setShowColors(old_show_colors); + } clang::ASTContext * - const bool old_show_colors; + const clang::ShowColorsKind old_show_colors; }; } // namespace _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
