https://github.com/kuilpd created https://github.com/llvm/llvm-project/pull/187680
* Correctly return the result when used from the console, so that it can use `DiagnosticsRendering` to output the error. * Add location pointer to `DILDiagnosticError` internal formatting to show diagnostics when called from the API. >From c864791ebf1c27fd3695b31bfede693a487b8cac Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Thu, 19 Mar 2026 19:38:35 +0500 Subject: [PATCH 1/2] [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 <[email protected]> Date: Fri, 20 Mar 2026 00:44:10 +0500 Subject: [PATCH 2/2] 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> _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
