Skip to content

Commit c33c7ac

Browse files
author
Shubham Shukla
committed
Register a cloned lambda body's nested declarations before remapping.
1 parent c18a748 commit c33c7ac

2 files changed

Lines changed: 38 additions & 14 deletions

File tree

lib/Differentiator/VisitorBase.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,28 @@ namespace clad {
878878
return newPVD;
879879
}
880880

881+
/// Register every (original, clone) VarDecl pair, at any depth.
882+
static void
883+
registerClonedDecls(const Stmt* Orig, Stmt* Cloned,
884+
std::unordered_map<const VarDecl*, VarDecl*>& Repls) {
885+
if (!Orig || !Cloned)
886+
return;
887+
if (const auto* DS = dyn_cast<DeclStmt>(Orig))
888+
if (auto* ClonedDS = dyn_cast<DeclStmt>(Cloned)) {
889+
auto O = DS->decl_begin();
890+
auto C = ClonedDS->decl_begin();
891+
for (; O != DS->decl_end() && C != ClonedDS->decl_end(); ++O, ++C)
892+
if (const auto* OVD = dyn_cast<VarDecl>(*O))
893+
if (auto* CVD = dyn_cast<VarDecl>(*C))
894+
if (OVD != CVD)
895+
Repls[OVD] = CVD;
896+
}
897+
auto O = Orig->child_begin();
898+
auto C = Cloned->child_begin();
899+
for (; O != Orig->child_end() && C != Cloned->child_end(); ++O, ++C)
900+
registerClonedDecls(*O, *C, Repls);
901+
}
902+
881903
Expr* VisitorBase::buildClonedLambda(const LambdaExpr* LE) {
882904
// A primal copy needs a *fresh* closure type; a plain StmtClone reuses the
883905
// original closure, so two clones share the operator() body -- both a
@@ -1026,23 +1048,11 @@ namespace clad {
10261048
// lambda's call operator rather than m_DiffReq.Function (the outer
10271049
// function being differentiated), which would reject the lambda locals.
10281050
Stmt* clonedS = CloneNode(S);
1051+
// Register before remapping, so references in this statement update too.
1052+
registerClonedDecls(S, clonedS, m_DeclReplacements);
10291053
utils::ReferencesUpdater up(m_Sema, getCurrentScope(), CallOp,
10301054
m_DeclReplacements);
10311055
up.TraverseStmt(clonedS);
1032-
// Cloning a DeclStmt produces a fresh VarDecl, but StmtClone records that
1033-
// only in its own decl mapping. Register it here too, or a later
1034-
// statement's clone keeps referring to the original lambda's variable --
1035-
// a reference into the user's AST that outlives differentiation.
1036-
if (const auto* DS = dyn_cast<DeclStmt>(S))
1037-
if (auto* ClonedDS = dyn_cast<DeclStmt>(clonedS)) {
1038-
auto O = DS->decl_begin();
1039-
auto C = ClonedDS->decl_begin();
1040-
for (; O != DS->decl_end() && C != ClonedDS->decl_end(); ++O, ++C)
1041-
if (const auto* OVD = dyn_cast<VarDecl>(*O))
1042-
if (auto* CVD = dyn_cast<VarDecl>(*C))
1043-
if (OVD != CVD)
1044-
m_DeclReplacements[OVD] = CVD;
1045-
}
10461056
addToCurrentBlock(clonedS);
10471057
}
10481058
CompoundStmt* ClonedBody = endBlock();

test/ForwardMode/Lambdas.C

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ double fn4(double x) {
4242
return _f(x);
4343
}
4444

45+
double fn5(double x) {
46+
auto _f = [](double _x) {
47+
double s = 0;
48+
for (int k = 0; k < 3; ++k)
49+
s += _x * _x;
50+
return s;
51+
};
52+
return _f(x);
53+
}
54+
4555
int main() {
4656
auto fn0_dx = clad::differentiate(fn0, 0);
4757
printf("Result is = %.2f\n", fn0_dx.execute(7)); // CHECK-EXEC: Result is = 14.00
@@ -62,4 +72,8 @@ int main() {
6272
auto fn4_dx = clad::differentiate(fn4, 0);
6373
printf("Result is = %.2f\n", fn4_dx.execute(7)); // CHECK-EXEC: Result is = 28.00
6474
printf("Result is = %.2f\n", fn4_dx.execute(-1)); // CHECK-EXEC: Result is = -4.00
75+
76+
auto fn5_dx = clad::differentiate(fn5, 0);
77+
printf("Result is = %.2f\n", fn5_dx.execute(7)); // CHECK-EXEC: Result is = 42.00
78+
printf("Result is = %.2f\n", fn5_dx.execute(-1)); // CHECK-EXEC: Result is = -6.00
6579
}

0 commit comments

Comments
 (0)