https://github.com/jimingham updated 
https://github.com/llvm/llvm-project/pull/203128

>From e44cadf82148e1953097516747c85d30a042f4ef Mon Sep 17 00:00:00 2001
From: Jim Ingham <[email protected]>
Date: Wed, 10 Jun 2026 16:47:05 -0700
Subject: [PATCH 1/4] Add the ability to look up persistent types and variables
 defined in the expression parser through the SB API's.

---
 lldb/bindings/interface/SBTargetDocstrings.i  |  30 +++++
 lldb/include/lldb/API/SBTarget.h              |   6 +
 lldb/source/API/SBTarget.cpp                  |  85 ++++++++++++++
 .../API/python_api/persistent_decls/Makefile  |   4 +
 .../persistent_decls/TestPersistentDecls.py   | 111 ++++++++++++++++++
 .../API/python_api/persistent_decls/main.c    |   6 +
 6 files changed, 242 insertions(+)
 create mode 100644 lldb/test/API/python_api/persistent_decls/Makefile
 create mode 100644 
lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
 create mode 100644 lldb/test/API/python_api/persistent_decls/main.c

diff --git a/lldb/bindings/interface/SBTargetDocstrings.i 
b/lldb/bindings/interface/SBTargetDocstrings.i
index b486a8f189f10..3cfb18f766cd2 100644
--- a/lldb/bindings/interface/SBTargetDocstrings.i
+++ b/lldb/bindings/interface/SBTargetDocstrings.i
@@ -307,6 +307,36 @@ produces: ::
         An SBAddress which will be valid if..."
 ) lldb::SBTarget::ResolveFileAddress;
 
+%feature("docstring", "
+    Look up a persistent type defined using the expression parser.
+
+    @param[in] type_name
+         The base name of the persistent type you defined.
+
+    @param[in] language
+         A member of the enum lldb::LanguageType giving the
+         language of the Expression parser you used to define
+         the persistent type.
+
+    @return
+        An SBType representing the persistent type you defined."
+) lldb::SBTarget::FindExpressionTypeForLanguage;
+
+%feature("docstring", "
+    Look up a persistent variable defined using the expression parser.
+
+    @param[in] variable_name
+         The name of the persistent variable you defined.
+
+    @param[in] language
+        A member of the enum lldb::LanguageType giving the
+        language of the Expression parser you used to define
+        the persistent type.
+
+    @return
+        An SBValue representing the persistent variable you defined."
+) lldb::SBTarget::FindExpressionVariableForLanguage;
+
 %feature("docstring", "
     Read target memory. If a target process is running then memory
     is read from here. Otherwise the memory is read from the object
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index d598c44dd7332..113c5db0331df 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -923,6 +923,12 @@ class LLDB_API SBTarget {
 
   lldb::SBType GetBasicType(lldb::BasicType type);
 
+  lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
+      lldb::LanguageType lang);
+
+  lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
+      lldb::LanguageType lang);
+
   lldb::SBValue CreateValueFromAddress(const char *name, lldb::SBAddress addr,
                                        lldb::SBType type);
 
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 72286336102d2..9ac6f06c9b840 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -40,6 +40,7 @@
 #include "lldb/Core/SearchFilter.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Expression/ExpressionVariable.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h"
 #include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
@@ -1878,6 +1879,90 @@ lldb::SBSymbolContextList 
SBTarget::FindGlobalFunctions(const char *name,
   return sb_sc_list;
 }
 
+lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
+      lldb::LanguageType language) {
+  TargetSP target_sp = GetSP();
+  if (!target_sp)
+    return {};
+
+  if (!typename_cstr || !typename_cstr[0])
+    return {};
+
+  ConstString const_typename(typename_cstr);
+
+  // If the language type was "unknown" search all languages:
+  if (language == lldb::eLanguageTypeUnknown) {
+    LanguageSet expr_languages =
+        Language::GetLanguagesSupportingTypeSystemsForExpressions();
+    for (int bit : expr_languages.bitvector.set_bits()) {
+      auto cur_lang = (LanguageType)bit;
+      PersistentExpressionState *persistent =
+          target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
+      if (persistent) {
+        std::optional<CompilerType> type_op
+          = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+        if (type_op) {
+          return SBType(*type_op);
+        }
+      }
+    }
+  } else {
+    PersistentExpressionState *persistent =
+        target_sp->GetPersistentExpressionStateForLanguage(language);
+    if (persistent) {
+      std::optional<CompilerType> type_op
+        = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+      if (type_op && (*type_op)) {
+        return SBType(*type_op);
+      }
+    }
+  }
+  return {};
+}
+
+lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
+    const char *varname_cstr, lldb::LanguageType language) {
+  TargetSP target_sp = GetSP();
+  if (!target_sp)
+    return {};
+
+  if (!varname_cstr || !varname_cstr[0])
+    return {};
+
+  ConstString const_varname(varname_cstr);
+
+  // If the language type was "unknown" search all languages:
+  if (language == lldb::eLanguageTypeUnknown) {
+    LanguageSet expr_languages =
+        Language::GetLanguagesSupportingTypeSystemsForExpressions();
+    for (int bit : expr_languages.bitvector.set_bits()) {
+      auto cur_lang = (LanguageType)bit;
+      PersistentExpressionState *persistent =
+          target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
+      if (persistent) {
+        lldb::ExpressionVariableSP expr_var_sp =
+            persistent->GetVariable(const_varname);
+        if (expr_var_sp) {
+          return expr_var_sp->GetValueObject();
+        }
+      }
+    }
+  } else {
+    PersistentExpressionState *persistent =
+        target_sp->GetPersistentExpressionStateForLanguage(language);
+    if (persistent) {
+      lldb::ExpressionVariableSP expr_var_sp =
+          persistent->GetVariable(const_varname);
+      if (expr_var_sp) {
+        return expr_var_sp->GetValueObject();
+      }
+    }
+  }
+  return {};
+}
+
+
+
 lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
   LLDB_INSTRUMENT_VA(this, typename_cstr);
 
