[Lldb-commits] [lldb] e24936b - [lldb] Fix DIL error diagnostics output (#187680)

via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 3 04:29:39 PDT 2026


Author: Ilia Kuklin
Date: 2026-04-03T16:29:33+05:00
New Revision: e24936b7ad5c6b1fdcc35d98c682fa5bd745e65b

URL: https://github.com/llvm/llvm-project/commit/e24936b7ad5c6b1fdcc35d98c682fa5bd745e65b
DIFF: https://github.com/llvm/llvm-project/commit/e24936b7ad5c6b1fdcc35d98c682fa5bd745e65b.diff

LOG: [lldb] Fix DIL error diagnostics output (#187680)

* Correctly return the result when used from the console, so that
`DiagnosticsRendering` could use it to output the error.
* Add location pointer to `DILDiagnosticError` internal formatting to
show diagnostics when called from the API.

Added: 
    lldb/test/Shell/Commands/command-dil-diagnostics.test

Modified: 
    lldb/source/Commands/CommandObjectFrame.cpp
    lldb/source/Target/StackFrame.cpp
    lldb/source/ValueObject/DILParser.cpp
    lldb/test/Shell/Commands/Inputs/main.c

Removed: 
    


################################################################################
diff  --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 1488e3bfe5890..f1800df58aa52 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -638,8 +638,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 89435e20cc49b..e04b4e2300635 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -545,7 +545,7 @@ 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));
+    return ValueObjectConstResult::Create(nullptr, error.Clone());
   }
 
   // Parse the expression.
@@ -554,7 +554,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
                             shared_from_this(), use_dynamic, options);
   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.
@@ -565,7 +565,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 919acd4645f71..d226ba66ef889 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -36,13 +36,27 @@ 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);
+  // If the error is not handled by `RenderDiagnosticDetails`, this creates an
+  // error message that can be displayed instead.
+  // Example:
+  // (lldb) script lldb.frame.GetValueForVariablePath("1 + foo")
+  // error: <user expression>:1:5: use of undeclared identifier 'foo'
+  //   1 | 1 + foo
+  //     |     ^~~
+  auto msg = llvm::formatv("<user expression>:1:{0}: {1}\n    1 | {2}\n      |",
+                           loc + 1, message, expr);
+  std::string rendered_str;
+  llvm::raw_string_ostream rendered_os(rendered_str);
+  rendered_os << msg.str();
+  rendered_os << llvm::indent(loc + 1) << "^";
+  if (err_len > 1) {
+    // Underline the rest of the erroneous token after the cursor '^'.
+    rendered_os << std::string(err_len - 1, '~');
+  }
   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>

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>


        


More information about the lldb-commits mailing list