https://github.com/hawkinsw updated 
https://github.com/llvm/llvm-project/pull/215706

>From 22fc78067e2ae82e8991ff3b9e5a877bf8fb9f35 Mon Sep 17 00:00:00 2001
From: Will Hawkins <[email protected]>
Date: Tue, 11 Aug 2026 21:46:30 -0400
Subject: [PATCH] [lldb] Support Persistent Variables as DIL Identifiers

When a persistent variable is used in a DIL expression, look it up as if
it were any other identifier in the global scope.

Signed-off-by: Will Hawkins <[email protected]>
---
 lldb/include/lldb/ValueObject/DILEval.h       |  7 ++++
 .../Commands/CommandObjectDWIMPrint.cpp       |  3 ++
 lldb/source/ValueObject/DILEval.cpp           | 37 ++++++++++++++++++
 .../PersistentResultVariableLookup/Makefile   |  3 ++
 .../TestFrameVarDILGlobalVariableLookup.py    | 39 +++++++++++++++++++
 .../PersistentResultVariableLookup/main.cpp   |  4 ++
 .../Shell/Commands/command-dwim-print.test    |  7 ++++
 7 files changed, 100 insertions(+)
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp

diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index 489dc801b20db..3a873063adda1 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -18,6 +18,13 @@
 
 namespace lldb_private::dil {
 
+/// Given the name of a persistent identifier (i.e., one that starts with a $),
+/// find the ValueObject for that name (if it exists).
+lldb::ValueObjectSP LookupPersistentIdentifier(llvm::StringRef name_ref,
+                                               StackFrame &stack_frame,
+                                               lldb::TargetSP target_sp,
+                                               lldb::LanguageType language);
+
 /// Given the name of an identifier (variable name, member name, type name,
 /// etc.), find the ValueObject for that name (if it exists), excluding global
 /// variables, and create and return an IdentifierInfo object containing all
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp 
b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 1b0b4c7881cfc..6332fbf2b291c 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -191,6 +191,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
     }
   }
 
