Author: Yao Qi Date: 2026-06-15T08:01:26-07:00 New Revision: 2f0a17cc05242d8b98d43a4c60a60f6bcbf5ed10
URL: https://github.com/llvm/llvm-project/commit/2f0a17cc05242d8b98d43a4c60a60f6bcbf5ed10 DIFF: https://github.com/llvm/llvm-project/commit/2f0a17cc05242d8b98d43a4c60a60f6bcbf5ed10.diff LOG: [clang] Honor ShowLevel for diagnostics without a source location (#203520) When lldb evaluates expression and gets error, it prints double `error: ` as below, ``` (lldb) expression v1::withImplicitTag(Simple{.mem = 6}) note: Ran expression as 'C++11'. error: error: Multiple internal symbols found for 'v1' ``` The first `error:` is from lldb and the second `error:` is from clang's diagnostic. LLDB's `ClangDiagnosticManagerAdapter` sets `ShowLevel=false`, so that its own rendering layer (`RenderDiagnosticDetails`) can add the severity prefix with color. However, clang still adds "error:" in the output buffer means the guard is missing. `TextDiagnosticPrinter::HandleDiagnostic` has two paths: one for diagnostics with a valid source location (delegating to `TextDiagnostic::emitDiagnostic`) and a simpler path for diagnostics without one. The with-location path already guarded `printDiagnosticLevel` behind `DiagOpts.ShowLevel`; the no-location path called it unconditionally. Add a parameterized unit test covering `ShowLevel=true` and `ShowLevel=false` for no-location diagnostics to prevent regression. --------- Co-authored-by: Michael Buch <[email protected]> Added: Modified: clang/lib/Frontend/TextDiagnosticPrinter.cpp clang/unittests/Frontend/TextDiagnosticTest.cpp lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py lldb/test/Shell/Expr/TestObjCxxEnumConflict.test Removed: ################################################################################ diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp index 83fd70e5f99f9..475f11e36977c 100644 --- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -133,7 +133,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, // diagnostics in a context that lacks language options, a source manager, or // other infrastructure necessary when emitting more rich diagnostics. if (!Info.getLocation().isValid()) { - TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); + if (DiagOpts.ShowLevel) + TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); TextDiagnostic::printDiagnosticMessage( OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note, DiagMessageStream.str(), OS.tell() - StartOfLocationInfo, diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp index 622dbc5883067..4c4decc4a6857 100644 --- a/clang/unittests/Frontend/TextDiagnosticTest.cpp +++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" #include "gtest/gtest.h" @@ -95,4 +96,29 @@ TEST(TextDiagnostic, ShowLine) { EXPECT_EQ("main.cpp:1: warning: message\n", PrintDiag(DiagOpts, Loc)); } +struct ShowLevelNoLocationTest + : public ::testing::TestWithParam<bool /* ShowLevel */> {}; + +TEST_P(ShowLevelNoLocationTest, LevelPrefixRespected) { + bool ShowLevel = GetParam(); + DiagnosticOptions DiagOpts; + DiagOpts.ShowLevel = ShowLevel; + std::string Output; + llvm::raw_string_ostream OS(Output); + TextDiagnosticPrinter Printer(OS, DiagOpts); + DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, &Printer, + /*ShouldOwnClient=*/false); + // Report without a SourceLocation, exercises the no-location path in + // TextDiagnosticPrinter::HandleDiagnostic. + unsigned ID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"); + Diags.Report(ID) << "message"; + if (ShowLevel) + EXPECT_EQ(Output, "error: message\n"); + else + EXPECT_EQ(Output, "message\n"); +} + +INSTANTIATE_TEST_SUITE_P(ShowLevelNoLocation, ShowLevelNoLocationTest, + ::testing::Bool()); + } // anonymous namespace diff --git a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py index 1f87a6918bb21..03851924aba45 100644 --- a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py +++ b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py @@ -140,7 +140,7 @@ def test_source_and_caret_printing(self): """ 1 | foo(1, 2) | ^~~ -note: candidate function not viable: requires single argument 'x', but 2 arguments were provided +candidate function not viable: requires single argument 'x', but 2 arguments were provided """, value.GetError().GetCString(), ) diff --git a/lldb/test/Shell/Expr/TestObjCxxEnumConflict.test b/lldb/test/Shell/Expr/TestObjCxxEnumConflict.test index cf1f2c67e3880..2cbe13280a6b6 100644 --- a/lldb/test/Shell/Expr/TestObjCxxEnumConflict.test +++ b/lldb/test/Shell/Expr/TestObjCxxEnumConflict.test @@ -50,5 +50,5 @@ expression -l objective-c -- (MyInt)5 # CHECK: error: reference to 'MyInt' is ambiguous # CHECK: error: reference to 'MyInt' is ambiguous -# CHECK: note: note: candidate found by name lookup is 'MyInt' -# CHECK: note: note: candidate found by name lookup is 'MyInt' +# CHECK: note: candidate found by name lookup is 'MyInt' +# CHECK: note: candidate found by name lookup is 'MyInt' _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
