[Lldb-commits] [lldb] [lldb] Treat `__this` from CodeView/PDB as captured `this` (PR #200271)

via lldb-commits lldb-commits at lists.llvm.org
Thu May 28 13:55:30 PDT 2026


https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/200271

When building with CodeView/PDB, the captured `this` parameter in a lambda is named `__this` instead of `this` (for clang, see [`CGDebugInfo::GetLambdaCaptureName`](https://github.com/llvm/llvm-project/blob/23776bd325ec951781923a638ad632e4126b30ea/clang/lib/CodeGen/CGDebugInfo.cpp#L2064)).

In this PR, I added lookups for `__this`. This change will make the success cases in `TestExprInsideLambdas.py` pass. The only difference with CodeView/PDB is that the errors show "use of undeclared identifier" instead of "use of non-static data member" because the lambda object isn't a nested type here.

Fixes #71837.

>From 207a2580d2a4ad030693c412e9b387b4fb640bbc Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Fri, 22 May 2026 15:17:42 +0200
Subject: [PATCH] [lldb] Treat `__this` from CodeView/PDB as captured `this`

---
 .../Clang/ClangExpressionDeclMap.cpp          |  6 +++-
 .../Clang/ClangExpressionSourceCode.cpp       | 13 +++++---
 .../Clang/ClangExpressionUtil.cpp             |  6 +++-
 .../Clang/ClangUserExpression.cpp             |  5 +--
 .../TestExprInsideLambdas.py                  | 33 ++++++++++++++++---
 5 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 1b873161120e7..2278e30d562ef 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -75,9 +75,13 @@ namespace {
 lldb::ValueObjectSP GetCapturedThisValueObject(StackFrame *frame) {
   assert(frame);
 
-  if (auto thisValSP = frame->FindVariable(ConstString("this")))
+  if (auto thisValSP = frame->FindVariable(ConstString("this"))) {
     if (auto thisThisValSP = thisValSP->GetChildMemberWithName("this"))
       return thisThisValSP;
+    // With CodeView/PDB, the member is named "__this".
+    if (auto codeview_this_sp = thisValSP->GetChildMemberWithName("__this"))
+      return codeview_this_sp;
+  }
 
   return nullptr;
 }
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index a856dc5897c01..b4af99c0e80f8 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -199,11 +199,14 @@ static clang::Qualifiers GetFrameCVQualifiers(StackFrame *frame) {
   if (!this_sp)
     return {};
 
-  // Lambdas that capture 'this' have a member variable called 'this'. The class
-  // context of __lldb_expr for a lambda is the class type of the 'this' capture
-  // (not the anonymous lambda structure). So use the qualifiers of the captured
-  // 'this'.
-  if (auto this_this_sp = this_sp->GetChildMemberWithName("this"))
+  // Lambdas that capture 'this' have a member variable called 'this' (DWARF) /
+  // '__this' (CodeView). The class context of __lldb_expr for a lambda is the
+  // class type of the 'this' capture (not the anonymous lambda structure). So
+  // use the qualifiers of the captured 'this'.
+  auto this_this_sp = this_sp->GetChildMemberWithName("this");
+  if (!this_this_sp)
+    this_this_sp = this_sp->GetChildMemberWithName("__this");
+  if (this_this_sp)
     return clang::Qualifiers::fromCVRMask(
         this_this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers());
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
index d4b2775b8c039..0b3b85dccdba8 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
@@ -17,9 +17,13 @@ namespace ClangExpressionUtil {
 lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame) {
   assert(frame);
 
-  if (auto this_val_sp = frame->FindVariable(ConstString("this")))
+  if (auto this_val_sp = frame->FindVariable(ConstString("this"))) {
     if (this_val_sp->GetChildMemberWithName("this"))
       return this_val_sp;
+    // With CodeView/PDB, the member is named "__this".
+    if (this_val_sp->GetChildMemberWithName("__this"))
+      return this_val_sp;
+  }
 
   return nullptr;
 }
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index ff158f4c99301..b7ebb6dfd5551 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -857,9 +857,10 @@ lldb::addr_t ClangUserExpression::GetCppObjectPointer(
   // We're inside a C++ class method. This could potentially be an unnamed
   // lambda structure. If the lambda captured a "this", that should be
   // the object pointer.
-  if (auto thisChildSP = valobj_sp->GetChildMemberWithName("this")) {
+  if (auto thisChildSP = valobj_sp->GetChildMemberWithName("this"))
     valobj_sp = thisChildSP;
-  }
+  else if (auto cv_this_child_sp = valobj_sp->GetChildMemberWithName("__this"))
+    valobj_sp = cv_this_child_sp;
 
   if (!err.Success() || !valobj_sp.get())
     return LLDB_INVALID_ADDRESS;
diff --git a/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py b/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
index 2aab83c50b716..f284dbc206b65 100644
--- a/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
+++ b/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
@@ -12,6 +12,9 @@
 
 @skipIfWasm  # no expression evaluation
 class ExprInsideLambdaTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+    SHARED_BUILD_TESTCASE = False
+
     def expectExprError(self, expr: str, expected: str):
         frame = self.thread.GetFrameAtIndex(0)
         value = frame.EvaluateExpression(expr)
@@ -112,18 +115,32 @@ def test_expr_inside_lambda(self):
         # Check access to outer top-level structure's members
         self.expectExprError(
             "class_var",
-            ("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
+            (
+                "use of undeclared identifier"
+                if self.getDebugInfo() == "pdb"
+                else (
+                    "use of non-static data member 'class_var' of 'Foo' from nested type"
+                )
+            ),
         )
 
         self.expectExprError(
-            "base_var", ("use of non-static data member" " 'base_var'")
+            "base_var",
+            (
+                "use of undeclared identifier"
+                if self.getDebugInfo() == "pdb"
+                else ("use of non-static data member 'base_var'")
+            ),
         )
 
         self.expectExprError(
             "local_var",
             (
-                "use of non-static data member 'local_var'"
-                " of '(unnamed class)' from nested type 'LocalLambdaClass'"
+                "use of undeclared identifier"
+                if self.getDebugInfo() == "pdb"
+                else (
+                    "use of non-static data member 'local_var' of '(unnamed class)' from nested type 'LocalLambdaClass'"
+                )
             ),
         )
 
@@ -135,5 +152,11 @@ def test_expr_inside_lambda(self):
 
         self.expectExprError(
             "class_var",
-            ("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
+            (
+                "use of undeclared identifier"
+                if self.getDebugInfo() == "pdb"
+                else (
+                    "use of non-static data member 'class_var' of 'Foo' from nested type"
+                )
+            ),
         )



More information about the lldb-commits mailing list