1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
""" Test that evaluating expressions from within C++ lambdas works
Particularly, we test the case of capturing "this" and
using members of the captured object in expression evaluation
while we're on a breakpoint inside a lambda.
"""
import lldb
from lldbsuite.test.lldbtest import *
class ExprInsideLambdaTestCase(TestBase):
def expectExprError(self, expr: str, expected: str):
frame = self.thread.GetFrameAtIndex(0)
value = frame.EvaluateExpression(expr)
errmsg = value.GetError().GetCString()
self.assertIn(expected, errmsg)
def test_expr_inside_lambda(self):
"""Test that lldb evaluating expressions inside lambda expressions works correctly."""
self.build()
(target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
# Inside 'Foo::method'
# Check access to captured 'this'
self.expect_expr("class_var", result_type="int", result_value="109")
self.expect_expr("this->class_var", result_type="int", result_value="109")
# Check that captured shadowed variables take preference over the
# corresponding member variable
self.expect_expr("shadowed", result_type="int", result_value="5")
self.expect_expr("this->shadowed", result_type="int", result_value="-137")
# Check access to local captures
self.expect_expr("local_var", result_type="int", result_value="137")
self.expect_expr("*class_ptr", result_type="int", result_value="137")
# Check access to base class variables
self.expect_expr("base_var", result_type="int", result_value="14")
self.expect_expr("base_base_var", result_type="int", result_value="11")
# Check access to global variable
self.expect_expr("global_var", result_type="int", result_value="-5")
# Check access to multiple captures/member variables
self.expect_expr(
"(shadowed + this->shadowed) * (base_base_var + local_var - class_var)",
result_type="int",
result_value="-5148",
)
# Check base-class function call
self.expect_expr("baz_virt()", result_type="int", result_value="2")
self.expect_expr("base_var", result_type="int", result_value="14")
self.expect_expr("this->shadowed", result_type="int", result_value="-1")
# 'p this' should yield 'struct Foo*'
frame = self.thread.GetFrameAtIndex(0)
outer_class_addr = frame.GetValueForVariablePath("this->this")
self.expect_expr("this", result_value=outer_class_addr.GetValue())
lldbutil.continue_to_breakpoint(process, bkpt)
# Inside 'nested_lambda'
# Check access to captured 'this'. Should still be 'struct Foo*'
self.expect_expr("class_var", result_type="int", result_value="109")
self.expect_expr("global_var", result_type="int", result_value="-5")
self.expect_expr("this", result_value=outer_class_addr.GetValue())
# Check access to captures
self.expect_expr("lambda_local_var", result_type="int", result_value="5")
self.expect_expr("local_var", result_type="int", result_value="137")
# Check access to variable in previous frame which we didn't capture
self.expectExprError("local_var_copy", "use of undeclared identifier")
lldbutil.continue_to_breakpoint(process, bkpt)
# By-ref mutates source variable
self.expect_expr("lambda_local_var", result_type="int", result_value="0")
# By-value doesn't mutate source variable
self.expect_expr("local_var_copy", result_type="int", result_value="136")
self.expect_expr("local_var", result_type="int", result_value="137")
lldbutil.continue_to_breakpoint(process, bkpt)
# Inside 'LocalLambdaClass::inner_method'
# Check access to captured 'this'
self.expect_expr("lambda_class_local", result_type="int", result_value="-12345")
self.expect_expr(
"this->lambda_class_local", result_type="int", result_value="-12345"
)
self.expect_expr("outer_ptr->class_var", result_type="int", result_value="109")
# 'p this' should yield 'struct LocalLambdaClass*'
frame = self.thread.GetFrameAtIndex(0)
local_class_addr = frame.GetValueForVariablePath("this->this")
self.assertNotEqual(local_class_addr, outer_class_addr)
self.expect_expr("this", result_value=local_class_addr.GetValue())
# Can still access global variable
self.expect_expr("global_var", result_type="int", result_value="-5")
# 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"),
)
self.expectExprError(
"base_var", ("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'"
),
)
# Inside non_capturing_method
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect_expr("local", result_type="int", result_value="5")
self.expect_expr("local2", result_type="int", result_value="10")
self.expect_expr("local2 * local", result_type="int", result_value="50")
self.expectExprError(
"class_var",
("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
)
|