diff --git a/lldb/test/API/python_api/persistent_decls/Makefile 
b/lldb/test/API/python_api/persistent_decls/Makefile
new file mode 100644
index 0000000000000..695335e068c0c
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -std=c99
+
+include Makefile.rules
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py 
b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
new file mode 100644
index 0000000000000..1381a251bb9a8
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -0,0 +1,111 @@
+"""
+Test the SBTarget API's to retrieve persistent types
+and values.
+"""
+
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+
+class TestPersistentDecls(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_persistent_types(self):
+        """Define some types in the expression evaluator and find them."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        self.types_test(False)
+
+    def test_persistent_types_unknown(self):
+        """Define some types in the expression evaluator and find them."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        self.types_test(True)
+
+    def test_persistent_values(self):
+        """Define some values in the expression evaluator and find them."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        self.values_test(False)
+        
+    def test_persistent_values_unknown(self):
+        """Define some values in the expression evaluator and find them."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        self.values_test(True)
+        
+    def types_test(self, use_unknown):
+        (target, _, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", self.main_source_file
+        )
+
+        # Make some types so we aren't succeeding in gettting the only one.
+        
+        typename = "$firstStruct"
+
+        self.expect(f"expr struct $SomeType {{ int b; int a; int c;}}")
+        self.expect(f"expr struct {typename} {{ int a; int b; char *c;}}")
+        self.expect(f"expr struct $AnotherType {{ int a; char *b; int c;}}")
+        self.expect(f"expr struct $YetAnotherType {{ char *a; int b; int c;}}")
+
+        if use_unknown:
+            language = lldb.eLanguageTypeUnknown
+        else:
+            language = lldb.eLanguageTypeC_plus_plus
+        
+        type = target.FindExpressionTypeForLanguage(typename, language)
+        self.assertTrue(type.IsValid(), "Got a valid type")
+
+        # Make sure we got the type we expected:
+        self.assertEqual(type.name, typename, "Got the right type.")
+        # Now check that the fields are right:
+        self.assertEqual(type.num_fields, 3, "Right number of fields")
+
+        ivar_a = type.fields[0]
+        self.assertEqual(ivar_a.name, "a", "a name is right")
+        self.assertEqual(ivar_a.type.name, "int", "Right type")
+
+        ivar_b = type.fields[1]
+        self.assertEqual(ivar_b.name, "b", "b name is right")
+        self.assertEqual(ivar_b.type.name, "int", "Right type")
+
+        ivar_c = type.fields[2]
+        self.assertEqual(ivar_c.name, "c", "c name is right")
+        self.assertEqual(ivar_c.type.name, "char *", "Right type")
+
+    def values_test(self, use_unknown):
+        (target, _, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", self.main_source_file
+        )
+
+        type_name = "struct $MyStruct"
+        value_name = "$my_struct"
+        self.expect("expr int $my_int = 100")
+        self.expect('expr char *$my_char_ptr = "Some char pointer."')
+        self.expect(f"expr {type_name} {{int a; int b;}}; {type_name} 
{value_name} = {{10, 20}}")
+
+        # Now try to find one:
+        if use_unknown:
+            language = lldb.eLanguageTypeUnknown
+        else:
+            language = lldb.eLanguageTypeC_plus_plus
+
+        value = target.FindExpressionVariableForLanguage(
+            value_name,
+            language
+        )
+        
+        self.assertTrue(value.IsValid(), "Got a valid SBValue")
+        self.assertTrue(value.GetError().Success(), "Got a value")
+
+        value_checker = ValueCheck(
+            name=value_name,
+            type=type_name,
+            children=[
+                ValueCheck(name="a", type="int", value='10'),
+                ValueCheck(name="b", type="int", value='20')
+            ]
+        )
+        value_checker.check_value(self, value, "Found the right value")
diff --git a/lldb/test/API/python_api/persistent_decls/main.c 
b/lldb/test/API/python_api/persistent_decls/main.c
new file mode 100644
index 0000000000000..31280778072e3
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/main.c
@@ -0,0 +1,6 @@
+int
+main()
+{
+  int test_var = 10; // Set a breakpoint here
+  return test_var;
+}

>From 5796a6c8a8abc5bbcaa9187da3b0a73ffeac15ba Mon Sep 17 00:00:00 2001
From: Jim Ingham <[email protected]>
Date: Thu, 11 Jun 2026 14:58:17 -0700
Subject: [PATCH 2/4] Formatting

---
 lldb/include/lldb/API/SBTarget.h              |  4 +--
 lldb/source/API/SBTarget.cpp                  | 20 +++++++--------
 .../persistent_decls/TestPersistentDecls.py   | 25 +++++++++----------
 .../API/python_api/persistent_decls/main.c    |  4 +--
 4 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 113c5db0331df..c9e04a5a2ec57 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -924,10 +924,10 @@ class LLDB_API SBTarget {
   lldb::SBType GetBasicType(lldb::BasicType type);
 
   lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
-      lldb::LanguageType lang);
+                                             lldb::LanguageType lang);
 
   lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
-      lldb::LanguageType lang);
+                                                  lldb::LanguageType lang);
 
   lldb::SBValue CreateValueFromAddress(const char *name, lldb::SBAddress addr,
                                        lldb::SBType type);
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 9ac6f06c9b840..cb2c0fc482a34 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1879,8 +1879,9 @@ lldb::SBSymbolContextList 
SBTarget::FindGlobalFunctions(const char *name,
   return sb_sc_list;
 }
 
-lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
-      lldb::LanguageType language) {
+lldb::SBType
+SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
+                                        lldb::LanguageType language) {
   TargetSP target_sp = GetSP();
   if (!target_sp)
     return {};
@@ -1899,8 +1900,8 @@ lldb::SBType 
SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
       PersistentExpressionState *persistent =
           target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
       if (persistent) {
-        std::optional<CompilerType> type_op
-          = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+        std::optional<CompilerType> type_op =
+            persistent->GetCompilerTypeFromPersistentDecl(const_typename);
         if (type_op) {
           return SBType(*type_op);
         }
@@ -1910,8 +1911,8 @@ lldb::SBType 
SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
     PersistentExpressionState *persistent =
         target_sp->GetPersistentExpressionStateForLanguage(language);
     if (persistent) {
-      std::optional<CompilerType> type_op
-        = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+      std::optional<CompilerType> type_op =
+          persistent->GetCompilerTypeFromPersistentDecl(const_typename);
       if (type_op && (*type_op)) {
         return SBType(*type_op);
       }
@@ -1920,8 +1921,9 @@ lldb::SBType 
SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
   return {};
 }
 
-lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
-    const char *varname_cstr, lldb::LanguageType language) {
+lldb::SBValue
+SBTarget::FindExpressionVariableForLanguage(const char *varname_cstr,
+                                            lldb::LanguageType language) {
   TargetSP target_sp = GetSP();
   if (!target_sp)
     return {};
@@ -1961,8 +1963,6 @@ lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
   return {};
 }
 
-
-
 lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
   LLDB_INSTRUMENT_VA(this, typename_cstr);
 
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py 
b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
index 1381a251bb9a8..e41b314a2bf94 100644
--- a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -29,20 +29,20 @@ def test_persistent_values(self):
         self.build()
         self.main_source_file = lldb.SBFileSpec("main.c")
         self.values_test(False)
-        
+
     def test_persistent_values_unknown(self):
         """Define some values in the expression evaluator and find them."""
         self.build()
         self.main_source_file = lldb.SBFileSpec("main.c")
         self.values_test(True)
-        
+
     def types_test(self, use_unknown):
         (target, _, _, _) = lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", self.main_source_file
         )
 
         # Make some types so we aren't succeeding in gettting the only one.
-        
+
         typename = "$firstStruct"
 
         self.expect(f"expr struct $SomeType {{ int b; int a; int c;}}")
@@ -54,7 +54,7 @@ def types_test(self, use_unknown):
             language = lldb.eLanguageTypeUnknown
         else:
             language = lldb.eLanguageTypeC_plus_plus
-        
+
         type = target.FindExpressionTypeForLanguage(typename, language)
         self.assertTrue(type.IsValid(), "Got a valid type")
 
@@ -84,7 +84,9 @@ def values_test(self, use_unknown):
         value_name = "$my_struct"
         self.expect("expr int $my_int = 100")
         self.expect('expr char *$my_char_ptr = "Some char pointer."')
-        self.expect(f"expr {type_name} {{int a; int b;}}; {type_name} 
{value_name} = {{10, 20}}")
+        self.expect(
+            f"expr {type_name} {{int a; int b;}}; {type_name} {value_name} = 
{{10, 20}}"
+        )
 
         # Now try to find one:
         if use_unknown:
@@ -92,11 +94,8 @@ def values_test(self, use_unknown):
         else:
             language = lldb.eLanguageTypeC_plus_plus
 
-        value = target.FindExpressionVariableForLanguage(
-            value_name,
-            language
-        )
-        
+        value = target.FindExpressionVariableForLanguage(value_name, language)
+
         self.assertTrue(value.IsValid(), "Got a valid SBValue")
         self.assertTrue(value.GetError().Success(), "Got a value")
 
@@ -104,8 +103,8 @@ def values_test(self, use_unknown):
             name=value_name,
             type=type_name,
             children=[
-                ValueCheck(name="a", type="int", value='10'),
-                ValueCheck(name="b", type="int", value='20')
-            ]
+                ValueCheck(name="a", type="int", value="10"),
+                ValueCheck(name="b", type="int", value="20"),
+            ],
         )
         value_checker.check_value(self, value, "Found the right value")
diff --git a/lldb/test/API/python_api/persistent_decls/main.c 
b/lldb/test/API/python_api/persistent_decls/main.c
index 31280778072e3..001333e92d9bf 100644
--- a/lldb/test/API/python_api/persistent_decls/main.c
+++ b/lldb/test/API/python_api/persistent_decls/main.c
@@ -1,6 +1,4 @@
-int
-main()
-{
+int main() {
   int test_var = 10; // Set a breakpoint here
   return test_var;
 }

>From 58a542486507882b4614fd883969d68597380c09 Mon Sep 17 00:00:00 2001
From: Jim Ingham <[email protected]>
Date: Mon, 15 Jun 2026 16:18:52 -0700
Subject: [PATCH 3/4] Don't use eLanguageTypeUnknown to search all languages. 
 There is only one possible variable/type per language, so I wanted to
 preserve the convenience of not having to go through a list to get the one
 thing it can hold.  And if you want to iterate over languages, that's easy to
 do from the outside. I was logging LanguageTypes a bunch and that got
 annoying so I also added a formatv adaptor for LanguageType.

---
 lldb/include/lldb/API/SBTarget.h              |   3 +-
 lldb/include/lldb/Target/Language.h           |   9 ++
 lldb/source/API/SBTarget.cpp                  | 118 +++++++++---------
 lldb/source/Target/Language.cpp               |   6 +
 .../persistent_decls/TestPersistentDecls.py   |  57 +++++----
 5 files changed, 108 insertions(+), 85 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index c9e04a5a2ec57..1c1bb1b501a0f 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -924,7 +924,8 @@ class LLDB_API SBTarget {
   lldb::SBType GetBasicType(lldb::BasicType type);
 
   lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
-                                             lldb::LanguageType lang);
+                                             lldb::LanguageType lang,
+                                             SBError &error);
 
   lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
                                                   lldb::LanguageType lang);
