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

Reply via email to