@@ -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 ();
0 commit comments