diff --git a/lldb/include/lldb/Target/Language.h 
b/lldb/include/lldb/Target/Language.h
index 9205b5e339977..5987ae373936f 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -24,6 +24,8 @@
 #include "lldb/Symbol/TypeSystem.h"
 #include "lldb/lldb-private.h"
 #include "lldb/lldb-public.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
 
 namespace lldb_private {
 
@@ -519,4 +521,11 @@ class Language : public PluginInterface {
 
 } // namespace lldb_private
 
+namespace llvm {
+  template <> struct format_provider<lldb::LanguageType> {
+  static void format(const lldb::LanguageType &language, llvm::raw_ostream &OS,
+                     llvm::StringRef Options);
+};
+} // namespace llvm
+
 #endif // LLDB_TARGET_LANGUAGE_H
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index cb2c0fc482a34..98525fd684eed 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1881,43 +1881,47 @@ lldb::SBSymbolContextList 
SBTarget::FindGlobalFunctions(const char *name,
 
 lldb::SBType
 SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
-                                        lldb::LanguageType language) {
+                                        lldb::LanguageType language,
+                                        SBError &sb_error) {
+  sb_error.Clear();
+
   TargetSP target_sp = GetSP();
-  if (!target_sp)
+  if (!target_sp) {
+    sb_error.SetErrorString("no target.");
     return {};
+  }
 
-  if (!typename_cstr || !typename_cstr[0])
+  if (!typename_cstr || !typename_cstr[0]) {
+    sb_error.SetErrorString("empty type name for search.");
     return {};
+  }
+
+  if (language == eLanguageTypeUnknown) {
+    sb_error.SetErrorString("eLanguageTypeUnknown can't define expression "
+        "types.");
+    return {};
+  }
 
   ConstString const_typename(typename_cstr);
 
-  // If the language type was "unknown" search all languages:
-  if (language == lldb::eLanguageTypeUnknown) {
-    LanguageSet expr_languages =
-        Language::GetLanguagesSupportingTypeSystemsForExpressions();
-    for (int bit : expr_languages.bitvector.set_bits()) {
-      auto cur_lang = (LanguageType)bit;
-      PersistentExpressionState *persistent =
-          target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
-      if (persistent) {
-        std::optional<CompilerType> type_op =
-            persistent->GetCompilerTypeFromPersistentDecl(const_typename);
-        if (type_op) {
-          return SBType(*type_op);
-        }
-      }
-    }
-  } else {
-    PersistentExpressionState *persistent =
-        target_sp->GetPersistentExpressionStateForLanguage(language);
-    if (persistent) {
-      std::optional<CompilerType> type_op =
-          persistent->GetCompilerTypeFromPersistentDecl(const_typename);
-      if (type_op && (*type_op)) {
-        return SBType(*type_op);
-      }
-    }
+  PersistentExpressionState *persistent =
+      target_sp->GetPersistentExpressionStateForLanguage(language);
+
+  if (!persistent) {
+    sb_error.SetErrorString(llvm::formatv(
+        "language {0} does not support expression defined types",
+        language).str().c_str());
+    return {};
   }
+
+  std::optional<CompilerType> type_op =
+      persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+  if (type_op && (*type_op)) {
+    return SBType(*type_op);
+  }
+  sb_error.SetErrorString(llvm::formatv(
+      "no type {0} found in expression types for language {1}",
+      typename_cstr, language).str().c_str());
   return {};
 }
 
@@ -1926,41 +1930,41 @@ SBTarget::FindExpressionVariableForLanguage(const char 
*varname_cstr,
                                             lldb::LanguageType language) {
   TargetSP target_sp = GetSP();
   if (!target_sp)
-    return {};
+    return ValueObjectConstResult::Create(nullptr,
+        Status::FromErrorStringWithFormatv(
+          "no variable {0} found for language {1}",
+          varname_cstr, language));
+
 
   if (!varname_cstr || !varname_cstr[0])
-    return {};
+    return ValueObjectConstResult::Create(target_sp.get(),
+       Status::FromErrorString("empty variable name for search."));
+
+  if (language == eLanguageTypeUnknown)
+    return ValueObjectConstResult::Create(nullptr,
+        Status::FromErrorStringWithFormatv(
+          "eLanguageTypeUnknown doesn't support expression variables.",
+          varname_cstr, language));
 
   ConstString const_varname(varname_cstr);
 
-  // If the language type was "unknown" search all languages:
-  if (language == lldb::eLanguageTypeUnknown) {
-    LanguageSet expr_languages =
-        Language::GetLanguagesSupportingTypeSystemsForExpressions();
-    for (int bit : expr_languages.bitvector.set_bits()) {
-      auto cur_lang = (LanguageType)bit;
-      PersistentExpressionState *persistent =
-          target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
-      if (persistent) {
-        lldb::ExpressionVariableSP expr_var_sp =
-            persistent->GetVariable(const_varname);
-        if (expr_var_sp) {
-          return expr_var_sp->GetValueObject();
-        }
-      }
-    }
-  } else {
-    PersistentExpressionState *persistent =
+  PersistentExpressionState *persistent =
         target_sp->GetPersistentExpressionStateForLanguage(language);
-    if (persistent) {
-      lldb::ExpressionVariableSP expr_var_sp =
-          persistent->GetVariable(const_varname);
-      if (expr_var_sp) {
-        return expr_var_sp->GetValueObject();
-      }
-    }
+  if (!persistent) {
+    return ValueObjectConstResult::Create(target_sp.get(),
+        Status::FromErrorStringWithFormatv(
+            "language: {0} doesn't support expression variables.", language));
   }
-  return {};
+
+  lldb::ExpressionVariableSP expr_var_sp =
+      persistent->GetVariable(const_varname);
+  if (expr_var_sp)
+    return expr_var_sp->GetValueObject();
+
+  return ValueObjectConstResult::Create(target_sp.get(),
+      Status::FromErrorStringWithFormatv(
+          "no variable {0} found for language {1}", varname_cstr, language));
+
 }
 
 lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 03754e988faa4..077c403f4ea58 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -631,3 +631,9 @@ bool SourceLanguage::IsObjC() const {
 bool SourceLanguage::IsCPlusPlus() const {
   return name == llvm::dwarf::DW_LNAME_C_plus_plus;
 }
+
+void llvm::format_provider<lldb::LanguageType>::format(
+    const lldb::LanguageType &language, llvm::raw_ostream &OS,
+    llvm::StringRef Options) {
+  OS << Language::GetNameForLanguageType(language);
+}
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py 
b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
index e41b314a2bf94..531366a3e96be 100644
--- a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -16,27 +16,15 @@ def test_persistent_types(self):
         """Define some types in the expression evaluator and find them."""
         self.build()
         self.main_source_file = lldb.SBFileSpec("main.c")
-        self.types_test(False)
-
-    def test_persistent_types_unknown(self):
-        """Define some types in the expression evaluator and find them."""
-        self.build()
-        self.main_source_file = lldb.SBFileSpec("main.c")
-        self.types_test(True)
+        self.types_test()
 
     def test_persistent_values(self):
         """Define some values in the expression evaluator and find them."""
         self.build()
         self.main_source_file = lldb.SBFileSpec("main.c")
-        self.values_test(False)
-
-    def test_persistent_values_unknown(self):
-        """Define some values in the expression evaluator and find them."""
-        self.build()
-        self.main_source_file = lldb.SBFileSpec("main.c")
-        self.values_test(True)
+        self.values_test()
 
-    def types_test(self, use_unknown):
+    def types_test(self):
         (target, _, _, _) = lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", self.main_source_file
         )
@@ -50,12 +38,10 @@ def types_test(self, use_unknown):
         self.expect(f"expr struct $AnotherType {{ int a; char *b; int c;}}")
         self.expect(f"expr struct $YetAnotherType {{ char *a; int b; int c;}}")
 
-        if use_unknown:
-            language = lldb.eLanguageTypeUnknown
-        else:
-            language = lldb.eLanguageTypeC_plus_plus
-
-        type = target.FindExpressionTypeForLanguage(typename, language)
+        language = lldb.eLanguageTypeC_plus_plus
+        error = lldb.SBError()
+        type = target.FindExpressionTypeForLanguage(typename, language, error)
+        self.assertSuccess(error, "Got the right error")
         self.assertTrue(type.IsValid(), "Got a valid type")
 
         # Make sure we got the type we expected:
@@ -75,7 +61,18 @@ def types_test(self, use_unknown):
         self.assertEqual(ivar_c.name, "c", "c name is right")
         self.assertEqual(ivar_c.type.name, "char *", "Right type")
 
-    def values_test(self, use_unknown):
+        # Also test the error returns:
+        #type = target.FindExpressionTypeForLanguage(typename, 
lldb.eLanguageTypeUnknown, error)
+        #self.assertFalse(error, "unknown doesn't support expression types")
+        #self.assertFalse(type.IsValid(), "Type is also invalid.")
+        type = target.FindExpressionTypeForLanguage("", language, error)
+        self.assertFalse(error.Success(), "empty type name for search.")
+        self.assertFalse(type.IsValid(), "Type is also invalid.")
+        type = 
target.FindExpressionTypeForLanguage("doesnt_start_with_dollar", language, 
error)
+        self.assertFalse(error.Success(), "Can't find names that don't exist.")
+        self.assertFalse(type.IsValid(), "Type is also invalid.")
+        
+    def values_test(self):
         (target, _, _, _) = lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", self.main_source_file
         )
@@ -89,15 +86,12 @@ def values_test(self, use_unknown):
         )
 
         # Now try to find one:
