Author: Jan Svoboda
Date: 2025-05-14T14:31:23-07:00
New Revision: 960afcc90e8fb75b725ed331f4bc60eb2398d6e5

URL: 
https://github.com/llvm/llvm-project/commit/960afcc90e8fb75b725ed331f4bc60eb2398d6e5
DIFF: 
https://github.com/llvm/llvm-project/commit/960afcc90e8fb75b725ed331f4bc60eb2398d6e5.diff

LOG: [clang][modules] Timestamp-less validation API (#138983)

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.

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
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/DependencyScanningService.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
index 4e97c7bc9f36e..22f670cb821e2 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
@@ -12,7 +12,6 @@
 #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
 #include "clang/Tooling/DependencyScanning/InProcessModuleCache.h"
 #include "llvm/ADT/BitmaskEnum.h"
-#include "llvm/Support/Chrono.h"
 
 namespace clang {
 namespace tooling {
@@ -85,9 +84,7 @@ class DependencyScanningService {
   DependencyScanningService(
       ScanningMode Mode, ScanningOutputFormat Format,
       ScanningOptimizations OptimizeArgs = ScanningOptimizations::Default,
-      bool EagerLoadModules = false, bool TraceVFS = false,
-      std::time_t BuildSessionTimestamp =
-          llvm::sys::toTimeT(std::chrono::system_clock::now()));
+      bool EagerLoadModules = false, bool TraceVFS = false);
 
   ScanningMode getMode() const { return Mode; }
 
@@ -105,8 +102,6 @@ class DependencyScanningService {
 
   ModuleCacheEntries &getModuleCacheEntries() { return ModCacheEntries; }
 
-  std::time_t getBuildSessionTimestamp() const { return BuildSessionTimestamp; 
}
-
 private:
   const ScanningMode Mode;
   const ScanningOutputFormat Format;
@@ -120,8 +115,6 @@ class DependencyScanningService {
   DependencyScanningFilesystemSharedCache SharedCache;
   /// The global module cache entries.
   ModuleCacheEntries ModCacheEntries;
-  /// The build session timestamp.
-  std::time_t BuildSessionTimestamp;
 };
 
 } // end namespace dependencies

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 5a79fe070c384..eb8483dcfc008 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 503d36467653e..b3a23e64dbada 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 d068f5e163176..2462b5c1f1421 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 = ForceValidateUserInputs ? NumUserInputs : 0;
 
         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 1b3d3c22aa9f5..491149b33f1d8 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5391,7 +5391,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 fa9533b7efd78..9fd7505726973 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -174,11 +174,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/DependencyScanningService.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
index 7f40c99f07287..96fe40c079c65 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -14,8 +14,6 @@ using namespace dependencies;
 
 DependencyScanningService::DependencyScanningService(
     ScanningMode Mode, ScanningOutputFormat Format,
-    ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS,
-    std::time_t BuildSessionTimestamp)
+    ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS)
     : Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs),
-      EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS),
-      BuildSessionTimestamp(BuildSessionTimestamp) {}
+      EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS) {}

diff  --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 21eea72b198b3..e30e997e40581 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -428,10 +428,6 @@ class DependencyScanningAction : public 
tooling::ToolAction {
     ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
         true;
 
-    if (ScanInstance.getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
-      ScanInstance.getHeaderSearchOpts().BuildSessionTimestamp =
-          Service.getBuildSessionTimestamp();
-
     ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
     ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
     // This will prevent us compiling individual modules asynchronously since

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; }


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to