Skip to content

Commit b9e473c

Browse files
[lldb] Fix GetParentIfClosure for async closures inside non-async functions
When computing the name of the parent function of a closure, LLDB takes the demangled parent function Node and replaces it on the top level "Global" demangle node. However, this logic was faulty in two ways: 1. A misplaced return made the "replace logic" only look at the fist child of the Global node. 2. The new Global node was inheriting _all_ children from the original Global node, which is wrong. For example, an async closure inside a non-async function would have this demangle tree: ``` Global <Async Attributes> <Explicit Closure> <Parent Function> ``` By replacing the `Explicit Closure` with `Parent Function`, we were creating another async function. The solution is to just create the Global node from scratch, dropping most other nodes it may have had. This begs the question of which other nodes could be there as a sibling of the closure in the tree; given how none of the existing tests failed with this patch, it seems safe to assume any such nodes are not too important (until proven otherwise).
1 parent 4a62991 commit b9e473c

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,16 +1600,38 @@ std::string SwiftLanguageRuntime::GetParentNameIfClosure(Function &func) {
16001600
swift_demangle::GetFirstChildOfKind(closure_node, function_kinds);
16011601
if (!parent_func_node)
16021602
return "";
1603-
swift_demangle::ReplaceChildWith(*node, *closure_node, *parent_func_node);
16041603

1605-
ManglingErrorOr<std::string> mangled = swift::Demangle::mangleNode(node);
1604+
NodeFactory factory;
1605+
Node *new_global = factory.createNode(Kind::Global);
1606+
if (!new_global)
1607+
return "";
1608+
// For a given function-like node, async information is a sibling - not a
1609+
// child - of the node in the demangling tree. Bring that over as well.
1610+
// Don't bring all children, however, as the closure number of `closure_node`
1611+
// is also a child of `closure_node`, i.e., it is not related to
1612+
// `parent_func_node`.
1613+
//
1614+
// node (Global)
1615+
// |
1616+
// |- closure_node
1617+
// |- parent_func_node (any function_kind)
1618+
// |- async info for parent_func_node
1619+
// |- closure number for closure_node
1620+
for (auto *child : *closure_node)
1621+
if (child->getKind() == Kind::AsyncAwaitResumePartialFunction ||
1622+
child->getKind() == Kind::AsyncSuspendResumePartialFunction)
1623+
new_global->addChild(child, factory);
1624+
new_global->addChild(parent_func_node, factory);
1625+
1626+
ManglingErrorOr<std::string> mangled =
1627+
swift::Demangle::mangleNode(new_global);
16061628
if (!mangled.isSuccess())
16071629
return "";
16081630

16091631
if (parent_func_node->getKind() == Kind::Constructor)
16101632
if (Module *module = func.CalculateSymbolContextModule().get())
1611-
return HandleCtorAndAllocatorVariants(mangled.result(), *module, *node,
1612-
*parent_func_node);
1633+
return HandleCtorAndAllocatorVariants(mangled.result(), *module,
1634+
*new_global, *parent_func_node);
16131635
return mangled.result();
16141636
}
16151637
} // namespace lldb_private

lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ inline NodePointer GetFirstChildOfKind(NodePointer node,
4141
inline void ReplaceChildWith(Node &parent, Node &to_replace, Node &new_child) {
4242
for (unsigned idx = 0; idx < parent.getNumChildren(); idx++) {
4343
auto *child = parent.getChild(idx);
44-
if (child == &to_replace)
44+
if (child == &to_replace) {
4545
parent.replaceChild(idx, &new_child);
46-
return;
46+
return;
47+
}
4748
}
4849
llvm_unreachable("invalid child passed to replaceChildWith");
4950
}

lldb/test/API/lang/swift/closures_var_not_captured/TestSwiftClosureVarNotCaptured.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,18 @@ def test_async_closure(self):
106106
)
107107
check_no_enhanced_diagnostic(self, thread.frames[0], "dont_find_me")
108108

109+
@swiftTest
110+
# Async variable inspection on Linux/Windows are still problematic.
111+
@skipIf(oslist=["windows", "linux"])
112+
def test_task_inside_non_async_func(self):
113+
self.build()
114+
(target, process, thread) = self.get_to_bkpt(
115+
"break_task_inside_non_async_function"
116+
)
117+
check_not_captured_error(
118+
self, thread.frames[0], "x", "task_inside_non_async_function()"
119+
)
120+
109121
@swiftTest
110122
def test_ctor_class_closure(self):
111123
self.build()

lldb/test/API/lang/swift/closures_var_not_captured/main.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,18 @@ enum MY_ENUM {
212212
}
213213
}
214214

215+
func async_foo() async {}
216+
217+
func task_inside_non_async_function() -> Task<Void, Never> {
218+
var x = 10;
219+
var task = Task {
220+
await async_foo()
221+
print("break_task_inside_non_async_function")
222+
}
223+
224+
return task
225+
}
226+
215227
func_1(arg: 42)
216228
func_2(arg: 42)
217229
await func_3(arg: 42)
@@ -227,3 +239,4 @@ my_struct.struct_computed_property = 10
227239
my_struct.struct_computed_property_didset = 10
228240
let _ = MY_ENUM(input: [1,2])
229241
MY_ENUM.static_func(input_static: [42])
242+
await task_inside_non_async_function().getResult()

0 commit comments

Comments
 (0)