@@ -1013,6 +1013,30 @@ namespace clad {
10131013 return newPVD;
10141014 }
10151015
1016+ #if CLANG_VERSION_MAJOR >= 17
1017+ // / Register every (original, clone) VarDecl pair, at any depth.
1018+ static void
1019+ registerClonedDecls (const Stmt* Orig, Stmt* Cloned,
1020+ std::unordered_map<const VarDecl*, VarDecl*>& Repls) {
1021+ if (!Orig || !Cloned)
1022+ return ;
1023+ if (const auto * DS = dyn_cast<DeclStmt>(Orig))
1024+ if (auto * ClonedDS = dyn_cast<DeclStmt>(Cloned)) {
1025+ auto O = DS ->decl_begin ();
1026+ auto C = ClonedDS->decl_begin ();
1027+ for (; O != DS ->decl_end () && C != ClonedDS->decl_end (); ++O, ++C)
1028+ if (const auto * OVD = dyn_cast<VarDecl>(*O))
1029+ if (auto * CVD = dyn_cast<VarDecl>(*C))
1030+ if (OVD != CVD )
1031+ Repls[OVD ] = CVD ;
1032+ }
1033+ auto O = Orig->child_begin ();
1034+ auto C = Cloned->child_begin ();
1035+ for (; O != Orig->child_end () && C != Cloned->child_end (); ++O, ++C)
1036+ registerClonedDecls (*O, *C, Repls);
1037+ }
1038+ #endif // CLANG_VERSION_MAJOR >= 17
1039+
10161040 Expr* VisitorBase::buildClonedLambda (const LambdaExpr* LE ) {
10171041 // A primal copy needs a *fresh* closure type; a plain StmtClone reuses the
10181042 // original closure, so two clones share the operator() body -- both a
@@ -1161,23 +1185,11 @@ namespace clad {
11611185 // lambda's call operator rather than m_DiffReq.Function (the outer
11621186 // function being differentiated), which would reject the lambda locals.
11631187 Stmt* clonedS = CloneNode (S);
1188+ // Register before remapping, so references in this statement update too.
1189+ registerClonedDecls (S, clonedS, m_DeclReplacements);
11641190 utils::ReferencesUpdater up (m_Sema, getCurrentScope (), CallOp,
11651191 m_DeclReplacements);
11661192 up.TraverseStmt (clonedS);
1167- // Cloning a DeclStmt produces a fresh VarDecl, but StmtClone records that
1168- // only in its own decl mapping. Register it here too, or a later
1169- // statement's clone keeps referring to the original lambda's variable --
1170- // a reference into the user's AST that outlives differentiation.
1171- if (const auto * DS = dyn_cast<DeclStmt>(S))
1172- if (auto * ClonedDS = dyn_cast<DeclStmt>(clonedS)) {
1173- auto O = DS ->decl_begin ();
1174- auto C = ClonedDS->decl_begin ();
1175- for (; O != DS ->decl_end () && C != ClonedDS->decl_end (); ++O, ++C)
1176- if (const auto * OVD = dyn_cast<VarDecl>(*O))
1177- if (auto * CVD = dyn_cast<VarDecl>(*C))
1178- if (OVD != CVD )
1179- m_DeclReplacements[OVD ] = CVD ;
1180- }
11811193 addToCurrentBlock (clonedS);
11821194 }
11831195 CompoundStmt* ClonedBody = endBlock ();
0 commit comments