[clang] [clang-tools-extra] [clang] Reference-count `ModuleCache` non-intrusively (PR #164889)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 27 12:29:02 PDT 2025


https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/164889

>From 7fb636266818ec1428060183698a2b0253e640c3 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 23 Oct 2025 13:38:03 -0700
Subject: [PATCH 1/2] [clang] Reference-count `ModuleCache` non-intrusively

---
 clang-tools-extra/clangd/ModulesBuilder.cpp              | 2 +-
 clang/include/clang/Frontend/ASTUnit.h                   | 2 +-
 clang/include/clang/Frontend/CompilerInstance.h          | 5 +++--
 clang/include/clang/Serialization/ModuleCache.h          | 5 ++---
 clang/include/clang/Serialization/ModuleManager.h        | 5 ++---
 .../Tooling/DependencyScanning/InProcessModuleCache.h    | 2 +-
 clang/lib/Frontend/ASTUnit.cpp                           | 3 ++-
 clang/lib/Frontend/CompilerInstance.cpp                  | 9 +++++----
 clang/lib/Frontend/Rewrite/FrontendActions.cpp           | 2 +-
 clang/lib/Serialization/ModuleCache.cpp                  | 4 ++--
 clang/lib/Serialization/ModuleManager.cpp                | 4 ++--
 .../Tooling/DependencyScanning/DependencyScannerImpl.cpp | 2 +-
 .../Tooling/DependencyScanning/InProcessModuleCache.cpp  | 4 ++--
 clang/unittests/Serialization/ModuleCacheTest.cpp        | 4 ++--
 14 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 0177a1751bd60..524ec620c4076 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -265,7 +265,7 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,
                   ModuleLoader);
 
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
+  std::shared_ptr<ModuleCache> ModCache = createCrossProcessModuleCache();
   PCHContainerOperations PCHOperations;
   CodeGenOptions CodeGenOpts;
   ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr,
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index 3cea159afa33c..2889353473590 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -117,7 +117,7 @@ class ASTUnit {
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
   IntrusiveRefCntPtr<FileManager>         FileMgr;
   IntrusiveRefCntPtr<SourceManager>       SourceMgr;
-  IntrusiveRefCntPtr<ModuleCache> ModCache;
+  std::shared_ptr<ModuleCache> ModCache;
   std::unique_ptr<HeaderSearch>           HeaderInfo;
   IntrusiveRefCntPtr<TargetInfo>          Target;
   std::shared_ptr<Preprocessor>           PP;
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 2403cbbb652dd..86ae9e8162b73 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -108,7 +108,7 @@ class CompilerInstance : public ModuleLoader {
   IntrusiveRefCntPtr<SourceManager> SourceMgr;
 
   /// The cache of PCM files.
-  IntrusiveRefCntPtr<ModuleCache> ModCache;
+  std::shared_ptr<ModuleCache> ModCache;
 
   /// Functor for getting the dependency preprocessor directives of a file.
   std::unique_ptr<DependencyDirectivesGetter> GetDependencyDirectives;
@@ -201,7 +201,7 @@ class CompilerInstance : public ModuleLoader {
           std::make_shared<CompilerInvocation>(),
       std::shared_ptr<PCHContainerOperations> PCHContainerOps =
           std::make_shared<PCHContainerOperations>(),
-      ModuleCache *ModCache = nullptr);
+      std::shared_ptr<ModuleCache> ModCache = nullptr);
   ~CompilerInstance() override;
 
   /// @name High-Level Operations
@@ -949,6 +949,7 @@ class CompilerInstance : public ModuleLoader {
   void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
 
   ModuleCache &getModuleCache() const { return *ModCache; }
+  std::shared_ptr<ModuleCache> getModuleCachePtr() const { return ModCache; }
 };
 
 } // end namespace clang
diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h
index ec052c5c18e0a..c6795c5dc358a 100644
--- a/clang/include/clang/Serialization/ModuleCache.h
+++ b/clang/include/clang/Serialization/ModuleCache.h
@@ -10,7 +10,6 @@
 #define LLVM_CLANG_SERIALIZATION_MODULECACHE_H
 
 #include "clang/Basic/LLVM.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
 
 #include <ctime>
 
@@ -23,7 +22,7 @@ class InMemoryModuleCache;
 
 /// The module cache used for compiling modules implicitly. This centralizes the
 /// operations the compiler might want to perform on the cache.