-        if use_unknown:
-            language = lldb.eLanguageTypeUnknown
-        else:
-            language = lldb.eLanguageTypeC_plus_plus
+        language = lldb.eLanguageTypeC_plus_plus
 
         value = target.FindExpressionVariableForLanguage(value_name, language)
 
         self.assertTrue(value.IsValid(), "Got a valid SBValue")
-        self.assertTrue(value.GetError().Success(), "Got a value")
+        self.assertSuccess(value.GetError(), "Got no errors")
 
         value_checker = ValueCheck(
             name=value_name,
@@ -108,3 +102,12 @@ def values_test(self, use_unknown):
             ],
         )
         value_checker.check_value(self, value, "Found the right value")
+
+        # Also test that errors are set correctly:
+        value = target.FindExpressionVariableForLanguage(value_name, 
lldb.eLanguageTypeUnknown)
+        self.assertFalse(value.error.Success(), "unknown can't compile 
expressions")
+        value = target.FindExpressionVariableForLanguage(None, language)
+        self.assertFalse(value.error.Success(), "reject empty expression 
variable name")
+        value = 
target.FindExpressionVariableForLanguage("doesnt_start_with_dollar", language)
+        self.assertFalse(value.error.Success(), "error on unknown variable 
name")
+        

>From d4f944aacde4d2947b3eb651341f5880d6597a44 Mon Sep 17 00:00:00 2001
From: Jim Ingham <[email protected]>
Date: Mon, 15 Jun 2026 16:45:42 -0700
Subject: [PATCH 4/4] Add LLDB_INSTRUMENT_VA macros to SBTarget additions.

---
 lldb/source/API/SBTarget.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 98525fd684eed..356279513ac7a 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1883,6 +1883,7 @@ lldb::SBType
 SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
                                         lldb::LanguageType language,
                                         SBError &sb_error) {
+  LLDB_INSTRUMENT_VA(this, typename_cstr, language, sb_error);
   sb_error.Clear();
 
   TargetSP target_sp = GetSP();
@@ -1928,6 +1929,7 @@ SBTarget::FindExpressionTypeForLanguage(const char 
*typename_cstr,
 lldb::SBValue
 SBTarget::FindExpressionVariableForLanguage(const char *varname_cstr,
                                             lldb::LanguageType language) {
+  LLDB_INSTRUMENT_VA(this, varname_cstr, language);
   TargetSP target_sp = GetSP();
   if (!target_sp)
     return ValueObjectConstResult::Create(nullptr,

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

Reply via email to