https://github.com/qiyao created
https://github.com/llvm/llvm-project/pull/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.
>From 7bf6b93489cf436055479c1dd8818dff293e4571 Mon Sep 17 00:00:00 2001
From: Yao Qi <[email protected]>
Date: Fri, 5 Jun 2026 14:59:19 +0100
Subject: [PATCH] [clang] Honor ShowLevel for diagnostics without a source
location
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.
---
clang/lib/Frontend/TextDiagnosticPrinter.cpp | 3 ++-
.../unittests/Frontend/TextDiagnosticTest.cpp | 26 +++++++++++++++++++
.../diagnostics/TestExprDiagnostics.py | 2 +-
.../Shell/Expr/TestObjCxxEnumConflict.test | 4 +--
4 files changed, 31 insertions(+), 4 deletions(-)
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..20ab54379c7a4 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));
}
+// Parameterized fixture for ShowLevel tests: bool param = ShowLevel value.
+struct ShowLevelNoLocationTest : public ::testing::TestWithParam<bool> {};
+
+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