Skip to content

Commit b337360

Browse files
committed
[Sema] DebuggerTestingTransform: avoid re-using AST nodes in generated code
While building a closure to inject `checkExpect` code, clone member references associated with assignment. Re-using AST nodes is generally invalid. This is visible with multi-statement closure inference enabled, because the body is type-checked together with enclosing context and both elements end up sharing `DeclRefExpr` and `MemberRefExpr`s.
1 parent a6755f1 commit b337360

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

Diff for: lib/Sema/DebuggerTestingTransform.cpp

+43
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,49 @@ class DebuggerTestingTransform : public ASTWalker {
208208
auto *PODeclRef = new (Ctx)
209209
UnresolvedDeclRefExpr(StringForPrintObjectName,
210210
DeclRefKind::Ordinary, DeclNameLoc());
211+
212+
std::function<DeclRefExpr *(DeclRefExpr *)> cloneDeclRef =
213+
[&](DeclRefExpr *DRE) {
214+
auto *ref = new (Ctx) DeclRefExpr(
215+
DRE->getDeclRef(),
216+
/*Loc=*/DeclNameLoc(),
217+
/*Implicit=*/true, DRE->getAccessSemantics(), DRE->getType());
218+
219+
if (auto hopTarget = DRE->isImplicitlyAsync())
220+
ref->setImplicitlyAsync(*hopTarget);
221+
222+
ref->setImplicitlyThrows(DRE->isImplicitlyThrows());
223+
224+
return ref;
225+
};
226+
227+
std::function<MemberRefExpr *(MemberRefExpr *)> cloneMemberRef =
228+
[&](MemberRefExpr *M) {
229+
auto *base = M->getBase();
230+
231+
if (auto *DRE = dyn_cast<DeclRefExpr>(base))
232+
base = cloneDeclRef(DRE);
233+
else if (auto *M = dyn_cast<MemberRefExpr>(base))
234+
base = cloneMemberRef(M);
235+
236+
auto *ref = new (Ctx)
237+
MemberRefExpr(base, /*dotLoc=*/SourceLoc(), M->getDecl(),
238+
/*loc=*/DeclNameLoc(),
239+
/*Implicit=*/true, M->getAccessSemantics());
240+
ref->setType(M->getType());
241+
242+
return ref;
243+
};
244+
245+
// Let's make a copy of either decl or member ref without source
246+
// information. It's invalid to have decl reference expressions
247+
// reused, each reference should get a fresh expression.
248+
if (auto *DRE = dyn_cast<DeclRefExpr>(DstRef)) {
249+
DstRef = cloneDeclRef(DRE);
250+
} else {
251+
DstRef = cloneMemberRef(cast<MemberRefExpr>(DstRef));
252+
}
253+
211254
auto *POArgList = ArgumentList::forImplicitUnlabeled(Ctx, {DstRef});
212255
auto *POCall = CallExpr::createImplicit(Ctx, PODeclRef, POArgList);
213256
POCall->setThrows(false);

0 commit comments

Comments
 (0)