https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/234493
>From 1a31c54fbc77a50d5ae4afa7b04b2c9800ca21d4 Mon Sep 17 00:00:00 2001 From: SahilPatidar <[email protected]> Date: Wed, 21 Oct 2026 14:22:00 +0530 Subject: [PATCH 1/3] [CodeGen] Add CodeGenModule::forgetDecl to discard cached mangled-name state Adds CodeGenModule::forgetDecl(GlobalDecl GD), exposed through CodeGenerator/ModuleBuilder, to clear cached entries in DeferredDecls and Manglings for a declaration. This is useful for clang-repl, where a failed partial translation unit (PTU) may be rolled back and a new definition emitted with the same mangled name. Without clearing the old state, CodeGen may reuse stale entries from the discarded PTU. This is also related to #223305 (module contamination after a failed template instantiation), where CodeGen holds onto state from a discarded PTU. --- clang/include/clang/CodeGen/ModuleBuilder.h | 5 +++++ clang/lib/CodeGen/CodeGenModule.cpp | 6 ++++++ clang/lib/CodeGen/CodeGenModule.h | 2 ++ clang/lib/CodeGen/ModuleBuilder.cpp | 6 ++++++ 4 files changed, 19 insertions(+) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 99e3bdf013a8e8..672f97bbae6bdb 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -113,6 +113,11 @@ class CodeGenerator : public ASTConsumer { /// Create a new \c llvm::Module after calling HandleTranslationUnit. This /// enable codegen in interactive processing environments. llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C); + + /// Clear any CodeGen state associated with \p GD’s mangled name so that a + /// new declaration using the same name is treated as if CodeGen has + /// never seen it before. + void forgetDecl(GlobalDecl GD); }; /// CreateLLVMCodeGen - Create a CodeGenerator instance. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a058d1fe7a2a3b..f26c09a9e7bb19 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -8665,6 +8665,12 @@ bool CodeGenModule::lookupRepresentativeDecl(StringRef MangledName, return true; } +void CodeGenModule::forgetDecl(GlobalDecl GD) { + StringRef MangledName = getMangledName(GD); + DeferredDecls.erase(MangledName); + Manglings.erase(MangledName); +} + /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 9e3f073c20f4a0..60fbc8167a8d7f 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -863,6 +863,8 @@ class CodeGenModule : public CodeGenTypeCache { bool lookupRepresentativeDecl(StringRef MangledName, GlobalDecl &Result) const; + void forgetDecl(GlobalDecl GD); + llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) { return AtomicSetterHelperFnMap[Ty]; } diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 0b00362487d2af..4be2aac9d6e8e2 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -155,6 +155,8 @@ namespace { return M.get(); } + void forgetDecl(GlobalDecl GD) { Builder->forgetDecl(GD); } + void Initialize(ASTContext &Context) override { Ctx = &Context; @@ -394,6 +396,10 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName, return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C); } +void CodeGenerator::forgetDecl(GlobalDecl GD) { + static_cast<CodeGeneratorImpl *>(this)->forgetDecl(GD); +} + std::unique_ptr<CodeGenerator> clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, >From ebc9cf780d7bf970f1329a06d0ff73ccfacdce36 Mon Sep 17 00:00:00 2001 From: SahilPatidar <[email protected]> Date: Sat, 24 Oct 2026 15:04:40 +0530 Subject: [PATCH 2/3] Apply CodeGenModule::forgetDecl and add test --- clang/lib/Interpreter/IncrementalParser.cpp | 38 ++++++++++++++++--- .../Interpreter/codegen-stale-entries.cpp | 25 ++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 clang/test/Interpreter/codegen-stale-entries.cpp diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 3cfabb5e5daa18..a2e6b7ee4a4c48 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" +#include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Interpreter/PartialTranslationUnit.h" #include "clang/Parse/Parser.h" @@ -199,6 +200,7 @@ void IncrementalParser::withdrawMostRecentTU( class ASTDeclUnmerger : public DeclVisitor<ASTDeclUnmerger> { Sema &S; TranslationUnitDecl *DiscardedTU; + CodeGenerator *CodeGen; template <typename DeclT> void withdraw(Redeclarable<DeclT> *DBase) { if (NamedDecl *Prev = findSurvivor(static_cast<DeclT *>(DBase))) @@ -275,20 +277,45 @@ class ASTDeclUnmerger : public DeclVisitor<ASTDeclUnmerger> { Primary->makeDeclVisibleInContext(Prev); } + void forgetMangledNames(std::initializer_list<GlobalDecl> GDs) { + if (!CodeGen) + return; + for (GlobalDecl GD : GDs) + CodeGen->forgetDecl(GD); + } + public: - ASTDeclUnmerger(Sema &S, TranslationUnitDecl *DiscardedTU) - : S(S), DiscardedTU(DiscardedTU) {} + ASTDeclUnmerger(Sema &S, TranslationUnitDecl *DiscardedTU, + CodeGenerator *CodeGen = nullptr) + : S(S), DiscardedTU(DiscardedTU), CodeGen(CodeGen) {} void VisitDecl(Decl *D) { if (auto *DC = dyn_cast<DeclContext>(D)) VisitDeclContext(DC); } - void VisitFunctionDecl(FunctionDecl *D) { withdraw(D); } + void VisitFunctionDecl(FunctionDecl *D) { + forgetMangledNames({GlobalDecl(D)}); + withdraw(D); + } + void VisitCXXConstructorDecl(CXXConstructorDecl *D) { + forgetMangledNames({GlobalDecl(D, Ctor_Complete), GlobalDecl(D, Ctor_Base), + GlobalDecl(D, Ctor_Comdat)}); + withdraw(D); + } + void VisitCXXDestructorDecl(CXXDestructorDecl *D) { + forgetMangledNames( + {GlobalDecl(D, Dtor_Deleting), GlobalDecl(D, Dtor_Complete), + GlobalDecl(D, Dtor_Base), GlobalDecl(D, Dtor_Comdat)}); + withdraw(D); + } void VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { withdraw(D); } void VisitTypedefNameDecl(TypedefNameDecl *D) { withdraw(D); } void VisitUsingShadowDecl(UsingShadowDecl *D) { withdraw(D); } - void VisitVarDecl(VarDecl *D) { withdraw(D); } + void VisitVarDecl(VarDecl *D) { + forgetMangledNames({GlobalDecl(D)}); + withdraw(D); + } void VisitTagDecl(TagDecl *D) { NamedDecl *Prev = findSurvivor(D); @@ -325,7 +352,8 @@ class ASTDeclUnmerger : public DeclVisitor<ASTDeclUnmerger> { }; void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) { - ASTDeclUnmerger(S, MostRecentTU).Visit(MostRecentTU); + ASTDeclUnmerger(S, MostRecentTU, Act ? Act->getCodeGen() : nullptr) + .Visit(MostRecentTU); // Lookup alone is not enough: the redeclaration chain still reaches these. withdrawMostRecentTU(MostRecentTU); diff --git a/clang/test/Interpreter/codegen-stale-entries.cpp b/clang/test/Interpreter/codegen-stale-entries.cpp new file mode 100644 index 00000000000000..ce54f071f2cf98 --- /dev/null +++ b/clang/test/Interpreter/codegen-stale-entries.cpp @@ -0,0 +1,25 @@ +// REQUIRES: host-supports-jit +// RUN: cat %s | clang-repl 2>&1 | FileCheck %s +// +// This test demonstrates that stale entries in CodeGen keep foo and infn +// reachable after %undo. It motivates removing stale entries from +// CodeGenModule::DeferredDecls and CodeGenModule::Manglings via +// CodeGenModule::forgetDecl (PR #234493). + +extern "C" int printf(const char *, ...); + +static int foo(int x); +static int foo(int x) { return x + 1; } +%undo +auto sfr = printf("foo=%d\n", foo(10)); +// CHECK-NOT: foo=11 +// CHECK: JIT session error: Symbols not found + +inline int infn(int x); +inline int infn(int x) { return x + 1; } +%undo +auto infnr = printf("infn=%d\n", infn(10)); +// CHECK-NOT: infn=11 +// CHECK: JIT session error: Symbols not found + +%quit >From 90cd0c449f1cf161831fda266e1980cbceab578e Mon Sep 17 00:00:00 2001 From: SahilPatidar <[email protected]> Date: Sun, 25 Oct 2026 10:47:16 +0530 Subject: [PATCH 3/3] add missing headers --- clang/lib/Interpreter/IncrementalParser.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index a2e6b7ee4a4c48..eeada8ab0a7695 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -19,6 +19,8 @@ #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/Basic/ABI.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Interpreter/PartialTranslationUnit.h" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