+  #if 0
   // Second, try `expr` as a persistent variable.
   if (expr.starts_with("$"))
     if (auto *state = target.GetPersistentExpressionStateForLanguage(
@@ -201,6 +202,8 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
           return;
         }
 
+  #endif
+
   // Third, and lastly, try `expr` as a source expression to evaluate.
   {
     auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index 0ef4e244410a4..da7c7eaac16ac 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -8,16 +8,20 @@
 
 #include "lldb/ValueObject/DILEval.h"
 #include "lldb/Core/Module.h"
+#include "lldb/Expression/ExpressionVariable.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/ValueObject/DILAST.h"
 #include "lldb/ValueObject/DILParser.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include "lldb/ValueObject/ValueObjectRegister.h"
 #include "lldb/ValueObject/ValueObjectVariable.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-types.h"
 #include "llvm/Support/ErrorExtras.h"
 #include "llvm/Support/FormatAdapters.h"
 #include <memory>
@@ -44,6 +48,17 @@ static lldb::ValueObjectSP 
ArrayToPointerConversion(ValueObject &valobj,
       /* do_deref */ false);
 }
 
+static llvm::Expected<lldb::LanguageType>
+GetSourceLanguageFromCU(StackFrame &ctx) {
+  SymbolContext symbol_context =
+      ctx.GetSymbolContext(lldb::eSymbolContextCompUnit);
+  if (!symbol_context.comp_unit)
+    return llvm::createStringErrorV("no compile unit for frame: {}",
+                                    ctx.GetFunctionName());
+
+  return symbol_context.comp_unit->GetLanguage();
+}
+
 static llvm::Expected<lldb::TypeSystemSP> GetTypeSystemFromCU(StackFrame &ctx) 
{
   SymbolContext symbol_context =
       ctx.GetSymbolContext(lldb::eSymbolContextCompUnit);
@@ -323,6 +338,20 @@ lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef 
name_ref,
   return nullptr;
 }
 
+lldb::ValueObjectSP LookupPersistentIdentifier(llvm::StringRef name_ref,
+                                               StackFrame &stack_frame,
+                                               lldb::TargetSP target_sp,
+                                               lldb::LanguageType language) {
+  if (name_ref.starts_with("$")) {
+    if (auto *state =
+            target_sp->GetPersistentExpressionStateForLanguage(language))
+      if (auto var_sp = state->GetVariable(name_ref))
+        if (auto valobj_sp = var_sp->GetValueObject())
+          return valobj_sp;
+  }
+  return nullptr;
+}
+
 lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
                                      StackFrame &stack_frame,
                                      lldb::DynamicValueType use_dynamic) {
@@ -459,6 +488,14 @@ Interpreter::Visit(const IdentifierNode &node) {
   if (!identifier)
     identifier = LookupEnumValue(node.GetName(), m_stack_frame);
 
+  if (!identifier && node.GetName()[0] == '$') {
+    auto language = GetSourceLanguageFromCU(m_stack_frame);
+    if (!language)
+      return language.takeError();
+    identifier = LookupPersistentIdentifier(node.GetName(), m_stack_frame,
+                                            m_target, language.get());
+  }
+
   if (!identifier && node.GetName() == "nullptr") {
     // If we got a "nullptr" identifier, and there is no defined variable with
     // this name, resolve it as a null pointer.
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile
 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py
 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py
new file mode 100644
index 0000000000000..a3d3825532ccc
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py
@@ -0,0 +1,39 @@
+"""
+Make sure 'frame var' using DIL parser/evaluator works for persistent/result 
variables.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+
+class TestFrameVarDILGlobalVariableLookup(TestBase):
+    # If your test case doesn't stress debug info, then
+    # set this to true.  That way it won't be run once for
+    # each debug info format.
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIf(macos_version=["<", "15.0"], archs=["arm64", "arm64e"])
+    @skipIf(
+        dwarf_version=["<", "5"],
+        oslist=[lldbplatformutil.getDarwinOSTriples()],
+    )
+    @expectedFailureAll(
+        compiler="clang",
+        compiler_version=["<", "19.0"],
+        oslist=[lldbplatformutil.getDarwinOSTriples()],
+    )
+    def test_frame_var(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+        self.expect("dwim-print --persistent-result true -- foo + 5", 
startstr="(int) $0 = ")
+        self.expect_var_path("$0", type="int", value="6")
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp
 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp
new file mode 100644
index 0000000000000..fd23884132e8d
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp
@@ -0,0 +1,4 @@
+int main(int argc, char **argv) {
+  int foo = 1;
+  return 0; // Set a breakpoint here
+}
diff --git a/lldb/test/Shell/Commands/command-dwim-print.test 
b/lldb/test/Shell/Commands/command-dwim-print.test
index 8c2697d8ebf8c..26662ea822648 100644
--- a/lldb/test/Shell/Commands/command-dwim-print.test
+++ b/lldb/test/Shell/Commands/command-dwim-print.test
@@ -14,3 +14,10 @@
 # RUN: echo quit | %lldb -o "settings set show-inline-diagnostics false" \
 # RUN:   -o "dwim-print a" 2>&1 | FileCheck %s --check-prefix=CHECK4
 # CHECK4: error: <user expression 0>:1:1: use of undeclared identifier
+# RUN: %clang_host -g %S/Inputs/main.c -o %t
+# RUN: echo quit | %lldb %t -o "b main" -o "r" -o \
+# RUN: "dwim-print --persistent-result true -- foo" -o \
+# RUN: "settings set dwim-print-verbosity full" -o \
+# RUN: "dwim-print -- $0" | FileCheck %s --check-prefix=CHECK5
+#            (lldb) dwim-print -- $0
+# CHECK5:note: ran `frame variable $0`
\ No newline at end of file

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to