[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