Skip to content

Commit 070d386

Browse files
Merge pull request #7493 from augusto2112/5.9-dont-cache-parse
[lldb] Mark parsing Swift expressions with generics as not cacheable
2 parents b3da2fc + dcba156 commit 070d386

File tree

7 files changed

+60
-6
lines changed

7 files changed

+60
-6
lines changed

lldb/include/lldb/Expression/UserExpression.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ class UserExpression : public Expression {
192192
/// expression. Text() should contain the definition of this function.
193193
const char *FunctionName() override { return "$__lldb_expr"; }
194194

195+
/// Returns whether the call to Parse on this user expression is cacheable.
196+
virtual bool IsParseCacheable() { return true; }
195197
/// Return the language that should be used when parsing. To use the
196198
/// default, return eLanguageTypeUnknown.
197199
lldb::LanguageType Language() const override { return m_language; }

lldb/source/Breakpoint/BreakpointLocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
250250
DiagnosticManager diagnostics;
251251

252252
if (condition_hash != m_condition_hash || !m_user_expression_sp ||
253+
!m_user_expression_sp->IsParseCacheable() ||
253254
!m_user_expression_sp->MatchesContext(exe_ctx)) {
254255
LanguageType language = eLanguageTypeUnknown;
255256
// See if we can figure out the language from the frame, otherwise use the

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

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

1728+
// If any generics are present, this expression is not parseable.
1729+
if (parsed_expr->code_manipulator)
1730+
m_is_cacheable =
1731+
!llvm::any_of(parsed_expr->code_manipulator->GetVariableInfo(),
1732+
[](const auto &variable) {
1733+
return variable.IsMetadataPointer() ||
1734+
variable.IsPackCount() ||
1735+
variable.IsUnboundPack();
1736+
});
1737+
17281738
auto dumpModule = [&](const char *msg) {
17291739
std::string s;
17301740
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
@@ -139,6 +139,10 @@ class SwiftUserExpression : public LLVMUserExpression {
139139
void WillStartExecuting() override;
140140
void DidFinishExecuting() override;
141141

142+
bool IsParseCacheable() override {
143+
return m_parser->IsParseCacheable();
144+
}
145+
142146
private:
143147
//------------------------------------------------------------------
144148
/// 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: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,43 @@
77

88
class TestArchetypeInConditionalBreakpoint(TestBase):
99
@swiftTest
10-
def test_stops(self):
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")
20+
21+
@swiftTest
22+
def test_doesnt_stop_class(self):
23+
self.doesnt_stop("break here for class")
24+
25+
def stops(self, breakpoint_string):
1126
"""Tests that using archetypes in a conditional breakpoint's expression works correctly"""
1227
self.build()
1328
target = lldbutil.run_to_breakpoint_make_target(self)
1429

1530
breakpoint = target.BreakpointCreateBySourceRegex(
16-
"break here", lldb.SBFileSpec("main.swift")
31+
breakpoint_string, lldb.SBFileSpec("main.swift")
1732
)
1833

1934
breakpoint.SetCondition("T.self == Int.self")
2035
_, process, _, _ = lldbutil.run_to_breakpoint_do_run(self, target, breakpoint)
2136

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

24-
@swiftTest
25-
def test_doesnt_stop(self):
40+
def doesnt_stop(self, breakpoint_string):
2641
"""Tests that using archetypes in a conditional breakpoint's expression works correctly"""
2742
self.build()
2843
target = lldbutil.run_to_breakpoint_make_target(self)
2944

3045
breakpoint = target.BreakpointCreateBySourceRegex(
31-
"break here", lldb.SBFileSpec("main.swift")
46+
breakpoint_string, lldb.SBFileSpec("main.swift")
3247
)
3348

3449
breakpoint.SetCondition("T.self == Double.self")
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)