[clang] [clang][modules] Remove `ModuleFile::File` (PR #185995)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 19 16:02:52 PDT 2026


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

>From f92608f3d87dd35bcc8610fe3a5af985c1728d3c Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Mon, 9 Mar 2026 20:52:07 -0700
Subject: [PATCH 1/2] [clang][modules] Remove `ModuleFile::File`

---
 clang/include/clang/Basic/Module.h            |  6 +--
 clang/include/clang/Frontend/ASTUnit.h        |  2 +-
 clang/include/clang/Serialization/ASTReader.h |  4 +-
 clang/include/clang/Serialization/ASTWriter.h |  2 +-
 .../include/clang/Serialization/ModuleFile.h  | 13 ++---
 .../clang/Serialization/ModuleManager.h       |  8 ---
 .../DependencyScannerImpl.cpp                 |  9 ++--
 clang/lib/Frontend/ASTUnit.cpp                |  4 +-
 clang/lib/Frontend/DependencyFile.cpp         |  2 +-
 clang/lib/Frontend/FrontendAction.cpp         | 18 ++++++-
 .../lib/Frontend/Rewrite/FrontendActions.cpp  | 15 +++---
 clang/lib/Serialization/ASTReader.cpp         | 14 ++---
 clang/lib/Serialization/ASTWriter.cpp         | 14 ++---
 clang/lib/Serialization/GlobalModuleIndex.cpp |  3 +-
 clang/lib/Serialization/ModuleManager.cpp     | 52 ++++++-------------
 .../prebuilt-modules-in-stable-dirs.c         |  1 +
 clang/tools/libclang/CXIndexDataConsumer.cpp  |  5 +-
 clang/tools/libclang/CXIndexDataConsumer.h    |  2 +-
 clang/tools/libclang/Indexing.cpp             |  9 ++--
 19 files changed, 82 insertions(+), 101 deletions(-)

diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h
index 016cc2ce684b8..cb996430076e2 100644
--- a/clang/include/clang/Basic/Module.h
+++ b/clang/include/clang/Basic/Module.h
@@ -54,10 +54,6 @@ class TargetInfo;
 /// Describes the name of a module.
 using ModuleId = SmallVector<std::pair<std::string, SourceLocation>, 2>;
 
-namespace serialization {
-class ModuleManager;
-} // namespace serialization
-
 /// Deduplication key for a loaded module file in \c ModuleManager.
 ///
 /// For implicitly-built modules, this is the \c DirectoryEntry of the module
@@ -77,7 +73,7 @@ class ModuleFileKey {
   /// for other kinds of module files.
   std::string ImplicitModulePathSuffix;
 
-  friend class serialization::ModuleManager;
+  friend class ASTReader;
   friend class ModuleFileName;
   friend llvm::DenseMapInfo<ModuleFileKey>;
 
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index 7f307d1670dc6..b187494e449f2 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -679,7 +679,7 @@ class ASTUnit {
   bool visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn);
 
   /// Get the PCH file if one was included.
-  OptionalFileEntryRef getPCHFile();
+  std::optional<StringRef> getPCHFile();
 
   /// Returns true if the ASTUnit was constructed from a serialized
   /// module file.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index e9706d0ea2f2b..d6f75e5973c45 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -223,7 +223,7 @@ class ASTReaderListener {
   }
 
   /// This is called for each AST file loaded.
-  virtual void visitModuleFile(StringRef Filename,
+  virtual void visitModuleFile(ModuleFileName Filename,
                                serialization::ModuleKind Kind) {}
 
   /// Returns true if this \c ASTReaderListener wants to receive the
@@ -313,7 +313,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
   void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) override;
   bool needsInputFileVisitation() override;
   bool needsSystemInputFileVisitation() override;
-  void visitModuleFile(StringRef Filename,
+  void visitModuleFile(ModuleFileName Filename,
                        serialization::ModuleKind Kind) override;
   bool visitInputFile(StringRef Filename, bool isSystem,
                       bool isOverridden, bool isExplicitModule) override;
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index 0f3993ad01693..be2fbdf1ade83 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -702,7 +702,7 @@ class ASTWriter : public ASTDeserializationListener,
   /// Get a timestamp for output into the AST file. The actual timestamp
   /// of the specified file may be ignored if we have been instructed to not
   /// include timestamps in the output file.
-  time_t getTimestampForOutput(const FileEntry *E) const;
+  time_t getTimestampForOutput(time_t ModTime) const;
 
   /// Write a precompiled header or a module with the AST produced by the
   /// \c Sema object, or a dependency scanner module with the preprocessor state
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index e761cadfcd86f..303bd65a8aad0 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -144,10 +144,8 @@ enum class InputFilesValidation {
 /// other modules.
 class ModuleFile {
 public:
-  ModuleFile(ModuleKind Kind, ModuleFileKey FileKey, FileEntryRef File,
-             unsigned Generation)
-      : Kind(Kind), FileKey(std::move(FileKey)), File(File),
-        Generation(Generation) {}
+  ModuleFile(ModuleKind Kind, ModuleFileKey FileKey, unsigned Generation)
+      : Kind(Kind), FileKey(std::move(FileKey)), Generation(Generation) {}
   ~ModuleFile();
 
   // === General information ===
@@ -201,8 +199,11 @@ class ModuleFile {
   /// Whether the top-level module has been read from the AST file.
   bool DidReadTopLevelSubmodule = false;
 
-  /// The file entry for the module file.
-  FileEntryRef File;
+  /// Size of the module file.
+  off_t Size = 0;
+
+  /// Modification of the module file.
+  time_t ModTime = 0;
 
   /// The signature of the module file, which may be used instead of the size
   /// and modification time to identify this particular file.
diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h
index 162856f2f14c0..1ef9aeee7e1fd 100644
--- a/clang/include/clang/Serialization/ModuleManager.h
+++ b/clang/include/clang/Serialization/ModuleManager.h
@@ -172,17 +172,9 @@ class ModuleManager {
   /// Returns the module associated with the given index
   ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }
 
-  /// Returns the module associated with the given file name.
-  /// Soon to be removed.
-  ModuleFile *lookupByFileName(StringRef FileName) const;
-
   /// Returns the module associated with the given module name.
   ModuleFile *lookupByModuleName(StringRef ModName) const;
 
-  /// Returns the module associated with the given module file.
-  /// Soon to be removed.
-  ModuleFile *lookup(const FileEntry *File) const;
-
   /// Returns the module associated with the given module file name.
   ModuleFile *lookupByFileName(ModuleFileName FileName) const;
 
diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index 20284c0d9165a..f882713a8b76d 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -135,7 +135,7 @@ class PrebuiltModuleListener : public ASTReaderListener {
   }
 
   /// Update which module that is being actively traversed.
-  void visitModuleFile(StringRef Filename,
+  void visitModuleFile(ModuleFileName Filename,
                        serialization::ModuleKind Kind) override {
     // If the CurrentFile is not
     // considered stable, update any of it's transitive dependents.
@@ -144,7 +144,7 @@ class PrebuiltModuleListener : public ASTReaderListener {
         !PrebuiltEntryIt->second.isInStableDir())
       PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
           PrebuiltModulesASTMap);
-    CurrentFile = Filename;
+    CurrentFile = Filename.str();
   }
 
   /// Check the header search options for a given module when considering
@@ -206,7 +206,7 @@ static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
                                   CI.getHeaderSearchOpts(), CI.getLangOpts(),
                                   Diags, StableDirs);
 
-  Listener.visitModuleFile(PrebuiltModuleFilename,
+  Listener.visitModuleFile(ModuleFileName::makeExplicit(PrebuiltModuleFilename),
                            serialization::MK_ExplicitModule);
   if (ASTReader::readASTFileControlBlock(
           PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
@@ -216,7 +216,8 @@ static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
     return true;
 
   while (!Worklist.empty()) {
-    Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule);
+    Listener.visitModuleFile(ModuleFileName::makeExplicit(Worklist.back()),
+                             serialization::MK_ExplicitModule);
     if (ASTReader::readASTFileControlBlock(
             Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
             CI.getPCHContainerReader(),
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 1e10178285bbd..05ae1f348f920 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -2443,7 +2443,7 @@ bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
   return true;
 }
 
-OptionalFileEntryRef ASTUnit::getPCHFile() {
+std::optional<StringRef> ASTUnit::getPCHFile() {
   if (!Reader)
     return std::nullopt;
 
@@ -2466,7 +2466,7 @@ OptionalFileEntryRef ASTUnit::getPCHFile() {
     return true;
   });
   if (Mod)
-    return Mod->File;
+    return Mod->FileName;
 
   return std::nullopt;
 }
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index 25584b4900228..64629abcaeb52 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -154,7 +154,7 @@ struct DepCollectorASTListener : public ASTReaderListener {
   bool needsSystemInputFileVisitation() override {
     return DepCollector.needSystemDependencies();
   }
-  void visitModuleFile(StringRef Filename,
+  void visitModuleFile(ModuleFileName Filename,
                        serialization::ModuleKind Kind) override {
     DepCollector.maybeAddDependency(Filename, /*FromModule*/ true,
                                     /*IsSystem*/ false, /*IsModuleFile*/ true,
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 81788d17acc4d..c3d1d802dfe04 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -850,6 +850,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
   if (!BeginInvocation(CI))
     return false;
 
+  // The list of module files the input AST file depends on. This is separate
+  // from FrontendOptions::ModuleFiles, because those only represent explicit
+  // modules, while this is capable of representing implicit ones too.
+  SmallVector<ModuleFileName> ModuleFiles;
+
   // If we're replaying the build of an AST file, import it and set up
   // the initial state from its build.
   if (ReplayASTFile) {
@@ -892,7 +897,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
 
       for (serialization::ModuleFile &MF : MM)
         if (&MF != &PrimaryModule)
-          CI.getFrontendOpts().ModuleFiles.emplace_back(MF.FileName.str());
+          ModuleFiles.emplace_back(MF.FileName);
 
       ASTReader->visitTopLevelModuleMaps(PrimaryModule, [&](FileEntryRef FE) {
         CI.getFrontendOpts().ModuleMapFiles.push_back(
@@ -1296,6 +1301,17 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
           diag::warn_eagerly_load_for_standard_cplusplus_modules);
   }
 
+  // If we were asked to load any module files by the ASTUnit, do so now.
+  for (const auto &ModuleFile : ModuleFiles) {
+    serialization::ModuleFile *Loaded = nullptr;
+    if (!CI.loadModuleFile(ModuleFile, Loaded))
+      return false;
+
+    if (Loaded && Loaded->StandardCXXModule)
+      CI.getDiagnostics().Report(
+          diag::warn_eagerly_load_for_standard_cplusplus_modules);
+  }
+
   // If there is a layout overrides file, attach an external AST source that
   // provides the layouts from that file.
   if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index ef6f9ccf87848..1e12d3a6ea3df 100644
--- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -205,25 +205,22 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
   CompilerInstance &CI;
   std::weak_ptr<raw_ostream> Out;
 
-  llvm::DenseSet<const FileEntry*> Rewritten;
+  llvm::DenseSet<const serialization::ModuleFile *> Rewritten;
 
 public:
   RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
       : CI(CI), Out(Out) {}
 
-  void visitModuleFile(StringRef Filename,
+  void visitModuleFile(ModuleFileName Filename,
                        serialization::ModuleKind Kind) override {
-    auto File = CI.getFileManager().getOptionalFileRef(Filename);
-    assert(File && "missing file for loaded module?");
+    serialization::ModuleFile *MF =
+        CI.getASTReader()->getModuleManager().lookupByFileName(Filename);
+    assert(MF && "missing module file for loaded module?");
 
     // Only rewrite each module file once.
-    if (!Rewritten.insert(*File).second)
+    if (!Rewritten.insert(MF).second)
       return;
 
-    serialization::ModuleFile *MF =
-        CI.getASTReader()->getModuleManager().lookup(*File);
-    assert(MF && "missing module file for loaded module?");
-
     // Not interested in PCH / preambles.
     if (!MF->isModule())
       return;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 03b1b02859b81..9274d4cc6f0fa 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -240,7 +240,7 @@ bool ChainedASTReaderListener::needsSystemInputFileVisitation() {
   Second->needsSystemInputFileVisitation();
 }
 
-void ChainedASTReaderListener::visitModuleFile(StringRef Filename,
+void ChainedASTReaderListener::visitModuleFile(ModuleFileName Filename,
                                                ModuleKind Kind) {
   First->visitModuleFile(Filename, Kind);
   Second->visitModuleFile(Filename, Kind);
@@ -3193,8 +3193,7 @@ ASTReader::getModuleForRelocationChecks(ModuleFile &F, bool DirectoryCheck) {
   if (HSOpts.ModulesValidateOncePerBuildSession && IsImplicitModule) {
     if (F.InputFilesValidationTimestamp >= HSOpts.BuildSessionTimestamp)
       return {std::nullopt, IgnoreError};
-    if (static_cast<uint64_t>(F.File.getModificationTime()) >=
-        HSOpts.BuildSessionTimestamp)
+    if (static_cast<uint64_t>(F.ModTime) >= HSOpts.BuildSessionTimestamp)
       return {std::nullopt, IgnoreError};
   }
 
@@ -4593,10 +4592,11 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
     uint16_t Len = endian::readNext<uint16_t, llvm::endianness::little>(Data);
     StringRef Name = StringRef((const char*)Data, Len);
     Data += Len;
-    ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule ||
-                              Kind == MK_ImplicitModule
-                          ? ModuleMgr.lookupByModuleName(Name)
-                          : ModuleMgr.lookupByFileName(Name));
+    ModuleFile *OM =
+        (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule ||
+                 Kind == MK_ImplicitModule
+             ? ModuleMgr.lookupByModuleName(Name)
+             : ModuleMgr.lookupByFileName(ModuleFileName::makeExplicit(Name)));
     if (!OM) {
       std::string Msg = "refers to unknown module, cannot find ";
       Msg.append(std::string(Name));
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index e3db39a1acb74..2b0808ad5ad5e 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1598,8 +1598,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, StringRef isysroot) {
       } else {
         // If we have calculated signature, there is no need to store
         // the size or timestamp.
-        Record.push_back(M.Signature ? 0 : M.File.getSize());
-        Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File));
+        Record.push_back(M.Signature ? 0 : M.Size);
+        Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.ModTime));
 
         llvm::append_range(Blob, M.Signature);
 
@@ -1963,7 +1963,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr) {
           INPUT_FILE,
           InputFileOffsets.size(),
           (uint64_t)Entry.File.getSize(),
-          (uint64_t)getTimestampForOutput(Entry.File),
+          (uint64_t)getTimestampForOutput(Entry.File.getModificationTime()),
           Entry.BufferOverridden,
           Entry.IsTransient,
           Entry.IsTopLevel,
@@ -2280,8 +2280,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
     bool Included = HFI->IsLocallyIncluded || PP->alreadyIncluded(*File);
 
     HeaderFileInfoTrait::key_type Key = {
-      Filename, File->getSize(), getTimestampForOutput(*File)
-    };
+        Filename, File->getSize(),
+        getTimestampForOutput(File->getModificationTime())};
     HeaderFileInfoTrait::data_type Data = {
       *HFI, Included, HS.getModuleMap().findResolvedModulesForHeader(*File), {}
     };
@@ -5488,8 +5488,8 @@ const LangOptions &ASTWriter::getLangOpts() const {
   return PP->getLangOpts();
 }
 
-time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const {
-  return IncludeTimestamps ? E->getModificationTime() : 0;
+time_t ASTWriter::getTimestampForOutput(time_t ModTime) const {
+  return IncludeTimestamps ? ModTime : 0;
 }
 
 ASTFileSignature
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 8ab8717776c3d..3f6b8e68e38f3 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -342,8 +342,7 @@ bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
   //  If the size and modification time match what we expected, record this
   // module file.
   bool Failed = true;
-  if (File->File.getSize() == Info.Size &&
-      File->File.getModificationTime() == Info.ModTime) {
+  if (File->Size == Info.Size && File->ModTime == Info.ModTime) {
     Info.File = File;
     ModulesByFile[File] = Known->second;
 
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index abb5b7955c8fa..6768028cd3ae3 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -40,15 +40,6 @@
 using namespace clang;
 using namespace serialization;
 
-ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
-  auto Entry = FileMgr.getOptionalFileRef(Name, /*OpenFile=*/false,
-                                          /*CacheFailure=*/false);
-  if (Entry)
-    return lookup(*Entry);
-
-  return nullptr;
-}
-
 ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
   if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
     if (const ModuleFileName *FileName = Mod->getASTFileName())
@@ -57,10 +48,6 @@ ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
   return nullptr;
 }
 
-ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
-  return lookup(ModuleFileKey(File));
-}
-
 ModuleFile *ModuleManager::lookupByFileName(ModuleFileName Name) const {
   std::optional<ModuleFileKey> Key = Name.makeKey(FileMgr);
   return Key ? lookup(*Key) : nullptr;
@@ -79,16 +66,14 @@ ModuleManager::lookupBuffer(StringRef Name) {
   return std::move(InMemoryBuffers[*Entry]);
 }
 
-static bool checkModuleFile(const FileEntry *File, off_t ExpectedSize,
+static bool checkModuleFile(off_t Size, time_t ModTime, off_t ExpectedSize,
                             time_t ExpectedModTime, std::string &ErrorStr) {
-  assert(File && "Checking expectations of a non-existent module file");
-
-  if (ExpectedSize && ExpectedSize != File->getSize()) {
+  if (ExpectedSize && ExpectedSize != Size) {
     ErrorStr = "module file has a different size than expected";
     return true;
   }
 
-  if (ExpectedModTime && ExpectedModTime != File->getModificationTime()) {
+  if (ExpectedModTime && ExpectedModTime != ModTime) {
     ErrorStr = "module file has a different modification time than expected";
     return true;
   }
@@ -153,8 +138,8 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
   // Check whether we already loaded this module, before
   if (ModuleFile *ModuleEntry = lookup(*FileKey)) {
     // Check file properties.
-    if (checkModuleFile(ModuleEntry->File, ExpectedSize, ExpectedModTime,
-                        ErrorStr))
+    if (checkModuleFile(ModuleEntry->Size, ModuleEntry->ModTime, ExpectedSize,
+                        ExpectedModTime, ErrorStr))
       return OutOfDate;
 
     // Check the stored signature.
@@ -167,7 +152,8 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
   }
 
   // Load the contents of the module
-  OptionalFileEntryRef Entry;
+  off_t Size = ExpectedSize;
+  time_t ModTime = ExpectedModTime;
   llvm::MemoryBuffer *ModuleBuffer = nullptr;
   std::unique_ptr<llvm::MemoryBuffer> NewFileBuffer = nullptr;
   if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
@@ -184,7 +170,7 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
     // import it earlier.
     return OutOfDate;
   } else {
-    Entry =
+    OptionalFileEntryRef Entry =
         expectedToOptional(FileName == StringRef("-")
                                ? FileMgr.getSTDIN()
                                : FileMgr.getFileRef(FileName, /*OpenFile=*/true,
@@ -198,7 +184,8 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
     // size/mtime expectations even when pulling the module file out of the
     // in-memory module cache or the provided in-memory buffers.
     // Check file properties.
-    if (checkModuleFile(*Entry, ExpectedSize, ExpectedModTime, ErrorStr))
+    if (checkModuleFile(Entry->getSize(), Entry->getModificationTime(),
+                        ExpectedSize, ExpectedModTime, ErrorStr))
       return OutOfDate;
 
     // Get a buffer of the file and close the file descriptor when done.
@@ -216,24 +203,20 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
       return Missing;
     }
 
+    Size = Entry->getSize();
+    ModTime = Entry->getModificationTime();
     NewFileBuffer = std::move(*Buf);
     ModuleBuffer = NewFileBuffer.get();
   }
 
-  if (!Entry) {
-    // Unless we loaded the buffer from a freshly open file (else branch above),
-    // we don't have any FileEntry for this ModuleFile. Make one up.
-    // FIXME: Make it so that ModuleFile is not tied to a FileEntry.
-    Entry = FileMgr.getVirtualFileRef(FileName, ExpectedSize, ExpectedModTime);
-  }
-
   // Allocate a new module.
-  auto NewModule =
-      std::make_unique<ModuleFile>(Type, *FileKey, *Entry, Generation);
+  auto NewModule = std::make_unique<ModuleFile>(Type, *FileKey, Generation);
   NewModule->Index = Chain.size();
   NewModule->FileName = FileName;
   NewModule->ImportLoc = ImportLoc;
   NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
+  NewModule->Size = Size;
+  NewModule->ModTime = ModTime;
   NewModule->Buffer = ModuleBuffer;
   // Initialize the stream.
   NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
@@ -251,11 +234,6 @@ ModuleManager::AddModuleResult ModuleManager::addModule(
   // We're keeping this module. Store it in the map.
   Module = Modules[*FileKey] = NewModule.get();
 
-  // Support clients that still rely on being able to look up ModuleFile with
-  // normal FileEntry.
-  // TODO: Remove this.
-  Modules[ModuleFileKey(*Entry)] = Module;
-
   updateModuleImports(*NewModule, ImportedBy, ImportLoc);
 
   if (!NewModule->isModule())
diff --git a/clang/test/ClangScanDeps/prebuilt-modules-in-stable-dirs.c b/clang/test/ClangScanDeps/prebuilt-modules-in-stable-dirs.c
index 39b2863d966c3..29fc9dda2953c 100644
--- a/clang/test/ClangScanDeps/prebuilt-modules-in-stable-dirs.c
+++ b/clang/test/ClangScanDeps/prebuilt-modules-in-stable-dirs.c
@@ -15,6 +15,7 @@
 // RUN: sed -e "s|DIR|%/t|g" %t/compile-pch.json.in > %t/compile-pch.json
 // RUN: clang-scan-deps -compilation-database %t/compile-pch.json \
 // RUN:   -j 1 -format experimental-full > %t/deps_pch.db
+// FIXME: We can't just build the PCH implicitly and use it in the scan.
 // RUN: %clang -x c-header -c %t/prebuild.h -isysroot %t/MacOSX.sdk \
 // RUN:   -I%t/BuildDir -ivfsoverlay %t/overlay.json \
 // RUN:   -I %t/MacOSX.sdk/usr/include -fmodules -fmodules-cache-path=%t/module-cache \
diff --git a/clang/tools/libclang/CXIndexDataConsumer.cpp b/clang/tools/libclang/CXIndexDataConsumer.cpp
index 265d5876ee7a6..8babcccf38c51 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -517,10 +517,13 @@ void CXIndexDataConsumer::importedModule(const ImportDecl *ImportD) {
   (void)astFile;
 }
 
-void CXIndexDataConsumer::importedPCH(FileEntryRef File) {
+void CXIndexDataConsumer::importedPCH(StringRef FileName) {
   if (!CB.importedASTFile)
     return;
 
+  FileManager &FileMgr = cxtu::getASTUnit(CXTU)->getFileManager();
+  OptionalFileEntryRef File = FileMgr.getOptionalFileRef(FileName);
+
   CXIdxImportedASTFileInfo Info = {
                                     cxfile::makeCXFile(File),
                                     /*module=*/nullptr,
diff --git a/clang/tools/libclang/CXIndexDataConsumer.h b/clang/tools/libclang/CXIndexDataConsumer.h
index b207db7cde6d7..3608f76a6fb8f 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.h
+++ b/clang/tools/libclang/CXIndexDataConsumer.h
@@ -367,7 +367,7 @@ class CXIndexDataConsumer : public index::IndexDataConsumer {
                       bool isModuleImport);
 
   void importedModule(const ImportDecl *ImportD);
-  void importedPCH(FileEntryRef File);
+  void importedPCH(StringRef FileName);
 
   void startedTranslationUnit();
 
diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index 75323d70afcfe..4e57b63490112 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -351,11 +351,8 @@ class IndexingFrontendAction : public ASTFrontendAction {
                                                  StringRef InFile) override {
     PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
 
-    if (!PPOpts.ImplicitPCHInclude.empty()) {
-      if (auto File =
-              CI.getFileManager().getOptionalFileRef(PPOpts.ImplicitPCHInclude))
-        DataConsumer->importedPCH(*File);
-    }
+    if (!PPOpts.ImplicitPCHInclude.empty())
+      DataConsumer->importedPCH(PPOpts.ImplicitPCHInclude);
 
     DataConsumer->setASTContext(CI.getASTContextPtr());
     Preprocessor &PP = CI.getPreprocessor();
@@ -695,7 +692,7 @@ static CXErrorCode clang_indexTranslationUnit_Impl(
 
   ASTUnit::ConcurrencyCheck Check(*Unit);
 
-  if (OptionalFileEntryRef PCHFile = Unit->getPCHFile())
+  if (std::optional<StringRef> PCHFile = Unit->getPCHFile())
     DataConsumer.importedPCH(*PCHFile);
 
   FileManager &FileMgr = Unit->getFileManager();

>From 8abf3cc48d6ddff6e1182168920765b3ea725f46 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 19 Mar 2026 16:02:40 -0700
Subject: [PATCH 2/2] End an unnecessary friendship

---
 clang/include/clang/Basic/Module.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h
index cb996430076e2..70668860dadc2 100644
--- a/clang/include/clang/Basic/Module.h
+++ b/clang/include/clang/Basic/Module.h
@@ -73,7 +73,6 @@ class ModuleFileKey {
   /// for other kinds of module files.
   std::string ImplicitModulePathSuffix;
 
-  friend class ASTReader;
   friend class ModuleFileName;
   friend llvm::DenseMapInfo<ModuleFileKey>;
 



More information about the cfe-commits mailing list