[Lldb-commits] [lldb] [lldb] Fix DIL error diagnostics output (PR #187680)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Wed Apr 1 07:27:52 PDT 2026
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/187680
>From c864791ebf1c27fd3695b31bfede693a487b8cac Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 19 Mar 2026 19:38:35 +0500
Subject: [PATCH 1/3] [lldb] Fix DIL error diagnostics output
---
lldb/source/Commands/CommandObjectFrame.cpp | 17 +++++++++++++++--
lldb/source/Target/StackFrame.cpp | 8 +++++---
lldb/source/ValueObject/DILParser.cpp | 16 ++++++++++++----
3 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 9133359fbf537..47ad6c164f5b9 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -637,8 +637,21 @@ may even involve JITing and running code in the target program.)");
Stream &output_stream = result.GetOutputStream();
options.SetRootValueObjectName(
valobj_sp->GetParent() ? entry.c_str() : nullptr);
- if (llvm::Error error = valobj_sp->Dump(output_stream, options))
- result.AppendError(toString(std::move(error)));
+ // Check only the `error` argument, because doing
+ // `valobj_sp->GetError()` will update the value and potentially
+ // return a new error that happens during the update, even if
+ // `GetValueForVariableExpressionPath` reported no errors.
+ if (error.Fail()) {
+ result.SetStatus(eReturnStatusFailed);
+ result.SetError(error.takeError());
+ } else {
+ // If there is an error while updating the value, it will be
+ // printed here as the contents of the value, e.g.
+ // `(int) *((int*)0) = <parent is NULL>`
+ if (llvm::Error error = valobj_sp->Dump(output_stream, options))
+ result.AppendError(toString(std::move(error)));
+ }
+
} else {
if (auto error_cstr = error.AsCString(nullptr))
result.AppendError(error_cstr);
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 9fb26176e43c0..0b4ced1cd67ba 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -552,7 +552,9 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
auto lex_or_err = dil::DILLexer::Create(var_expr, mode);
if (!lex_or_err) {
error = Status::FromError(lex_or_err.takeError());
- return ValueObjectConstResult::Create(nullptr, std::move(error));
+ // Duplicate the error so that it can be accessed from both
+ // the return result and the `&error` argument.
+ return ValueObjectConstResult::Create(nullptr, error.Clone());
}
// Parse the expression.
@@ -561,7 +563,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
!no_synth_child, !no_fragile_ivar, check_ptr_vs_member);
if (!tree_or_error) {
error = Status::FromError(tree_or_error.takeError());
- return ValueObjectConstResult::Create(nullptr, std::move(error));
+ return ValueObjectConstResult::Create(nullptr, error.Clone());
}
// Evaluate the parsed expression.
@@ -573,7 +575,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
auto valobj_or_error = interpreter.Evaluate(**tree_or_error);
if (!valobj_or_error) {
error = Status::FromError(valobj_or_error.takeError());
- return ValueObjectConstResult::Create(nullptr, std::move(error));
+ return ValueObjectConstResult::Create(nullptr, error.Clone());
}
var_sp = (*valobj_or_error)->GetVariable();
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index bb5a86bc7168b..4fd3d52bc9f0a 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -36,13 +36,21 @@ DILDiagnosticError::DILDiagnosticError(llvm::StringRef expr,
DiagnosticDetail::SourceLocation sloc = {
FileSpec{}, /*line=*/1, static_cast<uint16_t>(loc + 1),
err_len, false, /*in_user_input=*/true};
- std::string rendered_msg =
- llvm::formatv("<user expression 0>:1:{0}: {1}\n 1 | {2}\n | ^",
- loc + 1, message, expr);
+ StreamString rendered_msg(false);
+ auto msg = llvm::formatv("<user expression>:1:{0}: {1}\n 1 | {2}\n |",
+ loc + 1, message, expr);
+ rendered_msg << msg.str();
+ for (uint32_t i = 0; i <= loc; i++)
+ rendered_msg << " ";
+ rendered_msg << "^";
+ for (uint32_t i = 1; i < err_len; i++)
+ rendered_msg << "~";
+ std::string rendered_str = rendered_msg.GetString().str();
+
m_detail.source_location = sloc;
m_detail.severity = lldb::eSeverityError;
m_detail.message = message;
- m_detail.rendered = std::move(rendered_msg);
+ m_detail.rendered = std::move(rendered_str);
}
llvm::Expected<lldb::TypeSystemSP>
>From 3dfc0855900d009243b1a517b5359796ec31ea82 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 20 Mar 2026 00:44:10 +0500
Subject: [PATCH 2/3] Add a test
---
lldb/test/Shell/Commands/Inputs/main.c | 1 +
.../Commands/command-dil-diagnostics.test | 22 +++++++++++++++++++
2 files changed, 23 insertions(+)
create mode 100644 lldb/test/Shell/Commands/command-dil-diagnostics.test
diff --git a/lldb/test/Shell/Commands/Inputs/main.c b/lldb/test/Shell/Commands/Inputs/main.c
index c029ddd96cd52..284605e5db11d 100644
--- a/lldb/test/Shell/Commands/Inputs/main.c
+++ b/lldb/test/Shell/Commands/Inputs/main.c
@@ -1,2 +1,3 @@
int foo() { return 0; }
int main() { return foo(); }
+int a = 1;
diff --git a/lldb/test/Shell/Commands/command-dil-diagnostics.test b/lldb/test/Shell/Commands/command-dil-diagnostics.test
new file mode 100644
index 0000000000000..ee056e6bb3f51
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-dil-diagnostics.test
@@ -0,0 +1,22 @@
+## Check DIL error diagnostics output.
+# XFAIL: target-windows
+# RUN: %clang_host -g -O0 %S/Inputs/main.c -o %t
+# RUN: %lldb %t -o "command source -e 0 %s" -o exit 2>&1 | FileCheck %s --strict-whitespace
+settings set target.experimental.use-DIL true
+b main
+run
+
+## Check console diagnostincs pointing to an error in user input.
+frame var a+b
+# CHECK: {{^ (\^|˄)}}
+# CHECK-NEXT: {{^ (╰─ )?}}error: use of undeclared identifier 'b'
+
+## Check diagnostics when called from API.
+script lldb.frame.GetValueForVariablePath("++foo")
+# CHECK: error: <user expression>:1:3: use of undeclared identifier 'foo'
+# CHECK-NEXT: {{^ }}1 | ++foo
+# CHECK-NEXT: {{^ }} | ^~~
+
+## Check that a result that fails to retrieve data is displaying an error.
+frame var *((int*)0)
+# CHECK: (int) *((int*)0) = <parent is NULL>
>From 2a40531a65b3f30d1c288171b9f49331c9d23408 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 1 Apr 2026 19:26:17 +0500
Subject: [PATCH 3/3] Remove comment, use raw_string_ostream
---
lldb/source/Target/StackFrame.cpp | 2 --
lldb/source/ValueObject/DILParser.cpp | 13 +++++--------
2 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 0b4ced1cd67ba..7c42c87e8939b 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -552,8 +552,6 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
auto lex_or_err = dil::DILLexer::Create(var_expr, mode);
if (!lex_or_err) {
error = Status::FromError(lex_or_err.takeError());
- // Duplicate the error so that it can be accessed from both
- // the return result and the `&error` argument.
return ValueObjectConstResult::Create(nullptr, error.Clone());
}
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 4fd3d52bc9f0a..83c69dac22b16 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -33,19 +33,16 @@ DILDiagnosticError::DILDiagnosticError(llvm::StringRef expr,
const std::string &message, uint32_t loc,
uint16_t err_len)
: ErrorInfo(make_error_code(std::errc::invalid_argument)) {
+ assert(err_len != 0);
DiagnosticDetail::SourceLocation sloc = {
FileSpec{}, /*line=*/1, static_cast<uint16_t>(loc + 1),
err_len, false, /*in_user_input=*/true};
- StreamString rendered_msg(false);
auto msg = llvm::formatv("<user expression>:1:{0}: {1}\n 1 | {2}\n |",
loc + 1, message, expr);
- rendered_msg << msg.str();
- for (uint32_t i = 0; i <= loc; i++)
- rendered_msg << " ";
- rendered_msg << "^";
- for (uint32_t i = 1; i < err_len; i++)
- rendered_msg << "~";
- std::string rendered_str = rendered_msg.GetString().str();
+ std::string rendered_str;
+ llvm::raw_string_ostream rendered_os(rendered_str);
+ rendered_os << msg.str();
+ rendered_os << llvm::indent(loc + 1) << "^" << std::string(err_len - 1, '~');
m_detail.source_location = sloc;
m_detail.severity = lldb::eSeverityError;
More information about the lldb-commits
mailing list