From 35c5fa5ea8b091a842daf4e07b0ddced8d4c8877 Mon Sep 17 00:00:00 2001 From: Tempris Admin Date: Fri, 19 Jun 2026 01:17:14 +0700 Subject: [PATCH 1/2] Replace static LookupResult caches with per-instance members GetCladTapePush, GetCladTapePop, GetCladTapeBack, and GetCladZeroInit each used a function-local static llvm::Optional to cache their lookup. LookupResult objects hold pointers into the current ASTContext/Sema, so static locals cause stale AST references when multiple translation units are processed in the same process (e.g., in Cling's interactive mode). Replace all four statics with per-instance llvm::Optional members on VisitorBase: m_TapePushLookup, m_TapePopLookup, m_TapeBackLookup, and m_TapeZeroInitLookup. Each lookup is performed lazily on first use and dies with the visitor instance. Fixes: #1837 --- include/clad/Differentiator/VisitorBase.h | 8 +++++++ lib/Differentiator/VisitorBase.cpp | 28 ++++++++++------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/clad/Differentiator/VisitorBase.h b/include/clad/Differentiator/VisitorBase.h index bdd2c29d3..29314839c 100644 --- a/include/clad/Differentiator/VisitorBase.h +++ b/include/clad/Differentiator/VisitorBase.h @@ -34,6 +34,7 @@ #include #include #include +#include namespace clang { class NestedNameSpecifier; @@ -151,6 +152,13 @@ namespace clad { // expression to be of object type in the reverse mode as well. clang::Expr* m_ThisExprDerivative = nullptr; + /// Per-instance cache for tape lookup results. These are tied to the + /// current Sema/ASTContext and must not be shared across translation units. + clad_compat::llvm_Optional m_TapePushLookup; + clad_compat::llvm_Optional m_TapePopLookup; + clad_compat::llvm_Optional m_TapeBackLookup; + clad_compat::llvm_Optional m_TapeZeroInitLookup; + /// The currently visited statement. Useful for crash pretty-printing. const clang::Stmt* m_CurVisitedStmt = nullptr; diff --git a/lib/Differentiator/VisitorBase.cpp b/lib/Differentiator/VisitorBase.cpp index aecef52c7..d6015f5cd 100644 --- a/lib/Differentiator/VisitorBase.cpp +++ b/lib/Differentiator/VisitorBase.cpp @@ -517,10 +517,9 @@ namespace clad { } LookupResult& VisitorBase::GetCladTapePush() { - static clad_compat::llvm_Optional Result{}; - if (!Result) - Result = LookupCladTapeMethod("push"); - return clad_compat::llvm_Optional_GetValue(Result); + if (!m_TapePushLookup) + m_TapePushLookup = LookupCladTapeMethod("push"); + return clad_compat::llvm_Optional_GetValue(m_TapePushLookup); } Expr* VisitorBase::GetFunctionCall(const std::string& funcName, @@ -562,17 +561,15 @@ namespace clad { } LookupResult& VisitorBase::GetCladTapePop() { - static clad_compat::llvm_Optional Result{}; - if (!Result) - Result = LookupCladTapeMethod("pop"); - return clad_compat::llvm_Optional_GetValue(Result); + if (!m_TapePopLookup) + m_TapePopLookup = LookupCladTapeMethod("pop"); + return clad_compat::llvm_Optional_GetValue(m_TapePopLookup); } LookupResult& VisitorBase::GetCladTapeBack() { - static clad_compat::llvm_Optional Result{}; - if (!Result) - Result = LookupCladTapeMethod("back"); - return clad_compat::llvm_Optional_GetValue(Result); + if (!m_TapeBackLookup) + m_TapeBackLookup = LookupCladTapeMethod("back"); + return clad_compat::llvm_Optional_GetValue(m_TapeBackLookup); } QualType VisitorBase::GetCladTapeOfType(QualType T) { @@ -832,10 +829,9 @@ namespace clad { } Stmt* VisitorBase::GetCladZeroInit(llvm::MutableArrayRef args) { - static clad_compat::llvm_Optional Result{}; - if (!Result) - Result = LookupCladTapeMethod("zero_init"); - LookupResult& init = clad_compat::llvm_Optional_GetValue(Result); + if (!m_TapeZeroInitLookup) + m_TapeZeroInitLookup = LookupCladTapeMethod("zero_init"); + LookupResult& init = clad_compat::llvm_Optional_GetValue(m_TapeZeroInitLookup); CXXScopeSpec CSS; CSS.Extend(m_Context, utils::GetCladNamespace(m_Sema), noLoc, noLoc); auto* pushDRE = From f3d2ac696599df1e1ed10e1cce5d4350c57d13bd Mon Sep 17 00:00:00 2001 From: Tempris Admin Date: Fri, 26 Jun 2026 21:10:56 +0700 Subject: [PATCH 2/2] Fix LookupResult cache build --- include/clad/Differentiator/VisitorBase.h | 3 +++ lib/Differentiator/VisitorBase.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/clad/Differentiator/VisitorBase.h b/include/clad/Differentiator/VisitorBase.h index 29314839c..677e238ff 100644 --- a/include/clad/Differentiator/VisitorBase.h +++ b/include/clad/Differentiator/VisitorBase.h @@ -21,6 +21,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" @@ -152,6 +153,7 @@ namespace clad { // expression to be of object type in the reverse mode as well. clang::Expr* m_ThisExprDerivative = nullptr; + private: /// Per-instance cache for tape lookup results. These are tied to the /// current Sema/ASTContext and must not be shared across translation units. clad_compat::llvm_Optional m_TapePushLookup; @@ -159,6 +161,7 @@ namespace clad { clad_compat::llvm_Optional m_TapeBackLookup; clad_compat::llvm_Optional m_TapeZeroInitLookup; + protected: /// The currently visited statement. Useful for crash pretty-printing. const clang::Stmt* m_CurVisitedStmt = nullptr; diff --git a/lib/Differentiator/VisitorBase.cpp b/lib/Differentiator/VisitorBase.cpp index d6015f5cd..d225a91d1 100644 --- a/lib/Differentiator/VisitorBase.cpp +++ b/lib/Differentiator/VisitorBase.cpp @@ -831,7 +831,8 @@ namespace clad { Stmt* VisitorBase::GetCladZeroInit(llvm::MutableArrayRef args) { if (!m_TapeZeroInitLookup) m_TapeZeroInitLookup = LookupCladTapeMethod("zero_init"); - LookupResult& init = clad_compat::llvm_Optional_GetValue(m_TapeZeroInitLookup); + LookupResult& init = + clad_compat::llvm_Optional_GetValue(m_TapeZeroInitLookup); CXXScopeSpec CSS; CSS.Extend(m_Context, utils::GetCladNamespace(m_Sema), noLoc, noLoc); auto* pushDRE =