Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[clang][modules] Timestamp-less validation API #138983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2025

Conversation

jansvoboda11
Copy link
Contributor

@jansvoboda11 jansvoboda11 commented May 7, 2025

Timestamps are an implementation detail of the cross-process module cache implementation. This PR hides it from the ModuleCache API, which simplifies the in-process implementation.

@jansvoboda11 jansvoboda11 requested a review from Bigcheese May 7, 2025 22:38
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra clangd clang:modules C++20 modules and Clang Header Modules labels May 7, 2025
@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-clangd

@llvm/pr-subscribers-clang-tools-extra

Author: Jan Svoboda (jansvoboda11)

Changes

Timestamps are an implementation detail of the cross-process module cache implementation. This PR hide it from the ModuleCache API, which simplifies the in-process implementation.


Full diff: https://github.com/llvm/llvm-project/pull/138983.diff

11 Files Affected:

  • (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-1)
  • (modified) clang/include/clang/Serialization/ModuleCache.h (+6-8)
  • (modified) clang/include/clang/Serialization/ModuleFile.h (+3-5)
  • (modified) clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h (+1-1)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+6-4)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+3-1)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+3-6)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+1-1)
  • (modified) clang/lib/Serialization/ModuleCache.cpp (+14-6)
  • (modified) clang/lib/Serialization/ModuleManager.cpp (+3-3)
  • (modified) clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp (+8-8)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..5350f1b83a7f0 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -207,7 +207,8 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,
                   ModuleLoader);
 
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
+  IntrusiveRefCntPtr<ModuleCache> ModCache =
+      createCrossProcessModuleCache(HSOpts.BuildSessionTimestamp);
   PCHContainerOperations PCHOperations;
   ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr,
                    PCHOperations.getRawReader(), {});
diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h
index 3117d954a09cc..df950906333ba 100644
--- a/clang/include/clang/Serialization/ModuleCache.h
+++ b/clang/include/clang/Serialization/ModuleCache.h
@@ -33,17 +33,14 @@ class ModuleCache : public RefCountedBase<ModuleCache> {
   virtual std::unique_ptr<llvm::AdvisoryLock>
   getLock(StringRef ModuleFilename) = 0;
 
-  // TODO: Abstract away timestamps with isUpToDate() and markUpToDate().
   // TODO: Consider exposing a "validation lock" API to prevent multiple clients
   // concurrently noticing an out-of-date module file and validating its inputs.
 
-  /// Returns the timestamp denoting the last time inputs of the module file
-  /// were validated.
-  virtual std::time_t getModuleTimestamp(StringRef ModuleFilename) = 0;
+  /// Checks whether the inputs of the module file were marked as validated.
+  virtual bool isMarkedUpToDate(StringRef ModuleFilename) = 0;
 
-  /// Updates the timestamp denoting the last time inputs of the module file
-  /// were validated.
-  virtual void updateModuleTimestamp(StringRef ModuleFilename) = 0;
+  /// Marks the inputs of the module file as validated.
+  virtual void markUpToDate(StringRef ModuleFilename) = 0;
 
   /// Returns this process's view of the module cache.
   virtual InMemoryModuleCache &getInMemoryModuleCache() = 0;
@@ -58,7 +55,8 @@ 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();
+IntrusiveRefCntPtr<ModuleCache>
+createCrossProcessModuleCache(std::time_t BuildSessionTimestamp);
 } // namespace clang
 
 #endif
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index f20cb2f9f35ae..5b6e31dac39ed 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -270,11 +270,9 @@ class ModuleFile {
   // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()).
   unsigned NumUserInputFiles = 0;
 
-  /// If non-zero, specifies the time when we last validated input
-  /// files.  Zero means we never validated them.
-  ///
-  /// The time is specified in seconds since the start of the Epoch.
-  uint64_t InputFilesValidationTimestamp = 0;
+  /// Specifies whether the input files have been validated (i.e. checked
+  /// whether they are up-to-date).
+  bool InputFilesValidated = false;
 
   // === Source Locations ===
 
diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
index 213e60b39c199..fa11af2be5a67 100644
--- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
+++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
@@ -20,7 +20,7 @@ namespace tooling {
 namespace dependencies {
 struct ModuleCacheEntry {
   std::shared_mutex CompilationMutex;
-  std::atomic<std::time_t> Timestamp = 0;
+  std::atomic<bool> UpToDate = false;
 };
 
 struct ModuleCacheEntries {
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 35f823e9407db..9b2960299ac8f 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -829,9 +829,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
                                      AST->getFileManager(),
                                      UserFilesAreVolatile);
-  AST->ModCache = createCrossProcessModuleCache();
   AST->HSOpts = std::make_unique<HeaderSearchOptions>(HSOpts);
   AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front());
+  AST->ModCache =
+      createCrossProcessModuleCache(AST->HSOpts->BuildSessionTimestamp);
   AST->HeaderInfo.reset(new HeaderSearch(AST->getHeaderSearchOpts(),
                                          AST->getSourceManager(),
                                          AST->getDiagnostics(),
@@ -1548,7 +1549,8 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
                                      UserFilesAreVolatile);
-  AST->ModCache = createCrossProcessModuleCache();
+  AST->ModCache = createCrossProcessModuleCache(
+      AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp);
 
   return AST;
 }
@@ -1834,7 +1836,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
   AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
   AST->StorePreamblesInMemory = StorePreamblesInMemory;
   AST->PreambleStoragePath = PreambleStoragePath;
-  AST->ModCache = createCrossProcessModuleCache();
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->TUKind = TUKind;
@@ -1843,6 +1844,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
     = IncludeBriefCommentsInCodeCompletion;
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->Invocation = CI;
+  AST->ModCache = createCrossProcessModuleCache(
+      AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp);
   AST->SkipFunctionBodies = SkipFunctionBodies;
   if (ForSerialization)
     AST->WriterData.reset(new ASTWriterData(*AST->ModCache));
@@ -2378,7 +2381,6 @@ bool ASTUnit::serialize(raw_ostream &OS) {
 
   SmallString<128> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
   ASTWriter Writer(Stream, Buffer, *ModCache, {});
   return serializeUnit(Writer, Buffer, getSema(), OS);
 }
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index b59496babb62c..2ed0cf3da3d6d 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -72,7 +72,9 @@ CompilerInstance::CompilerInstance(
     ModuleCache *ModCache)
     : ModuleLoader(/*BuildingModule=*/ModCache),
       Invocation(std::move(Invocation)),
-      ModCache(ModCache ? ModCache : createCrossProcessModuleCache()),
+      ModCache(ModCache ? ModCache
+                        : createCrossProcessModuleCache(
+                              getHeaderSearchOpts().BuildSessionTimestamp)),
       ThePCHContainerOperations(std::move(PCHContainerOps)) {
   assert(this->Invocation && "Invocation must not be null");
 }
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index a17d6229ee3a1..e877669947796 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3103,8 +3103,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
 
         unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
         if (HSOpts.ModulesValidateOncePerBuildSession &&
-            F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp &&
-            F.Kind == MK_ImplicitModule)
+            F.InputFilesValidated && F.Kind == MK_ImplicitModule)
           N = NumUserInputs;
 
         for (unsigned I = 0; I < N; ++I) {
@@ -4950,10 +4949,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type,
     // timestamp files are up-to-date in this build session.
     for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
       ImportedModule &M = Loaded[I];
-      if (M.Mod->Kind == MK_ImplicitModule &&
-          M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp)
-        getModuleManager().getModuleCache().updateModuleTimestamp(
-            M.Mod->FileName);
+      if (M.Mod->Kind == MK_ImplicitModule && !M.Mod->InputFilesValidated)
+        getModuleManager().getModuleCache().markUpToDate(M.Mod->FileName);
     }
   }
 
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index cccf53de25882..27ddb2b6ebec3 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5394,7 +5394,7 @@ ASTWriter::WriteAST(llvm::PointerUnion<Sema *, Preprocessor *> Subject,
   if (WritingModule && PPRef.getHeaderSearchInfo()
                            .getHeaderSearchOpts()
                            .ModulesValidateOncePerBuildSession)
-    ModCache.updateModuleTimestamp(OutputFile);
+    ModCache.markUpToDate(OutputFile);
 
   if (ShouldCacheASTInMemory) {
     // Construct MemoryBuffer and update buffer manager.
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 4ae49c4ec9a05..43f8ff8d681fe 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -20,7 +20,12 @@ namespace {
 class CrossProcessModuleCache : public ModuleCache {
   InMemoryModuleCache InMemory;
 
+  std::time_t BuildSessionTimestamp;
+
 public:
+  explicit CrossProcessModuleCache(std::time_t BuildSessionTimestamp)
+      : BuildSessionTimestamp(BuildSessionTimestamp) {}
+
   void prepareForGetLock(StringRef ModuleFilename) override {
     // FIXME: Do this in LockFileManager and only if the directory doesn't
     // exist.
@@ -33,16 +38,17 @@ class CrossProcessModuleCache : public ModuleCache {
     return std::make_unique<llvm::LockFileManager>(ModuleFilename);
   }
 
-  std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
+  bool isMarkedUpToDate(StringRef ModuleFilename) override {
     std::string TimestampFilename =
         serialization::ModuleFile::getTimestampFilename(ModuleFilename);
     llvm::sys::fs::file_status Status;
     if (llvm::sys::fs::status(ModuleFilename, Status) != std::error_code{})
-      return 0;
-    return llvm::sys::toTimeT(Status.getLastModificationTime());
+      return false;
+    return llvm::sys::toTimeT(Status.getLastModificationTime()) >
+           BuildSessionTimestamp;
   }
 
-  void updateModuleTimestamp(StringRef ModuleFilename) override {
+  void markUpToDate(StringRef ModuleFilename) override {
     // Overwrite the timestamp file contents so that file's mtime changes.
     std::error_code EC;
     llvm::raw_fd_ostream OS(
@@ -62,6 +68,8 @@ class CrossProcessModuleCache : public ModuleCache {
 };
 } // namespace
 
-IntrusiveRefCntPtr<ModuleCache> clang::createCrossProcessModuleCache() {
-  return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>();
+IntrusiveRefCntPtr<ModuleCache>
+clang::createCrossProcessModuleCache(std::time_t BuildSessionTimestamp) {
+  return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>(
+      BuildSessionTimestamp);
 }
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index e3d7ff4fd82a7..73f1a979dfea6 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -172,11 +172,11 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
   NewModule->Index = Chain.size();
   NewModule->FileName = FileName.str();
   NewModule->ImportLoc = ImportLoc;
-  NewModule->InputFilesValidationTimestamp = 0;
+  NewModule->InputFilesValidated = false;
 
   if (NewModule->Kind == MK_ImplicitModule)
-    NewModule->InputFilesValidationTimestamp =
-        ModCache->getModuleTimestamp(NewModule->FileName);
+    NewModule->InputFilesValidated =
+        ModCache->isMarkedUpToDate(NewModule->FileName);
 
   // Load the contents of the module
   if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
index 80db2d47d940e..ccfe42c092f58 100644
--- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
+++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
@@ -75,29 +75,29 @@ class InProcessModuleCache : public ModuleCache {
     return std::make_unique<ReaderWriterLock>(CompilationMutex);
   }
 
-  std::time_t getModuleTimestamp(StringRef Filename) override {
-    auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
+  bool isMarkedUpToDate(StringRef Filename) override {
+    auto &IsUpToDate = [&]() -> std::atomic<bool> & {
       std::lock_guard<std::mutex> Lock(Entries.Mutex);
       auto &Entry = Entries.Map[Filename];
       if (!Entry)
         Entry = std::make_unique<ModuleCacheEntry>();
-      return Entry->Timestamp;
+      return Entry->UpToDate;
     }();
 
-    return Timestamp.load();
+    return IsUpToDate;
   }
 
-  void updateModuleTimestamp(StringRef Filename) override {
+  void markUpToDate(StringRef Filename) override {
     // Note: This essentially replaces FS contention with mutex contention.
-    auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
+    auto &IsUpToDate = [&]() -> std::atomic<bool> & {
       std::lock_guard<std::mutex> Lock(Entries.Mutex);
       auto &Entry = Entries.Map[Filename];
       if (!Entry)
         Entry = std::make_unique<ModuleCacheEntry>();
-      return Entry->Timestamp;
+      return Entry->UpToDate;
     }();
 
-    Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
+    IsUpToDate = true;
   }
 
   InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }

@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-clang-modules

Author: Jan Svoboda (jansvoboda11)

Changes

Timestamps are an implementation detail of the cross-process module cache implementation. This PR hide it from the ModuleCache API, which simplifies the in-process implementation.


Full diff: https://github.com/llvm/llvm-project/pull/138983.diff

11 Files Affected:

  • (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-1)
  • (modified) clang/include/clang/Serialization/ModuleCache.h (+6-8)
  • (modified) clang/include/clang/Serialization/ModuleFile.h (+3-5)
  • (modified) clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h (+1-1)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+6-4)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+3-1)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+3-6)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+1-1)
  • (modified) clang/lib/Serialization/ModuleCache.cpp (+14-6)
  • (modified) clang/lib/Serialization/ModuleManager.cpp (+3-3)
  • (modified) clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp (+8-8)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..5350f1b83a7f0 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -207,7 +207,8 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,
                   ModuleLoader);
 
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
+  IntrusiveRefCntPtr<ModuleCache> ModCache =
+      createCrossProcessModuleCache(HSOpts.BuildSessionTimestamp);
   PCHContainerOperations PCHOperations;
   ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr,
                    PCHOperations.getRawReader(), {});
diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h
index 3117d954a09cc..df950906333ba 100644
--- a/clang/include/clang/Serialization/ModuleCache.h
+++ b/clang/include/clang/Serialization/ModuleCache.h
@@ -33,17 +33,14 @@ class ModuleCache : public RefCountedBase<ModuleCache> {
   virtual std::unique_ptr<llvm::AdvisoryLock>
   getLock(StringRef ModuleFilename) = 0;
 
-  // TODO: Abstract away timestamps with isUpToDate() and markUpToDate().
   // TODO: Consider exposing a "validation lock" API to prevent multiple clients
   // concurrently noticing an out-of-date module file and validating its inputs.
 
-  /// Returns the timestamp denoting the last time inputs of the module file
-  /// were validated.
-  virtual std::time_t getModuleTimestamp(StringRef ModuleFilename) = 0;
+  /// Checks whether the inputs of the module file were marked as validated.
+  virtual bool isMarkedUpToDate(StringRef ModuleFilename) = 0;
 
-  /// Updates the timestamp denoting the last time inputs of the module file
-  /// were validated.
-  virtual void updateModuleTimestamp(StringRef ModuleFilename) = 0;
+  /// Marks the inputs of the module file as validated.
+  virtual void markUpToDate(StringRef ModuleFilename) = 0;
 
   /// Returns this process's view of the module cache.
   virtual InMemoryModuleCache &getInMemoryModuleCache() = 0;
@@ -58,7 +55,8 @@ 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();
+IntrusiveRefCntPtr<ModuleCache>
+createCrossProcessModuleCache(std::time_t BuildSessionTimestamp);
 } // namespace clang
 
 #endif
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index f20cb2f9f35ae..5b6e31dac39ed 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -270,11 +270,9 @@ class ModuleFile {
   // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()).
   unsigned NumUserInputFiles = 0;
 
-  /// If non-zero, specifies the time when we last validated input
-  /// files.  Zero means we never validated them.
-  ///
-  /// The time is specified in seconds since the start of the Epoch.
-  uint64_t InputFilesValidationTimestamp = 0;
+  /// Specifies whether the input files have been validated (i.e. checked
+  /// whether they are up-to-date).
+  bool InputFilesValidated = false;
 
   // === Source Locations ===
 
diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
index 213e60b39c199..fa11af2be5a67 100644
--- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
+++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h
@@ -20,7 +20,7 @@ namespace tooling {
 namespace dependencies {
 struct ModuleCacheEntry {
   std::shared_mutex CompilationMutex;
-  std::atomic<std::time_t> Timestamp = 0;
+  std::atomic<bool> UpToDate = false;
 };
 
 struct ModuleCacheEntries {
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 35f823e9407db..9b2960299ac8f 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -829,9 +829,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
                                      AST->getFileManager(),
                                      UserFilesAreVolatile);
-  AST->ModCache = createCrossProcessModuleCache();
   AST->HSOpts = std::make_unique<HeaderSearchOptions>(HSOpts);
   AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front());
+  AST->ModCache =
+      createCrossProcessModuleCache(AST->HSOpts->BuildSessionTimestamp);
   AST->HeaderInfo.reset(new HeaderSearch(AST->getHeaderSearchOpts(),
                                          AST->getSourceManager(),
                                          AST->getDiagnostics(),
@@ -1548,7 +1549,8 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
                                      UserFilesAreVolatile);
-  AST->ModCache = createCrossProcessModuleCache();
+  AST->ModCache = createCrossProcessModuleCache(
+      AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp);
 
   return AST;
 }
@@ -1834,7 +1836,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
   AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
   AST->StorePreamblesInMemory = StorePreamblesInMemory;
   AST->PreambleStoragePath = PreambleStoragePath;
-  AST->ModCache = createCrossProcessModuleCache();
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->TUKind = TUKind;
@@ -1843,6 +1844,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
     = IncludeBriefCommentsInCodeCompletion;
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->Invocation = CI;
+  AST->ModCache = createCrossProcessModuleCache(
+      AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp);
   AST->SkipFunctionBodies = SkipFunctionBodies;
   if (ForSerialization)
     AST->WriterData.reset(new ASTWriterData(*AST->ModCache));
@@ -2378,7 +2381,6 @@ bool ASTUnit::serialize(raw_ostream &OS) {
 
   SmallString<128> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
-  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
   ASTWriter Writer(Stream, Buffer, *ModCache, {});
   return serializeUnit(Writer, Buffer, getSema(), OS);
 }
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index b59496babb62c..2ed0cf3da3d6d 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -72,7 +72,9 @@ CompilerInstance::CompilerInstance(
     ModuleCache *ModCache)
     : ModuleLoader(/*BuildingModule=*/ModCache),
       Invocation(std::move(Invocation)),
-      ModCache(ModCache ? ModCache : createCrossProcessModuleCache()),
+      ModCache(ModCache ? ModCache
+                        : createCrossProcessModuleCache(
+                              getHeaderSearchOpts().BuildSessionTimestamp)),
       ThePCHContainerOperations(std::move(PCHContainerOps)) {
   assert(this->Invocation && "Invocation must not be null");
 }
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index a17d6229ee3a1..e877669947796 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3103,8 +3103,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
 
         unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
         if (HSOpts.ModulesValidateOncePerBuildSession &&
-            F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp &&
-            F.Kind == MK_ImplicitModule)
+            F.InputFilesValidated && F.Kind == MK_ImplicitModule)
           N = NumUserInputs;
 
         for (unsigned I = 0; I < N; ++I) {
@@ -4950,10 +4949,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type,
     // timestamp files are up-to-date in this build session.
     for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
       ImportedModule &M = Loaded[I];
-      if (M.Mod->Kind == MK_ImplicitModule &&
-          M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp)
-        getModuleManager().getModuleCache().updateModuleTimestamp(
-            M.Mod->FileName);
+      if (M.Mod->Kind == MK_ImplicitModule && !M.Mod->InputFilesValidated)
+        getModuleManager().getModuleCache().markUpToDate(M.Mod->FileName);
     }
   }
 
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index cccf53de25882..27ddb2b6ebec3 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5394,7 +5394,7 @@ ASTWriter::WriteAST(llvm::PointerUnion<Sema *, Preprocessor *> Subject,
   if (WritingModule && PPRef.getHeaderSearchInfo()
                            .getHeaderSearchOpts()
                            .ModulesValidateOncePerBuildSession)
-    ModCache.updateModuleTimestamp(OutputFile);
+    ModCache.markUpToDate(OutputFile);
 
   if (ShouldCacheASTInMemory) {
     // Construct MemoryBuffer and update buffer manager.
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 4ae49c4ec9a05..43f8ff8d681fe 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -20,7 +20,12 @@ namespace {
 class CrossProcessModuleCache : public ModuleCache {
   InMemoryModuleCache InMemory;
 
+  std::time_t BuildSessionTimestamp;
+
 public:
+  explicit CrossProcessModuleCache(std::time_t BuildSessionTimestamp)
+      : BuildSessionTimestamp(BuildSessionTimestamp) {}
+
   void prepareForGetLock(StringRef ModuleFilename) override {
     // FIXME: Do this in LockFileManager and only if the directory doesn't
     // exist.
@@ -33,16 +38,17 @@ class CrossProcessModuleCache : public ModuleCache {
     return std::make_unique<llvm::LockFileManager>(ModuleFilename);
   }
 
-  std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
+  bool isMarkedUpToDate(StringRef ModuleFilename) override {
     std::string TimestampFilename =
         serialization::ModuleFile::getTimestampFilename(ModuleFilename);
     llvm::sys::fs::file_status Status;
     if (llvm::sys::fs::status(ModuleFilename, Status) != std::error_code{})
-      return 0;
-    return llvm::sys::toTimeT(Status.getLastModificationTime());
+      return false;
+    return llvm::sys::toTimeT(Status.getLastModificationTime()) >
+           BuildSessionTimestamp;
   }
 
-  void updateModuleTimestamp(StringRef ModuleFilename) override {
+  void markUpToDate(StringRef ModuleFilename) override {
     // Overwrite the timestamp file contents so that file's mtime changes.
     std::error_code EC;
     llvm::raw_fd_ostream OS(
@@ -62,6 +68,8 @@ class CrossProcessModuleCache : public ModuleCache {
 };
 } // namespace
 
-IntrusiveRefCntPtr<ModuleCache> clang::createCrossProcessModuleCache() {
-  return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>();
+IntrusiveRefCntPtr<ModuleCache>
+clang::createCrossProcessModuleCache(std::time_t BuildSessionTimestamp) {
+  return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>(
+      BuildSessionTimestamp);
 }
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index e3d7ff4fd82a7..73f1a979dfea6 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -172,11 +172,11 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
   NewModule->Index = Chain.size();
   NewModule->FileName = FileName.str();
   NewModule->ImportLoc = ImportLoc;
-  NewModule->InputFilesValidationTimestamp = 0;
+  NewModule->InputFilesValidated = false;
 
   if (NewModule->Kind == MK_ImplicitModule)
-    NewModule->InputFilesValidationTimestamp =
-        ModCache->getModuleTimestamp(NewModule->FileName);
+    NewModule->InputFilesValidated =
+        ModCache->isMarkedUpToDate(NewModule->FileName);
 
   // Load the contents of the module
   if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
index 80db2d47d940e..ccfe42c092f58 100644
--- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
+++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
@@ -75,29 +75,29 @@ class InProcessModuleCache : public ModuleCache {
     return std::make_unique<ReaderWriterLock>(CompilationMutex);
   }
 
-  std::time_t getModuleTimestamp(StringRef Filename) override {
-    auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
+  bool isMarkedUpToDate(StringRef Filename) override {
+    auto &IsUpToDate = [&]() -> std::atomic<bool> & {
       std::lock_guard<std::mutex> Lock(Entries.Mutex);
       auto &Entry = Entries.Map[Filename];
       if (!Entry)
         Entry = std::make_unique<ModuleCacheEntry>();
-      return Entry->Timestamp;
+      return Entry->UpToDate;
     }();
 
-    return Timestamp.load();
+    return IsUpToDate;
   }
 
-  void updateModuleTimestamp(StringRef Filename) override {
+  void markUpToDate(StringRef Filename) override {
     // Note: This essentially replaces FS contention with mutex contention.
-    auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
+    auto &IsUpToDate = [&]() -> std::atomic<bool> & {
       std::lock_guard<std::mutex> Lock(Entries.Mutex);
       auto &Entry = Entries.Map[Filename];
       if (!Entry)
         Entry = std::make_unique<ModuleCacheEntry>();
-      return Entry->Timestamp;
+      return Entry->UpToDate;
     }();
 
-    Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
+    IsUpToDate = true;
   }
 
   InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }

Copy link

github-actions bot commented May 7, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- clang-tools-extra/clangd/ModulesBuilder.cpp clang/include/clang/Serialization/ModuleCache.h clang/include/clang/Serialization/ModuleFile.h clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Frontend/CompilerInstance.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ModuleCache.cpp clang/lib/Serialization/ModuleManager.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
View the diff from clang-format here.
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index eb8483dcf..3fe062e68 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -826,9 +826,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
   AST->Diagnostics = Diags;
   AST->FileMgr = new FileManager(FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
-  AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
-                                     AST->getFileManager(),
-                                     UserFilesAreVolatile);
+  AST->SourceMgr = new SourceManager(
+      AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile);
   AST->HSOpts = std::make_unique<HeaderSearchOptions>(HSOpts);
   AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front());
   AST->ModCache =

Copy link
Contributor

@Bigcheese Bigcheese left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, looks like it keeps the existing semantics.

@jansvoboda11 jansvoboda11 merged commit 960afcc into llvm:main May 14, 2025
10 of 11 checks passed
@jansvoboda11 jansvoboda11 deleted the timestamp-less-api branch May 14, 2025 21:31
@qinkunbao
Copy link
Member

Hi, can you check if this PR broke the build bot?
https://lab.llvm.org/buildbot/#/builders/85/builds/8774

@qinkunbao
Copy link
Member

Hi, I've reverted the pull request to address the build bot failure. Please feel free to update the PR with the necessary fixes and resubmit it. Thank you for your understanding.

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category clang-tools-extra clangd
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.