-class ModuleCache : public RefCountedBase<ModuleCache> {
+class ModuleCache {
 public:
   /// May perform any work that only needs to be performed once for multiple
   /// calls \c getLock() with the same module filename.
@@ -62,7 +61,7 @@ class ModuleCache : public RefCountedBase<ModuleCache> {
 /// operated on by multiple processes. This instance must be used across all
 /// \c CompilerInstance instances participating in building modules for single
 /// translation unit in order to share the same \c InMemoryModuleCache.
-IntrusiveRefCntPtr<ModuleCache> createCrossProcessModuleCache();
+std::shared_ptr<ModuleCache> createCrossProcessModuleCache();
 
 /// Shared implementation of `ModuleCache::maybePrune()`.
 void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter);
diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h
index 1eb74aee9787c..8ab70b6630f47 100644
--- a/clang/include/clang/Serialization/ModuleManager.h
+++ b/clang/include/clang/Serialization/ModuleManager.h
@@ -18,7 +18,6 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Serialization/ModuleFile.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -65,7 +64,7 @@ class ModuleManager {
   FileManager &FileMgr;
 
   /// Cache of PCM files.
-  IntrusiveRefCntPtr<ModuleCache> ModCache;
+  ModuleCache &ModCache;
 
   /// Knows how to unwrap module containers.
   const PCHContainerReader &PCHContainerRdr;
@@ -306,7 +305,7 @@ class ModuleManager {
   /// View the graphviz representation of the module graph.
   void viewGraph();
 
-  ModuleCache &getModuleCache() const { return *ModCache; }
+  ModuleCache &getModuleCache() const { return ModCache; }
 };
 
 } // namespace serialization
diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
index 213e60b39c199..81283f6aa5efc 100644
--- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
+++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
@@ -28,7 +28,7 @@ struct ModuleCacheEntries {
   llvm::StringMap<std::unique_ptr<ModuleCacheEntry>> Map;
 };
 
-IntrusiveRefCntPtr<ModuleCache>
+std::shared_ptr<ModuleCache>
 makeInProcessModuleCache(ModuleCacheEntries &Entries);
 } // namespace dependencies
 } // namespace tooling
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 6cc7094846155..0ae72521d8cd6 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -1506,6 +1506,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
   if (CI.hasTarget())
     Target = CI.getTargetPtr();
   Reader = CI.getASTReader();
+  ModCache = CI.getModuleCachePtr();
   HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
   if (Invocation != CI.getInvocationPtr()) {
     // This happens when Parse creates a copy of \c Invocation to modify.
@@ -2403,7 +2404,7 @@ bool ASTUnit::serialize(raw_ostream &OS) {
 
   SmallString<128> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
+  std::shared_ptr<ModuleCache> ModCache = createCrossProcessModuleCache();
   ASTWriter Writer(Stream, Buffer, *ModCache, *CodeGenOpts, {});
   return serializeUnit(Writer, Buffer, getSema(), OS);
 }
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index e3bf0eaa3c391..2482e3c649d6f 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -70,10 +70,11 @@ using namespace clang;
 CompilerInstance::CompilerInstance(
     std::shared_ptr<CompilerInvocation> Invocation,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    ModuleCache *ModCache)
-    : ModuleLoader(/*BuildingModule=*/ModCache),
+    std::shared_ptr<ModuleCache> ModCache)
+    : ModuleLoader(/*BuildingModule=*/ModCache != nullptr),
       Invocation(std::move(Invocation)),
-      ModCache(ModCache ? ModCache : createCrossProcessModuleCache()),
+      ModCache(ModCache ? std::move(ModCache)
+                        : createCrossProcessModuleCache()),
       ThePCHContainerOperations(std::move(PCHContainerOps)) {
   assert(this->Invocation && "Invocation must not be null");
 }
@@ -1155,7 +1156,7 @@ std::unique_ptr<CompilerInstance> CompilerInstance::cloneForModuleCompileImpl(
   // CompilerInstance::CompilerInstance is responsible for finalizing the
   // buffers to prevent use-after-frees.
   auto InstancePtr = std::make_unique<CompilerInstance>(
-      std::move(Invocation), getPCHContainerOperations(), &getModuleCache());
+      std::move(Invocation), getPCHContainerOperations(), ModCache);
   auto &Instance = *InstancePtr;
 
   auto &Inv = Instance.getInvocation();
diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index f5656b3b190e9..ef6f9ccf87848 100644
--- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -244,7 +244,7 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
     // Rewrite the contents of the module in a separate compiler instance.
     CompilerInstance Instance(
         std::make_shared<CompilerInvocation>(CI.getInvocation()),
-        CI.getPCHContainerOperations(), &CI.getModuleCache());
+        CI.getPCHContainerOperations(), CI.getModuleCachePtr());
     Instance.setVirtualFileSystem(CI.getVirtualFileSystemPtr());
     Instance.createDiagnostics(
         new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 9850956380423..aa6b3c0871ba4 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -148,6 +148,6 @@ class CrossProcessModuleCache : public ModuleCache {
 };
 } // namespace
 
-IntrusiveRefCntPtr<ModuleCache> clang::createCrossProcessModuleCache() {
-  return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>();
+std::shared_ptr<ModuleCache> clang::createCrossProcessModuleCache() {
+  return std::make_shared<CrossProcessModuleCache>();
 }
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 482c17649ed55..236fe20fdad7c 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -176,7 +176,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
 
   if (NewModule->Kind == MK_ImplicitModule)
     NewModule->InputFilesValidationTimestamp =
-        ModCache->getModuleTimestamp(NewModule->FileName);
+        ModCache.getModuleTimestamp(NewModule->FileName);
 
   // Load the contents of the module
   if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
@@ -330,7 +330,7 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
 ModuleManager::ModuleManager(FileManager &FileMgr, ModuleCache &ModCache,
                              const PCHContainerReader &PCHContainerRdr,
                              const HeaderSearch &HeaderSearchInfo)
-    : FileMgr(FileMgr), ModCache(&ModCache), PCHContainerRdr(PCHContainerRdr),
+    : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
       HeaderSearchInfo(HeaderSearchInfo) {}
 
 void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 42f52d0ff6241..1fcbd3c6b38dc 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -661,7 +661,7 @@ bool DependencyScanningAction::runInvocation(
   // Create a compiler instance to handle the actual work.
   auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
   ScanInstanceStorage.emplace(std::move(Invocation), std::move(PCHContainerOps),
-                              ModCache.get());
+                              std::move(ModCache));
   CompilerInstance &ScanInstance = *ScanInstanceStorage;
 
   assert(!DiagConsumerFinished && "attempt to reuse finished consumer");
diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
index d1e543b438225..75dd2d8c21b9a 100644
--- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
+++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
@@ -114,7 +114,7 @@ class InProcessModuleCache : public ModuleCache {
 };
 } // namespace
 
-IntrusiveRefCntPtr<ModuleCache>
+std::shared_ptr<ModuleCache>
 dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {
-  return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
+  return std::make_shared<InProcessModuleCache>(Entries);
 }
diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp
index e9b8da3dba6af..00044ac729a3c 100644
--- a/clang/unittests/Serialization/ModuleCacheTest.cpp
+++ b/clang/unittests/Serialization/ModuleCacheTest.cpp
@@ -145,7 +145,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) {
   ASSERT_TRUE(Invocation2);
   CompilerInstance Instance2(std::move(Invocation2),
                              Instance.getPCHContainerOperations(),
-                             &Instance.getModuleCache());
+                             Instance.getModuleCachePtr());
   Instance2.setVirtualFileSystem(CIOpts.VFS);
   Instance2.setDiagnostics(Diags);
   SyntaxOnlyAction Action2;
@@ -191,7 +191,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) {
   ASSERT_TRUE(Invocation2);
   CompilerInstance Instance2(std::move(Invocation2),
                              Instance.getPCHContainerOperations(),
-                             &Instance.getModuleCache());
+                             Instance.getModuleCachePtr());
   Instance2.setVirtualFileSystem(CIOpts.VFS);
   Instance2.setDiagnostics(Diags);
   SyntaxOnlyAction Action2;

>From a60214ab3b085e86c3b4ac3f62fbd3bbe9282b8d Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Mon, 27 Oct 2025 12:28:48 -0700
Subject: [PATCH 2/2] Add missing (previously transitive) include

---
 .../clang/Tooling/DependencyScanning/InProcessModuleCache.h      | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
index 81283f6aa5efc..ac531444bab99 100644
--- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
+++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
@@ -12,6 +12,7 @@
 #include "clang/Serialization/ModuleCache.h"
 #include "llvm/ADT/StringMap.h"
 
+#include <atomic>
 #include <mutex>
 #include <shared_mutex>
 



More information about the cfe-commits mailing list