[clang] [lldb] [clang] Honor ShowLevel for diagnostics without a source location (PR #203520)
Yao Qi via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 12 08:54:25 PDT 2026
https://github.com/qiyao updated https://github.com/llvm/llvm-project/pull/203520
>From 7bf6b93489cf436055479c1dd8818dff293e4571 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Fri, 5 Jun 2026 14:59:19 +0100
Subject: [PATCH 1/2] [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'
>From 204bcb8fa84e7cca743b205876ea8a714d650abd Mon Sep 17 00:00:00 2001
From: Yao Qi <qiyaoltc at gmail.com>
Date: Fri, 12 Jun 2026 16:54:16 +0100
Subject: [PATCH 2/2] Update clang/unittests/Frontend/TextDiagnosticTest.cpp
Co-authored-by: Michael Buch <michaelbuch12 at gmail.com>
---
clang/unittests/Frontend/TextDiagnosticTest.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp
index 20ab54379c7a4..d99d3aef4caa2 100644
--- a/clang/unittests/Frontend/TextDiagnosticTest.cpp
+++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp
@@ -96,8 +96,7 @@ 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> {};
+struct ShowLevelNoLocationTest : public ::testing::TestWithParam<bool /* ShowLevel */> {};
TEST_P(ShowLevelNoLocationTest, LevelPrefixRespected) {
bool ShowLevel = GetParam();
More information about the cfe-commits
mailing list