Skip to content

Commit 97bb2d8

Browse files
committed
[lldb] Mark parsing Swift expressions with generics as not cacheable
Because a Swift expression may have different generic instantiations in different invocations, we cannot cache the parsing of them.
1 parent f3aa765 commit 97bb2d8

File tree

5 files changed

+59
-9
lines changed

5 files changed

+59
-9
lines changed

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,16 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
17241724
return ParseResult::unrecoverable_error;
17251725
}
17261726

1727+
{
1728+
// If any generics are present, this expression is not parseable.
1729+
m_is_cacheable =
1730+
!llvm::any_of(parsed_expr->code_manipulator->GetVariableInfo(),
1731+
[](const auto &variable) {
1732+
return variable.IsMetadataPointer() ||
1733+
variable.IsPackCount() ||
1734+
variable.IsUnboundPack();
1735+
});
1736+
}
17271737
auto dumpModule = [&](const char *msg) {
17281738
std::string s;
17291739
llvm::raw_string_ostream ss(s);

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ class SwiftExpressionParser : public ExpressionParser {
9797
ParseResult Parse(DiagnosticManager &diagnostic_manager,
9898
uint32_t first_line = 0, uint32_t last_line = UINT32_MAX);
9999

100+
/// Returns true if the call to parse of this type is cacheable.
101+
bool IsParseCacheable() const {
102+
return m_is_cacheable;
103+
}
104+
100105
//------------------------------------------------------------------
101106
/// Ready an already-parsed expression for execution, possibly
102107
/// evaluating it statically.
@@ -198,6 +203,9 @@ class SwiftExpressionParser : public ExpressionParser {
198203

199204
/// If true, we are running in REPL mode
200205
EvaluateExpressionOptions m_options;
206+
207+
/// Indicates whether the call to Parse of this type is cacheable.
208+
bool m_is_cacheable;
201209
};
202210
} // namespace lldb_private
203211

lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class SwiftUserExpression : public LLVMUserExpression {
138138
void WillStartExecuting() override;
139139
void DidFinishExecuting() override;
140140

141+
bool IsParseCacheable() override {
142+
return m_parser->IsParseCacheable();
143+
}
144+
141145
private:
142146
//------------------------------------------------------------------
143147
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the

lldb/test/API/lang/swift/archetype_in_cond_breakpoint/TestArchetypeInConditionalBreakpoint.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,45 @@
66

77

88
class TestArchetypeInConditionalBreakpoint(TestBase):
9+
@swiftTest
10+
def test_stops_free_function(self):
11+
self.stops("break here for free function")
12+
13+
@swiftTest
14+
def test_doesnt_stop_free_function(self):
15+
self.doesnt_stop("break here for free function")
16+
17+
@swiftTest
18+
def test_stops_class(self):
19+
self.stops("break here for class")
920

1021
@swiftTest
11-
def test_stops(self):
22+
def test_doesnt_stop_class(self):
23+
self.doesnt_stop("break here for class")
24+
25+
def stops(self, breakpoint_string):
1226
"""Tests that using archetypes in a conditional breakpoint's expression works correctly"""
1327
self.build()
1428
target = lldbutil.run_to_breakpoint_make_target(self)
1529

1630
breakpoint = target.BreakpointCreateBySourceRegex(
17-
"break here", lldb.SBFileSpec("main.swift"))
31+
breakpoint_string, lldb.SBFileSpec("main.swift")
32+
)
1833

1934
breakpoint.SetCondition("T.self == Int.self")
2035
_, process, _, _ = lldbutil.run_to_breakpoint_do_run(self, target, breakpoint)
21-
22-
self.assertEqual(process.state, lldb.eStateStopped)
2336

37+
self.assertEqual(process.state, lldb.eStateStopped)
38+
self.expect("expression T.self", substrs=["Int"])
2439

25-
@swiftTest
26-
def test_doesnt_stop(self):
40+
def doesnt_stop(self, breakpoint_string):
2741
"""Tests that using archetypes in a conditional breakpoint's expression works correctly"""
2842
self.build()
2943
target = lldbutil.run_to_breakpoint_make_target(self)
3044

3145
breakpoint = target.BreakpointCreateBySourceRegex(
32-
"break here", lldb.SBFileSpec("main.swift"))
46+
breakpoint_string, lldb.SBFileSpec("main.swift")
47+
)
3348

3449
breakpoint.SetCondition("T.self == Double.self")
3550

@@ -41,4 +56,3 @@ def test_doesnt_stop(self):
4156

4257
# Make sure that we didn't stop since the condition doesn't match
4358
self.assertEqual(process.state, lldb.eStateExited)
44-
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1+
12
func f<T>(t: T) {
2-
print(1) // break here
3+
print(1) // break here for free function
34
}
5+
f(t: "This is a string")
6+
f(t: "This is another string")
7+
f(t: true)
48
f(t: 5)
9+
10+
class MyClass<T> {
11+
func f() {
12+
print(1) // break here for class
13+
}
14+
}
15+
MyClass<String>().f()
16+
MyClass<String>().f()
17+
MyClass<Bool>().f()
18+
MyClass<Int>().f()

0 commit comments

Comments
 (0)