https://github.com/Bigcheese updated 
https://github.com/llvm/llvm-project/pull/181916

>From ce9695a981657b32c28b7ea444f8b8f846249cab Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Thu, 12 Feb 2026 16:45:21 -0800
Subject: [PATCH 1/6] [clang][modulemap] Lazily load module maps by header name

After header search has found a header it looks for module maps that
cover that header. This patch uses the parsed representation of module
maps to do this search instead of relying on FileEntryRef lookups
after stating headers in module maps.

This behavior is currently gated behind the
-fmodules-lazy-load-module-maps -cc1 flag.
---
 clang/include/clang/Lex/HeaderSearch.h        |  19 +-
 clang/include/clang/Lex/HeaderSearchOptions.h |   7 +-
 clang/include/clang/Lex/ModuleMap.h           |  23 ++
 clang/include/clang/Options/Options.td        |   3 +
 clang/lib/Frontend/CompilerInstance.cpp       |   4 +
 clang/lib/Lex/HeaderSearch.cpp                | 257 +++++++++++++++---
 clang/lib/Lex/ModuleMap.cpp                   |  36 +++
 clang/lib/Serialization/ASTReader.cpp         |  22 +-
 clang/test/Modules/lazy-by-header-extern.c    |  69 +++++
 clang/test/Modules/lazy-by-header-lookup.c    |  38 +++
 clang/test/Modules/lazy-by-header-nested.c    |  46 ++++
 clang/test/Modules/lazy-by-header-private.c   |  41 +++
 .../Modules/lazy-by-header-umbrella-dir.c     |  66 +++++
 .../Modules/lazy-by-header-umbrella-header.c  |  46 ++++
 clang/test/Modules/lazy-by-name-lookup.c      |   4 +-
 15 files changed, 629 insertions(+), 52 deletions(-)
 create mode 100644 clang/test/Modules/lazy-by-header-extern.c
 create mode 100644 clang/test/Modules/lazy-by-header-lookup.c
 create mode 100644 clang/test/Modules/lazy-by-header-nested.c
 create mode 100644 clang/test/Modules/lazy-by-header-private.c
 create mode 100644 clang/test/Modules/lazy-by-header-umbrella-dir.c
 create mode 100644 clang/test/Modules/lazy-by-header-umbrella-header.c

diff --git a/clang/include/clang/Lex/HeaderSearch.h 
b/clang/include/clang/Lex/HeaderSearch.h
index 252e421e796f4..83c37d9dced55 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -334,11 +334,20 @@ class HeaderSearch {
 
   struct ModuleMapDirectoryState {
     OptionalFileEntryRef ModuleMapFile;
+    OptionalFileEntryRef PrivateModuleMapFile;
     enum {
       Parsed,
       Loaded,
       Invalid,
     } Status;
+
+    /// Relative header path -> list of module names
+    llvm::StringMap<llvm::SmallVector<StringRef, 1>> HeaderToModules{};
+    /// Relative dir path -> module name
+    llvm::SmallVector<std::pair<std::string, StringRef>, 2>
+        UmbrellaDirModules{};
+    /// List of module names with umbrella header decls
+    llvm::SmallVector<StringRef, 2> UmbrellaHeaderModules{};
   };
 
   /// Describes whether a given directory has a module map in it.
@@ -372,6 +381,13 @@ class HeaderSearch {
   /// map their keys to the SearchDir index of their header map.
   void indexInitialHeaderMaps();
 
+  /// Build the header to module cache for a directory's module map.
+  ///
+  /// This fills a ModuleMapDirectoryState with information from its 
directory's
+  /// module map.
+  void buildHeaderToModuleCache(DirectoryEntryRef Dir,
+                                ModuleMapDirectoryState &MMState);
+
 public:
   HeaderSearch(const HeaderSearchOptions &HSOpts, SourceManager &SourceMgr,
                DiagnosticsEngine &Diags, const LangOptions &LangOpts,
@@ -953,7 +969,8 @@ class HeaderSearch {
                                                 bool IsSystem,
                                                 DirectoryEntryRef Dir,
                                                 FileID ID = FileID(),
-                                                unsigned *Offset = nullptr);
+                                                unsigned *Offset = nullptr,
+                                                bool DiagnosePrivMMap = false);
 
   ModuleMapResult parseModuleMapFileImpl(FileEntryRef File, bool IsSystem,
                                          DirectoryEntryRef Dir,
diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h 
b/clang/include/clang/Lex/HeaderSearchOptions.h
index 2f33c0749f02a..d8d638b635ec9 100644
--- a/clang/include/clang/Lex/HeaderSearchOptions.h
+++ b/clang/include/clang/Lex/HeaderSearchOptions.h
@@ -283,6 +283,11 @@ class HeaderSearchOptions {
   LLVM_PREFERRED_TYPE(bool)
   unsigned AllowModuleMapSubdirectorySearch : 1;
 
+  /// Whether modules from module maps should only be loaded when used, not 
just
+  /// when parsed.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned LazyLoadModMaps : 1;
+
   HeaderSearchOptions(StringRef _Sysroot = "/")
       : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false),
         ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false),
@@ -301,7 +306,7 @@ class HeaderSearchOptions {
         ModulesPruneNonAffectingModuleMaps(true), ModulesHashContent(false),
         ModulesSerializeOnlyPreprocessor(false),
         ModulesStrictContextHash(false), ModulesIncludeVFSUsage(false),
-        AllowModuleMapSubdirectorySearch(true) {}
+        AllowModuleMapSubdirectorySearch(true), LazyLoadModMaps(false) {}
 
   /// AddPath - Add the \p Path path to the specified \p Group list.
   void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
diff --git a/clang/include/clang/Lex/ModuleMap.h 
b/clang/include/clang/Lex/ModuleMap.h
index 6eba7cad0890b..585bd32a16ce5 100644
--- a/clang/include/clang/Lex/ModuleMap.h
+++ b/clang/include/clang/Lex/ModuleMap.h
@@ -435,6 +435,18 @@ class ModuleMap {
   KnownHeader findModuleForHeader(FileEntryRef File, bool AllowTextual = false,
                                   bool AllowExcluded = false);
 
+  /// Find the FileEntry for an umbrella header in a module as if it was 
written
+  /// in the module map as a header decl.
+  ///
+  /// \param M The module in which we're resolving the header directive.
+  /// \param NameAsWritten The name of the header as written in the module map.
+  /// \param RelativePathName Filled in with the relative path name from the
+  ///        module to the resolved header.
+  /// \return The resolved file, if any.
+  OptionalFileEntryRef
+  findUmbrellaHeaderForModule(Module *M, std::string NameAsWritten,
+                              SmallVectorImpl<char> &RelativePathName);
+
   /// Retrieve all the modules that contain the given header file. Note that
   /// this does not implicitly load module maps, except for builtin headers,
   /// and does not consult the external source. (Those checks are the
@@ -717,6 +729,8 @@ class ModuleMap {
                           DirectoryEntryRef Dir, FileID ID = FileID(),
                           SourceLocation ExternModuleLoc = SourceLocation());
 
+  void loadAllParsedModules();
+
   /// Load the given module map file, and record any modules we
   /// encounter.
   ///
@@ -743,6 +757,15 @@ class ModuleMap {
                             unsigned *Offset = nullptr,
                             SourceLocation ExternModuleLoc = SourceLocation());
 
+  /// Get the ModuleMapFile for a FileEntry previously parsed with
+  /// parseModuleMapFile.
+  const modulemap::ModuleMapFile *getParsedModuleMap(FileEntryRef File) const {
+    auto It = ParsedModuleMap.find(File);
+    if (It == ParsedModuleMap.end())
+      return nullptr;
+    return It->second;
+  }
+
   /// Dump the contents of the module map, for debugging purposes.
   void dump();
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 24b31fb3fefcc..0eb130e8d6cc2 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -8525,6 +8525,9 @@ def ftest_module_file_extension_EQ :
   Joined<["-"], "ftest-module-file-extension=">,
   HelpText<"introduce a module file extension for testing purposes. "
            "The argument is parsed as blockname:major:minor:hashed:user info">;
+def fmodules_lazy_load_module_maps : Flag<["-"], 
"fmodules-lazy-load-module-maps">,
+  HelpText<"Load modules from module maps only when needed">,
+  MarshallingInfoFlag<HeaderSearchOpts<"LazyLoadModMaps">>;
 
 defm recovery_ast : BoolOption<"f", "recovery-ast",
   LangOpts<"RecoveryAST">, DefaultTrue,
diff --git a/clang/lib/Frontend/CompilerInstance.cpp 
b/clang/lib/Frontend/CompilerInstance.cpp
index 9f1a3c56feec1..977b3ec791d62 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -2261,6 +2261,10 @@ GlobalModuleIndex 
*CompilerInstance::loadGlobalModuleIndex(
   // we need to make the global index cover all modules, so we do that here.
   if (!HaveFullGlobalModuleIndex && GlobalIndex && !buildingModule()) {
     ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap();
+
+    // Load modules that were parsed from module maps but not loaded yet.
+    MMap.loadAllParsedModules();
+
     bool RecreateIndex = false;
     for (ModuleMap::module_iterator I = MMap.module_begin(),
         E = MMap.module_end(); I != E; ++I) {
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 5f52d62bd36ed..716b5936ec479 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1619,15 +1619,116 @@ StringRef HeaderSearch::getIncludeNameForHeader(const 
FileEntry *File) const {
   return It->second;
 }
 
+void HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
+                                            ModuleMapDirectoryState &MMState) {
+  if (!MMState.ModuleMapFile)
+    return;
+  const modulemap::ModuleMapFile *ParsedMM =
+      ModMap.getParsedModuleMap(*MMState.ModuleMapFile);
+  if (!ParsedMM)
+    return;
+  const modulemap::ModuleMapFile *ParsedPrivateMM = nullptr;
+  if (MMState.PrivateModuleMapFile)
+    ParsedPrivateMM = ModMap.getParsedModuleMap(*MMState.PrivateModuleMapFile);
+
+  std::function<void(const modulemap::ModuleMapFile &, DirectoryEntryRef,
+                     StringRef)>
+      ProcessModuleMapFile = [&](const modulemap::ModuleMapFile &MMF,
+                                 DirectoryEntryRef MMDir,
+                                 StringRef PathPrefix) {
+        auto AddToCache = [&](StringRef RelPath, StringRef ModuleName) {
+          if (PathPrefix.empty()) {
+            MMState.HeaderToModules[RelPath].push_back(ModuleName);
+          } else {
+            SmallString<128> RelFromRootPath(PathPrefix);
+            llvm::sys::path::append(RelFromRootPath, RelPath);
+            MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
+          }
+        };
+
+        auto ProcessExternModuleDecl =
+            [&](const modulemap::ExternModuleDecl &EMD) {
+              StringRef FileNameRef = EMD.Path;
+              SmallString<128> ModuleMapFileName;
+              if (llvm::sys::path::is_relative(FileNameRef)) {
+                ModuleMapFileName = MMDir.getName();
+                llvm::sys::path::append(ModuleMapFileName, EMD.Path);
+                FileNameRef = ModuleMapFileName;
+              }
+              if (auto EFile = FileMgr.getOptionalFileRef(FileNameRef)) {
+                if (auto *ExtMMF = ModMap.getParsedModuleMap(*EFile)) {
+                  // Compute the new prefix by appending the extern module's
+                  // directory (from the extern declaration path) to the 
current
+                  // prefix.
+                  SmallString<128> NewPrefix(PathPrefix);
+                  StringRef ExternDir = llvm::sys::path::parent_path(EMD.Path);
+                  if (!ExternDir.empty())
+                    llvm::sys::path::append(NewPrefix, ExternDir);
+                  ProcessModuleMapFile(*ExtMMF, EFile->getDir(), NewPrefix);
+                }
+              }
+            };
+
+        std::function<void(const modulemap::ModuleDecl &, StringRef)>
+            ProcessModule = [&](const modulemap::ModuleDecl &MD,
+                                StringRef ModuleName) {
+              // Skip inferred submodules (module *)
+              if (MD.Id.front().first == "*")
+                return;
+              for (const auto &Decl : MD.Decls) {
+                std::visit(
+                    llvm::makeVisitor(
+                        [&](const modulemap::HeaderDecl &HD) {
+                          if (HD.Umbrella) {
+                            
MMState.UmbrellaHeaderModules.push_back(ModuleName);
+                          } else {
+                            AddToCache(HD.Path, ModuleName);
+                          }
+                        },
+                        [&](const modulemap::UmbrellaDirDecl &UDD) {
+                          SmallString<128> FullPath(PathPrefix);
+                          llvm::sys::path::append(FullPath, UDD.Path);
+                          MMState.UmbrellaDirModules.push_back(std::make_pair(
+                              std::string(FullPath), ModuleName));
+                        },
+                        [&](const modulemap::ModuleDecl &SubMD) {
+                          ProcessModule(SubMD, ModuleName);
+                        },
+                        [&](const modulemap::ExternModuleDecl &EMD) {
+                          ProcessExternModuleDecl(EMD);
+                        },
+                        [](const auto &) {
+                          // Ignore other decls.
+                        }),
+                    Decl);
+              }
+            };
+
+        for (const auto &Decl : MMF.Decls) {
+          std::visit(llvm::makeVisitor(
+                         [&](const modulemap::ModuleDecl &MD) {
+                           ProcessModule(MD, MD.Id.front().first);
+                         },
+                         [&](const modulemap::ExternModuleDecl &EMD) {
+                           ProcessExternModuleDecl(EMD);
+                         }),
+                     Decl);
+        }
+      };
+
+  ProcessModuleMapFile(*ParsedMM, Dir, "");
+  if (ParsedPrivateMM)
+    ProcessModuleMapFile(*ParsedPrivateMM, Dir, "");
+}
+
 bool HeaderSearch::hasModuleMap(StringRef FileName,
                                 const DirectoryEntry *Root,
                                 bool IsSystem) {
   if (!HSOpts.ImplicitModuleMaps)
     return false;
 
-  SmallVector<DirectoryEntryRef, 2> FixUpDirectories;
-
   StringRef DirName = FileName;
+  const DirectoryEntry *CurDir = nullptr;
   do {
     // Get the parent directory name.
     DirName = llvm::sys::path::parent_path(DirName);
@@ -1638,33 +1739,74 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
     auto Dir = FileMgr.getOptionalDirectoryRef(DirName);
     if (!Dir)
       return false;
+    CurDir = *Dir;
+
+    bool IsFramework =
+        llvm::sys::path::extension(Dir->getName()) == ".framework";
 
-    // Try to load the module map file in this directory.
-    switch (parseAndLoadModuleMapFile(
-        *Dir, IsSystem,
-        llvm::sys::path::extension(Dir->getName()) == ".framework")) {
-    case MMR_NewlyProcessed:
-    case MMR_AlreadyProcessed: {
-      // Success. All of the directories we stepped through inherit this module
-      // map file.
-      const ModuleMapDirectoryState &MMDS = DirectoryModuleMap[*Dir];
-      for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
-        DirectoryModuleMap[FixUpDirectories[I]] = MMDS;
+    // Check if it's possible that the module map for this directory can 
resolve
+    // this header.
+    parseModuleMapFile(*Dir, IsSystem, IsFramework);
+    auto DirState = DirectoryModuleMap.find(*Dir);
+    if (DirState == DirectoryModuleMap.end() || 
!DirState->second.ModuleMapFile)
+      continue;
+
+    if (!HSOpts.LazyLoadModMaps)
       return true;
+
+    auto &MMState = DirState->second;
+
+    // Build cache if not already built
+    if (MMState.HeaderToModules.empty() && MMState.UmbrellaDirModules.empty() 
&&
+        MMState.UmbrellaHeaderModules.empty()) {
+      buildHeaderToModuleCache(*Dir, MMState);
     }
-    case MMR_NoDirectory:
-    case MMR_InvalidModuleMap:
-      break;
+
+    // Compute relative path from directory to the file. Use DirName (which
+    // we computed via parent_path) rather than Dir->getName() to ensure
+    // consistent path separators.
+    StringRef RelativePath = FileName.substr(DirName.size());
+    // Strip leading separator
+    while (!RelativePath.empty() &&
+           llvm::sys::path::is_separator(RelativePath.front()))
+      RelativePath = RelativePath.substr(1);
+
+    // Check for exact matches in cache
+    llvm::SmallVector<StringRef, 4> ModulesToLoad;
+    auto CachedMods = MMState.HeaderToModules.find(RelativePath);
+    if (CachedMods != MMState.HeaderToModules.end()) {
+      ModulesToLoad.append(CachedMods->second.begin(),
+                           CachedMods->second.end());
     }
 
-    // If we hit the top of our search, we're done.
-    if (*Dir == Root)
-      return false;
+    // Check umbrella directories
+    for (const auto &UmbrellaDir : MMState.UmbrellaDirModules) {
+      if (RelativePath.starts_with(UmbrellaDir.first) ||
+          UmbrellaDir.first == ".") {
+        ModulesToLoad.push_back(UmbrellaDir.second);
+      }
+    }
 
-    // Keep track of all of the directories we checked, so we can mark them as
-    // having module maps if we eventually do find a module map.
-    FixUpDirectories.push_back(*Dir);
-  } while (true);
+    // Add all umbrella header modules. We don't know which headers these
+    // umbrella headers apply to, so we add all that could possibly apply.
+    // `ModuleMap::findModuleForHeader` will select the correct one.
+    ModulesToLoad.append(MMState.UmbrellaHeaderModules.begin(),
+                         MMState.UmbrellaHeaderModules.end());
+
+    // Load all matching modules
+    bool LoadedAny = false;
+    for (StringRef ModName : ModulesToLoad) {
+      if (ModMap.findOrLoadModule(ModName)) {
+        LoadedAny = true;
+      }
+    }
+
+    if (LoadedAny)
+      return true;
+
+    // If we hit the top of our search, we're done.
+  } while (CurDir != Root);
+  return false;
 }
 
 ModuleMap::KnownHeader
@@ -1698,12 +1840,9 @@ HeaderSearch::findResolvedModulesForHeader(FileEntryRef 
File) const {
   return ModMap.findResolvedModulesForHeader(File);
 }
 
-static bool suggestModule(HeaderSearch &HS, FileEntryRef File,
-                          Module *RequestingModule,
+static bool suggestModule(HeaderSearch &HS, ModuleMap::KnownHeader Module,
+                          FileEntryRef File, clang::Module *RequestingModule,
                           ModuleMap::KnownHeader *SuggestedModule) {
-  ModuleMap::KnownHeader Module =
-      HS.findModuleForHeader(File, /*AllowTextual*/true);
-
   // If this module specifies [no_undeclared_includes], we cannot find any
   // file that's in a non-dependency module.
   if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) {
@@ -1737,9 +1876,31 @@ bool HeaderSearch::findUsableModuleForHeader(
     FileEntryRef File, const DirectoryEntry *Root, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
   if (needModuleLookup(RequestingModule, SuggestedModule)) {
-    // If there is a module that corresponds to this header, suggest it.
-    hasModuleMap(File.getNameAsRequested(), Root, IsSystemHeaderDir);
-    return suggestModule(*this, File, RequestingModule, SuggestedModule);
+    if (!HSOpts.LazyLoadModMaps) {
+      // NOTE: This is required for `shadowed-submodule.m` to pass as it relies
+      //       on A1/module.modulemap being loaded even though we already know
+      //       which module the header belongs to. We will remove this behavior
+      //       as part of lazy module map loading.
+      hasModuleMap(File.getNameAsRequested(), Root, IsSystemHeaderDir);
+      ModuleMap::KnownHeader Module =
+          findModuleForHeader(File, /*AllowTextual=*/true);
+      return suggestModule(*this, Module, File, RequestingModule,
+                           SuggestedModule);
+    }
+
+    // First check if we already know about this header
+    ModuleMap::KnownHeader Module =
+        findModuleForHeader(File, /*AllowTextual=*/true);
+
+    // If we don't have a module yet, try to find/load module maps
+    if (!Module) {
+      hasModuleMap(File.getNameAsRequested(), Root, IsSystemHeaderDir);
+      // Try again after loading module maps
+      Module = ModMap.findModuleForHeader(File, /*AllowTextual=*/true);
+    }
+
+    return suggestModule(*this, Module, File, RequestingModule,
+                         SuggestedModule);
   }
   return true;
 }
@@ -1766,7 +1927,10 @@ bool HeaderSearch::findUsableModuleForFrameworkHeader(
     // important so that we're consistent about whether this header
     // corresponds to a module. Possibly we should lock down framework modules
     // so that this is not possible.
-    return suggestModule(*this, File, RequestingModule, SuggestedModule);
+    ModuleMap::KnownHeader Module =
+        findModuleForHeader(File, /*AllowTextual=*/true);
+    return suggestModule(*this, Module, File, RequestingModule,
+                         SuggestedModule);
   }
   return true;
 }
@@ -1829,7 +1993,8 @@ bool HeaderSearch::parseAndLoadModuleMapFile(FileEntryRef 
File, bool IsSystem,
   }
 
   assert(Dir && "module map home directory must exist");
-  switch (parseAndLoadModuleMapFileImpl(File, IsSystem, *Dir, ID, Offset)) {
+  switch (parseAndLoadModuleMapFileImpl(File, IsSystem, *Dir, ID, Offset,
+                                        /*DiagnosePrivMMap=*/true)) {
   case MMR_AlreadyProcessed:
   case MMR_NewlyProcessed:
     return false;
@@ -1843,7 +2008,8 @@ bool HeaderSearch::parseAndLoadModuleMapFile(FileEntryRef 
File, bool IsSystem,
 HeaderSearch::ModuleMapResult
 HeaderSearch::parseAndLoadModuleMapFileImpl(FileEntryRef File, bool IsSystem,
                                             DirectoryEntryRef Dir, FileID ID,
-                                            unsigned *Offset) {
+                                            unsigned *Offset,
+                                            bool DiagnosePrivMMap) {
   // Check whether we've already loaded this module map, and mark it as being
   // loaded in case we recursively try to load it from itself.
   auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));
@@ -1858,7 +2024,7 @@ HeaderSearch::parseAndLoadModuleMapFileImpl(FileEntryRef 
File, bool IsSystem,
 
   // Try to load a corresponding private module map.
   if (OptionalFileEntryRef PMMFile =
-          getPrivateModuleMap(File, FileMgr, Diags, !ParsedModuleMaps[File])) {
+          getPrivateModuleMap(File, FileMgr, Diags, DiagnosePrivMMap)) {
     if (ModMap.parseAndLoadModuleMapFile(*PMMFile, IsSystem, Dir)) {
       LoadedModuleMaps[File] = false;
       return MMR_InvalidModuleMap;
@@ -1886,7 +2052,7 @@ HeaderSearch::parseModuleMapFileImpl(FileEntryRef File, 
bool IsSystem,
 
   // Try to parse a corresponding private module map.
   if (OptionalFileEntryRef PMMFile =
-          getPrivateModuleMap(File, FileMgr, Diags)) {
+          getPrivateModuleMap(File, FileMgr, Diags, false)) {
     if (ModMap.parseModuleMapFile(*PMMFile, IsSystem, Dir)) {
       ParsedModuleMaps[File] = false;
       return MMR_InvalidModuleMap;
@@ -1965,7 +2131,7 @@ HeaderSearch::ModuleMapResult
 HeaderSearch::parseAndLoadModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
                                         bool IsFramework) {
   auto InsertRes = DirectoryModuleMap.insert(std::pair{
-      Dir, ModuleMapDirectoryState{{}, ModuleMapDirectoryState::Invalid}});
+      Dir, ModuleMapDirectoryState{{}, {}, ModuleMapDirectoryState::Invalid}});
   ModuleMapDirectoryState &MMState = InsertRes.first->second;
   if (!InsertRes.second) {
     switch (MMState.Status) {
@@ -1978,8 +2144,12 @@ 
HeaderSearch::parseAndLoadModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
     };
   }
 
-  if (!MMState.ModuleMapFile)
+  if (!MMState.ModuleMapFile) {
     MMState.ModuleMapFile = lookupModuleMapFile(Dir, IsFramework);
+    if (MMState.ModuleMapFile)
+      MMState.PrivateModuleMapFile =
+          getPrivateModuleMap(*MMState.ModuleMapFile, FileMgr, Diags);
+  }
 
   if (MMState.ModuleMapFile) {
     ModuleMapResult Result =
@@ -2008,8 +2178,11 @@ HeaderSearch::parseModuleMapFile(StringRef DirName, bool 
IsSystem,
 HeaderSearch::ModuleMapResult
 HeaderSearch::parseModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
                                  bool IsFramework) {
+  if (!HSOpts.LazyLoadModMaps)
+    return parseAndLoadModuleMapFile(Dir, IsSystem, IsFramework);
+
   auto InsertRes = DirectoryModuleMap.insert(std::pair{
-      Dir, ModuleMapDirectoryState{{}, ModuleMapDirectoryState::Invalid}});
+      Dir, ModuleMapDirectoryState{{}, {}, ModuleMapDirectoryState::Invalid}});
   ModuleMapDirectoryState &MMState = InsertRes.first->second;
   if (!InsertRes.second) {
     switch (MMState.Status) {
@@ -2021,8 +2194,12 @@ HeaderSearch::parseModuleMapFile(DirectoryEntryRef Dir, 
bool IsSystem,
     };
   }
 
-  if (!MMState.ModuleMapFile)
+  if (!MMState.ModuleMapFile) {
     MMState.ModuleMapFile = lookupModuleMapFile(Dir, IsFramework);
+    if (MMState.ModuleMapFile)
+      MMState.PrivateModuleMapFile =
+          getPrivateModuleMap(*MMState.ModuleMapFile, FileMgr, Diags);
+  }
 
   if (MMState.ModuleMapFile) {
     ModuleMapResult Result =
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index ea1ed9b48b101..1ed6a91e92458 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -621,6 +621,16 @@ ModuleMap::KnownHeader 
ModuleMap::findModuleForHeader(FileEntryRef File,
   return MakeResult(findOrCreateModuleForHeaderInUmbrellaDir(File));
 }
 
+OptionalFileEntryRef ModuleMap::findUmbrellaHeaderForModule(
+    Module *M, std::string NameAsWritten,
+    SmallVectorImpl<char> &RelativePathName) {
+  Module::UnresolvedHeaderDirective Header;
+  Header.FileName = std::move(NameAsWritten);
+  Header.IsUmbrella = true;
+  bool NeedsFramework;
+  return findHeader(M, Header, RelativePathName, NeedsFramework);
+}
+
 ModuleMap::KnownHeader
 ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {
   assert(!Headers.count(File) && "already have a module for this header");
@@ -1360,6 +1370,26 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, 
bool IsSystem,
       std::make_unique<modulemap::ModuleMapFile>(std::move(*MaybeMMF)));
   const modulemap::ModuleMapFile &MMF = *ParsedModuleMaps.back();
   std::vector<const modulemap::ExternModuleDecl *> PendingExternalModuleMaps;
+  std::function<void(const modulemap::ModuleDecl &)> CollectExternDecls =
+      [&](const modulemap::ModuleDecl &MD) {
+        for (const auto &Decl : MD.Decls) {
+          std::visit(llvm::makeVisitor(
+                         [&](const modulemap::ModuleDecl &SubMD) {
+                           // Skip inferred submodules (module *)
+                           if (SubMD.Id.front().first == "*")
+                             return;
+                           CollectExternDecls(SubMD);
+                         },
+                         [&](const modulemap::ExternModuleDecl &EMD) {
+                           PendingExternalModuleMaps.push_back(&EMD);
+                         },
+                         [&](const auto &) {
+                           // Ignore other decls
+                         }),
+                     Decl);
+        }
+      };
+
   for (const auto &Decl : MMF.Decls) {
     std::visit(llvm::makeVisitor(
                    [&](const modulemap::ModuleDecl &MD) {
@@ -1369,6 +1399,7 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, 
bool IsSystem,
                      auto &ModuleDecls =
                          ParsedModules[StringRef(MD.Id.front().first)];
                      ModuleDecls.push_back(std::pair(&MMF, &MD));
+                     CollectExternDecls(MD);
                    },
                    [&](const modulemap::ExternModuleDecl &EMD) {
                      PendingExternalModuleMaps.push_back(&EMD);
@@ -1400,6 +1431,11 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, 
bool IsSystem,
   return false;
 }
 
+void ModuleMap::loadAllParsedModules() {
+  for (const auto &Entry : ParsedModules)
+    findOrLoadModule(Entry.first());
+}
+
 FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const {
   if (Module->DefinitionLoc.isInvalid())
     return {};
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f3902d57e3d1f..db34d9dc4bcdf 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6316,6 +6316,15 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
       CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
       CurrentModule->ModuleMapIsPrivate = ModuleMapIsPrivate;
       CurrentModule->NamedModuleHasInit = NamedModuleHasInit;
+
+      if (!ParentModule && !F.BaseDirectory.empty()) {
+        if (auto Dir = FileMgr.getOptionalDirectoryRef(F.BaseDirectory))
+          CurrentModule->Directory = *Dir;
+      } else if (ParentModule && ParentModule->Directory) {
+        // Submodules inherit the directory from their parent.
+        CurrentModule->Directory = ParentModule->Directory;
+      }
+
       if (DeserializationListener)
         DeserializationListener->ModuleRead(GlobalID, CurrentModule);
 
@@ -6341,14 +6350,12 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
     }
 
     case SUBMODULE_UMBRELLA_HEADER: {
-      // FIXME: This doesn't work for framework modules as `Filename` is the
-      //        name as written in the module file and does not include
-      //        `Headers/`, so this path will never exist.
-      auto Filename = ResolveImportedPath(PathBuf, Blob, F);
-      if (auto Umbrella = PP.getFileManager().getOptionalFileRef(*Filename)) {
+      SmallString<128> RelativePathName;
+      if (auto Umbrella = ModMap.findUmbrellaHeaderForModule(
+              CurrentModule, Blob.str(), RelativePathName)) {
         if (!CurrentModule->getUmbrellaHeaderAsWritten()) {
-          // FIXME: NameAsWritten
-          ModMap.setUmbrellaHeaderAsWritten(CurrentModule, *Umbrella, Blob, 
"");
+          ModMap.setUmbrellaHeaderAsWritten(CurrentModule, *Umbrella, Blob,
+                                            RelativePathName);
         }
         // Note that it's too late at this point to return out of date if the
         // name from the PCM doesn't match up with the one in the module map,
@@ -6379,7 +6386,6 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
     }
 
     case SUBMODULE_UMBRELLA_DIR: {
-      // See comments in SUBMODULE_UMBRELLA_HEADER
       auto Dirname = ResolveImportedPath(PathBuf, Blob, F);
       if (auto Umbrella =
               PP.getFileManager().getOptionalDirectoryRef(*Dirname)) {
diff --git a/clang/test/Modules/lazy-by-header-extern.c 
b/clang/test/Modules/lazy-by-header-extern.c
new file mode 100644
index 0000000000000..c7bc451f1523e
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-extern.c
@@ -0,0 +1,69 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+// Test that extern module declarations are followed when building the header
+// cache, so headers declared in external module maps can be found. This tests
+// regular headers, umbrella headers, and umbrella directories in extern
+// module maps.
+
+//--- module.modulemap
+
+extern module Ext "sub/extern.modulemap"
+extern module ExtUmbrellaHeader "umbrella_hdr/extern.modulemap"
+extern module ExtUmbrellaDir "umbrella_dir/extern.modulemap"
+
+//--- sub/extern.modulemap
+
+// Regular header in extern module.
+module Ext {
+  header "ext.h"
+}
+
+//--- umbrella_hdr/extern.modulemap
+
+module ExtUmbrellaHeader {
+  umbrella header "umbrella.h"
+}
+
+//--- umbrella_dir/extern.modulemap
+
+module ExtUmbrellaDir {
+  umbrella "inc"
+}
+
+//--- sub/ext.h
+
+//--- umbrella_hdr/umbrella.h
+#include "covered.h"
+
+//--- umbrella_hdr/covered.h
+
+//--- umbrella_dir/inc/from_umbrella.h
+
+//--- tu.c
+
+#include <sub/ext.h>
+#include <umbrella_hdr/covered.h>
+#include <umbrella_dir/inc/from_umbrella.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'Ext'}}
+// expected-remark@*{{loading parsed module 'ExtUmbrellaHeader'}}
+// expected-remark@*{{loading parsed module 'ExtUmbrellaDir'}}
+#else
+// expected-remark@*{{loading modulemap}}
+// expected-remark@*{{loading modulemap}}
+// expected-remark@*{{loading modulemap}}
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-header-lookup.c 
b/clang/test/Modules/lazy-by-header-lookup.c
new file mode 100644
index 0000000000000..4d4f47ff76788
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-lookup.c
@@ -0,0 +1,38 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+//--- module.modulemap
+
+module A {
+  header "A.h"
+}
+
+module B {
+  header "B.h"
+  header "B2.h"
+}
+
+//--- A.h
+
+//--- B.h
+
+//--- B2.h
+
+//--- tu.c
+
+#include <B.h>
+#include <B2.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'B'}}
+#else
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-header-nested.c 
b/clang/test/Modules/lazy-by-header-nested.c
new file mode 100644
index 0000000000000..dd0ed128fa1c4
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-nested.c
@@ -0,0 +1,46 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+// Test that module maps in parent directories are found when including headers
+// from subdirectories. The module map declares headers with relative paths
+// that include the subdirectory.
+
+//--- module.modulemap
+
+module A {
+  header "sub/A.h"
+}
+
+module B {
+  header "sub/deep/B.h"
+}
+
+module Other {
+  header "other/O.h"
+}
+
+//--- sub/A.h
+
+//--- sub/deep/B.h
+
+//--- other/O.h
+
+//--- tu.c
+
+#include <sub/A.h>
+#include <sub/deep/B.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'A'}}
+// expected-remark@*{{loading parsed module 'B'}}
+#else
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-header-private.c 
b/clang/test/Modules/lazy-by-header-private.c
new file mode 100644
index 0000000000000..caf9288cfce3f
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-private.c
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+// Test that headers declared in private module maps are found correctly with
+// lazy loading.
+
+//--- module.modulemap
+
+module A {
+  header "A.h"
+}
+
+//--- module.private.modulemap
+
+module A_Private {
+  header "A_Private.h"
+}
+
+//--- A.h
+
+//--- A_Private.h
+
+//--- tu.c
+
+#include <A_Private.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'A_Private'}}
+#else
+// expected-remark@*{{loading modulemap}}
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-header-umbrella-dir.c 
b/clang/test/Modules/lazy-by-header-umbrella-dir.c
new file mode 100644
index 0000000000000..50b8889606325
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-umbrella-dir.c
@@ -0,0 +1,66 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+// Test that umbrella directories trigger module loading. When a header is
+// included that falls under an umbrella directory, the module declaring that
+// umbrella directory should be loaded. Other modules in the same module map
+// should not be loaded unless their headers are also included.
+
+//--- module.modulemap
+
+module A {
+  umbrella "subdir"
+}
+
+// These modules shouldn't get loaded.
+module Other {
+  umbrella "othersubdir"
+}
+
+module B {
+  header "B.h"
+}
+
+//--- subdir/foo.h
+
+//--- subdir/bar.h
+
+//--- othersubdir/os.h
+
+//--- B.h
+
+//--- C.h
+
+// Test umbrella "." which covers all headers in the module map's directory.
+//--- dotumbrella/module.modulemap
+
+module DotUmbrella {
+  umbrella "."
+}
+
+//--- dotumbrella/dot.h
+
+//--- tu.c
+
+// Including a header from the umbrella directory should load module A.
+#include <subdir/foo.h>
+#include <subdir/bar.h>
+#include <C.h> // This shouldn't trigger any loads.
+#include <dotumbrella/dot.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'A'}}
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'DotUmbrella'}}
+#else
+// expected-remark@*{{loading modulemap}}
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-header-umbrella-header.c 
b/clang/test/Modules/lazy-by-header-umbrella-header.c
new file mode 100644
index 0000000000000..cf6e25b258bbf
--- /dev/null
+++ b/clang/test/Modules/lazy-by-header-umbrella-header.c
@@ -0,0 +1,46 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -fmodules-lazy-load-module-maps -verify
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
+// RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
+// RUN:   -DEAGER -verify
+
+// Test that umbrella headers trigger module loading. Since the lazy loader
+// can't know which headers are covered by an umbrella header without parsing
+// it, modules with umbrella headers are loaded conservatively when any header
+// in the same directory is included.
+
+//--- module.modulemap
+
+module A {
+  umbrella header "A.h"
+}
+
+module B {
+  header "B.h"
+}
+
+//--- A.h
+#include <A_impl.h>
+
+//--- A_impl.h
+// A header that would be covered by the umbrella.
+
+//--- B.h
+// Not covered 
+
+//--- tu.c
+
+// Including a header that might be covered by an umbrella header should
+// conservatively load the module with the umbrella header.
+#include <A_impl.h>
+
+#ifndef EAGER
+// expected-remark@*{{parsing modulemap}}
+// expected-remark@*{{loading parsed module 'A'}}
+#else
+// expected-remark@*{{loading modulemap}}
+#endif
diff --git a/clang/test/Modules/lazy-by-name-lookup.c 
b/clang/test/Modules/lazy-by-name-lookup.c
index 11a3a5cda709d..f4f288d69aaec 100644
--- a/clang/test/Modules/lazy-by-name-lookup.c
+++ b/clang/test/Modules/lazy-by-name-lookup.c
@@ -2,7 +2,7 @@
 // RUN: split-file %s %t
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -I%t \
 // RUN:   -fmodules-cache-path=%t/cache %t/tu.c -fsyntax-only -Rmodule-map \
-// RUN:   -verify
+// RUN:   -fmodules-lazy-load-module-maps -verify
 
 //--- module.modulemap
 
@@ -28,4 +28,4 @@ module B {
 
 // expected-remark@*{{parsing modulemap}}
 // expected-remark@*{{loading parsed module 'A'}}
-// expected-remark@*{{loading modulemap}}
\ No newline at end of file
+// expected-remark@*{{loading parsed module 'B'}}

>From 28d2fa8296b66c9d8108c781cafcf6e0d7d6c6ec Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Mon, 23 Feb 2026 17:42:21 -0800
Subject: [PATCH 2/6] Fix windows tests, this normalizes paths because they
 include slashes.

---
 clang/lib/Lex/HeaderSearch.cpp | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 716b5936ec479..fed0c62ca6045 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1637,13 +1637,10 @@ void 
HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
                                  DirectoryEntryRef MMDir,
                                  StringRef PathPrefix) {
         auto AddToCache = [&](StringRef RelPath, StringRef ModuleName) {
-          if (PathPrefix.empty()) {
-            MMState.HeaderToModules[RelPath].push_back(ModuleName);
-          } else {
-            SmallString<128> RelFromRootPath(PathPrefix);
-            llvm::sys::path::append(RelFromRootPath, RelPath);
-            MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
-          }
+          SmallString<128> RelFromRootPath(PathPrefix);
+          llvm::sys::path::append(RelFromRootPath, RelPath);
+          llvm::sys::path::native(RelFromRootPath);
+          MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
         };
 
         auto ProcessExternModuleDecl =
@@ -1662,8 +1659,10 @@ void 
HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
                   // prefix.
                   SmallString<128> NewPrefix(PathPrefix);
                   StringRef ExternDir = llvm::sys::path::parent_path(EMD.Path);
-                  if (!ExternDir.empty())
+                  if (!ExternDir.empty()) {
                     llvm::sys::path::append(NewPrefix, ExternDir);
+                    llvm::sys::path::native(NewPrefix);
+                  }
                   ProcessModuleMapFile(*ExtMMF, EFile->getDir(), NewPrefix);
                 }
               }
@@ -1688,6 +1687,7 @@ void 
HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
                         [&](const modulemap::UmbrellaDirDecl &UDD) {
                           SmallString<128> FullPath(PathPrefix);
                           llvm::sys::path::append(FullPath, UDD.Path);
+                          llvm::sys::path::native(FullPath);
                           MMState.UmbrellaDirModules.push_back(std::make_pair(
                               std::string(FullPath), ModuleName));
                         },
@@ -1770,6 +1770,9 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
     while (!RelativePath.empty() &&
            llvm::sys::path::is_separator(RelativePath.front()))
       RelativePath = RelativePath.substr(1);
+    SmallString<128> RelativePathNative(RelativePath);
+    llvm::sys::path::native(RelativePathNative);
+    RelativePath = RelativePathNative;
 
     // Check for exact matches in cache
     llvm::SmallVector<StringRef, 4> ModulesToLoad;

>From 32ccb86564fb8d99de130320f4c8f7b949e030a1 Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Tue, 24 Feb 2026 00:15:43 -0800
Subject: [PATCH 3/6] Split up lambdas into separate private member functions.

---
 clang/include/clang/Lex/HeaderSearch.h |  17 +++
 clang/lib/Lex/HeaderSearch.cpp         | 181 +++++++++++++------------
 2 files changed, 111 insertions(+), 87 deletions(-)

diff --git a/clang/include/clang/Lex/HeaderSearch.h 
b/clang/include/clang/Lex/HeaderSearch.h
index 83c37d9dced55..bd9caeee095ff 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -388,6 +388,23 @@ class HeaderSearch {
   void buildHeaderToModuleCache(DirectoryEntryRef Dir,
                                 ModuleMapDirectoryState &MMState);
 
+  void processModuleMapForHeaderToModuleCache(
+      const modulemap::ModuleMapFile &MMF, DirectoryEntryRef MMDir,
+      StringRef PathPrefix, ModuleMapDirectoryState &MMState);
+
+  void processExternModuleDeclForHeaderToModuleCache(
+      const modulemap::ExternModuleDecl &EMD, DirectoryEntryRef MMDir,
+      StringRef PathPrefix, ModuleMapDirectoryState &MMState);
+
+  void processModuleDeclForHeaderToModuleCache(
+      const modulemap::ModuleDecl &MD, StringRef ModuleName,
+      DirectoryEntryRef MMDir, StringRef PathPrefix,
+      ModuleMapDirectoryState &MMState);
+
+  void addToHeaderToModuleCache(StringRef RelPath, StringRef ModuleName,
+                                StringRef PathPrefix,
+                                ModuleMapDirectoryState &MMState);
+
 public:
   HeaderSearch(const HeaderSearchOptions &HSOpts, SourceManager &SourceMgr,
                DiagnosticsEngine &Diags, const LangOptions &LangOpts,
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index fed0c62ca6045..38c74b56426e2 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1631,94 +1631,101 @@ void 
HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
   if (MMState.PrivateModuleMapFile)
     ParsedPrivateMM = ModMap.getParsedModuleMap(*MMState.PrivateModuleMapFile);
 
-  std::function<void(const modulemap::ModuleMapFile &, DirectoryEntryRef,
-                     StringRef)>
-      ProcessModuleMapFile = [&](const modulemap::ModuleMapFile &MMF,
-                                 DirectoryEntryRef MMDir,
-                                 StringRef PathPrefix) {
-        auto AddToCache = [&](StringRef RelPath, StringRef ModuleName) {
-          SmallString<128> RelFromRootPath(PathPrefix);
-          llvm::sys::path::append(RelFromRootPath, RelPath);
-          llvm::sys::path::native(RelFromRootPath);
-          MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
-        };
-
-        auto ProcessExternModuleDecl =
-            [&](const modulemap::ExternModuleDecl &EMD) {
-              StringRef FileNameRef = EMD.Path;
-              SmallString<128> ModuleMapFileName;
-              if (llvm::sys::path::is_relative(FileNameRef)) {
-                ModuleMapFileName = MMDir.getName();
-                llvm::sys::path::append(ModuleMapFileName, EMD.Path);
-                FileNameRef = ModuleMapFileName;
-              }
-              if (auto EFile = FileMgr.getOptionalFileRef(FileNameRef)) {
-                if (auto *ExtMMF = ModMap.getParsedModuleMap(*EFile)) {
-                  // Compute the new prefix by appending the extern module's
-                  // directory (from the extern declaration path) to the 
current
-                  // prefix.
-                  SmallString<128> NewPrefix(PathPrefix);
-                  StringRef ExternDir = llvm::sys::path::parent_path(EMD.Path);
-                  if (!ExternDir.empty()) {
-                    llvm::sys::path::append(NewPrefix, ExternDir);
-                    llvm::sys::path::native(NewPrefix);
-                  }
-                  ProcessModuleMapFile(*ExtMMF, EFile->getDir(), NewPrefix);
-                }
-              }
-            };
-
-        std::function<void(const modulemap::ModuleDecl &, StringRef)>
-            ProcessModule = [&](const modulemap::ModuleDecl &MD,
-                                StringRef ModuleName) {
-              // Skip inferred submodules (module *)
-              if (MD.Id.front().first == "*")
-                return;
-              for (const auto &Decl : MD.Decls) {
-                std::visit(
-                    llvm::makeVisitor(
-                        [&](const modulemap::HeaderDecl &HD) {
-                          if (HD.Umbrella) {
-                            
MMState.UmbrellaHeaderModules.push_back(ModuleName);
-                          } else {
-                            AddToCache(HD.Path, ModuleName);
-                          }
-                        },
-                        [&](const modulemap::UmbrellaDirDecl &UDD) {
-                          SmallString<128> FullPath(PathPrefix);
-                          llvm::sys::path::append(FullPath, UDD.Path);
-                          llvm::sys::path::native(FullPath);
-                          MMState.UmbrellaDirModules.push_back(std::make_pair(
-                              std::string(FullPath), ModuleName));
-                        },
-                        [&](const modulemap::ModuleDecl &SubMD) {
-                          ProcessModule(SubMD, ModuleName);
-                        },
-                        [&](const modulemap::ExternModuleDecl &EMD) {
-                          ProcessExternModuleDecl(EMD);
-                        },
-                        [](const auto &) {
-                          // Ignore other decls.
-                        }),
-                    Decl);
-              }
-            };
-
-        for (const auto &Decl : MMF.Decls) {
-          std::visit(llvm::makeVisitor(
-                         [&](const modulemap::ModuleDecl &MD) {
-                           ProcessModule(MD, MD.Id.front().first);
-                         },
-                         [&](const modulemap::ExternModuleDecl &EMD) {
-                           ProcessExternModuleDecl(EMD);
-                         }),
-                     Decl);
-        }
-      };
-
-  ProcessModuleMapFile(*ParsedMM, Dir, "");
+  processModuleMapForHeaderToModuleCache(*ParsedMM, Dir, "", MMState);
   if (ParsedPrivateMM)
-    ProcessModuleMapFile(*ParsedPrivateMM, Dir, "");
+    processModuleMapForHeaderToModuleCache(*ParsedPrivateMM, Dir, "", MMState);
+}
+
+void HeaderSearch::addToHeaderToModuleCache(StringRef RelPath,
+                                            StringRef ModuleName,
+                                            StringRef PathPrefix,
+                                            ModuleMapDirectoryState &MMState) {
+  SmallString<128> RelFromRootPath(PathPrefix);
+  llvm::sys::path::append(RelFromRootPath, RelPath);
+  llvm::sys::path::native(RelFromRootPath);
+  MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
+}
+
+void HeaderSearch::processExternModuleDeclForHeaderToModuleCache(
+    const modulemap::ExternModuleDecl &EMD, DirectoryEntryRef MMDir,
+    StringRef PathPrefix, ModuleMapDirectoryState &MMState) {
+  StringRef FileNameRef = EMD.Path;
+  SmallString<128> ModuleMapFileName;
+  if (llvm::sys::path::is_relative(FileNameRef)) {
+    ModuleMapFileName = MMDir.getName();
+    llvm::sys::path::append(ModuleMapFileName, EMD.Path);
+    FileNameRef = ModuleMapFileName;
+  }
+  if (auto EFile = FileMgr.getOptionalFileRef(FileNameRef)) {
+    if (auto *ExtMMF = ModMap.getParsedModuleMap(*EFile)) {
+      // Compute the new prefix by appending the extern module's directory
+      // (from the extern declaration path) to the current prefix.
+      SmallString<128> NewPrefix(PathPrefix);
+      StringRef ExternDir = llvm::sys::path::parent_path(EMD.Path);
+      if (!ExternDir.empty()) {
+        llvm::sys::path::append(NewPrefix, ExternDir);
+        llvm::sys::path::native(NewPrefix);
+      }
+      processModuleMapForHeaderToModuleCache(*ExtMMF, EFile->getDir(),
+                                             NewPrefix, MMState);
+    }
+  }
+}
+
+void HeaderSearch::processModuleDeclForHeaderToModuleCache(
+    const modulemap::ModuleDecl &MD, StringRef ModuleName,
+    DirectoryEntryRef MMDir, StringRef PathPrefix,
+    ModuleMapDirectoryState &MMState) {
+  // Skip inferred submodules (module *)
+  if (MD.Id.front().first == "*")
+    return;
+  for (const auto &Decl : MD.Decls) {
+    std::visit(llvm::makeVisitor(
+                   [&](const modulemap::HeaderDecl &HD) {
+                     if (HD.Umbrella) {
+                       MMState.UmbrellaHeaderModules.push_back(ModuleName);
+                     } else {
+                       addToHeaderToModuleCache(HD.Path, ModuleName, 
PathPrefix,
+                                                MMState);
+                     }
+                   },
+                   [&](const modulemap::UmbrellaDirDecl &UDD) {
+                     SmallString<128> FullPath(PathPrefix);
+                     llvm::sys::path::append(FullPath, UDD.Path);
+                     llvm::sys::path::native(FullPath);
+                     MMState.UmbrellaDirModules.push_back(
+                         std::make_pair(std::string(FullPath), ModuleName));
+                   },
+                   [&](const modulemap::ModuleDecl &SubMD) {
+                     processModuleDeclForHeaderToModuleCache(
+                         SubMD, ModuleName, MMDir, PathPrefix, MMState);
+                   },
+                   [&](const modulemap::ExternModuleDecl &EMD) {
+                     processExternModuleDeclForHeaderToModuleCache(
+                         EMD, MMDir, PathPrefix, MMState);
+                   },
+                   [](const auto &) {
+                     // Ignore other decls.
+                   }),
+               Decl);
+  }
+}
+
+void HeaderSearch::processModuleMapForHeaderToModuleCache(
+    const modulemap::ModuleMapFile &MMF, DirectoryEntryRef MMDir,
+    StringRef PathPrefix, ModuleMapDirectoryState &MMState) {
+  for (const auto &Decl : MMF.Decls) {
+    std::visit(llvm::makeVisitor(
+                   [&](const modulemap::ModuleDecl &MD) {
+                     processModuleDeclForHeaderToModuleCache(
+                         MD, MD.Id.front().first, MMDir, PathPrefix, MMState);
+                   },
+                   [&](const modulemap::ExternModuleDecl &EMD) {
+                     processExternModuleDeclForHeaderToModuleCache(
+                         EMD, MMDir, PathPrefix, MMState);
+                   }),
+               Decl);
+  }
 }
 
 bool HeaderSearch::hasModuleMap(StringRef FileName,

>From 6608927c3f92fc65c2fdeed77599143b2f7931b8 Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Tue, 24 Feb 2026 00:21:35 -0800
Subject: [PATCH 4/6] format

---
 clang/lib/Lex/HeaderSearch.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 38c74b56426e2..bf3be6519f735 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -2015,11 +2015,9 @@ bool 
HeaderSearch::parseAndLoadModuleMapFile(FileEntryRef File, bool IsSystem,
   llvm_unreachable("Unknown load module map result");
 }
 
-HeaderSearch::ModuleMapResult
-HeaderSearch::parseAndLoadModuleMapFileImpl(FileEntryRef File, bool IsSystem,
-                                            DirectoryEntryRef Dir, FileID ID,
-                                            unsigned *Offset,
-                                            bool DiagnosePrivMMap) {
+HeaderSearch::ModuleMapResult HeaderSearch::parseAndLoadModuleMapFileImpl(
+    FileEntryRef File, bool IsSystem, DirectoryEntryRef Dir, FileID ID,
+    unsigned *Offset, bool DiagnosePrivMMap) {
   // Check whether we've already loaded this module map, and mark it as being
   // loaded in case we recursively try to load it from itself.
   auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));

>From 31e20dd063a8a4dd582b5ee55aaa7518c02e9491 Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Tue, 24 Feb 2026 11:23:35 -0800
Subject: [PATCH 5/6] Clarify umbrella header comment

---
 clang/lib/Lex/HeaderSearch.cpp | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index bf3be6519f735..56f82e04a9601 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1797,9 +1797,17 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
       }
     }
 
-    // Add all umbrella header modules. We don't know which headers these
-    // umbrella headers apply to, so we add all that could possibly apply.
-    // `ModuleMap::findModuleForHeader` will select the correct one.
+    // Add all modules corresponding to an umbrella header. We don't know which
+    // other headers these umbrella headers include, so it's possible any one 
of
+    // them includes `FileName`. `ModuleMap::findModuleForHeader` will select
+    // the correct module, accounting for any already known headers from other
+    // module maps or loaded PCMs.
+    //
+    // TODO: Clang should strictly enforce that umbrella headers include the
+    //       other headers in their directory, or that they are referenced in
+    //       the module map. The current behavior can be order of 
include/import
+    //       dependent. This would allow treating umbrella headers the same as
+    //       umbrella directories here.
     ModulesToLoad.append(MMState.UmbrellaHeaderModules.begin(),
                          MMState.UmbrellaHeaderModules.end());
 

>From 6f07c05fa04856be9e03f44d94f485776caace5b Mon Sep 17 00:00:00 2001
From: Michael Spencer <[email protected]>
Date: Wed, 25 Feb 2026 13:00:39 -0800
Subject: [PATCH 6/6] Use index instead of cache and split out visitor.

---
 clang/include/clang/Lex/HeaderSearch.h | 16 ++---
 clang/lib/Lex/HeaderSearch.cpp         | 83 +++++++++++++-------------
 2 files changed, 50 insertions(+), 49 deletions(-)

diff --git a/clang/include/clang/Lex/HeaderSearch.h 
b/clang/include/clang/Lex/HeaderSearch.h
index bd9caeee095ff..c8023652fef33 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -381,27 +381,27 @@ class HeaderSearch {
   /// map their keys to the SearchDir index of their header map.
   void indexInitialHeaderMaps();
 
-  /// Build the header to module cache for a directory's module map.
+  /// Build the module map index for a directory's module map.
   ///
-  /// This fills a ModuleMapDirectoryState with information from its 
directory's
-  /// module map.
-  void buildHeaderToModuleCache(DirectoryEntryRef Dir,
+  /// This fills a ModuleMapDirectoryState with index information from its
+  /// directory's module map.
+  void buildModuleMapIndex(DirectoryEntryRef Dir,
                                 ModuleMapDirectoryState &MMState);
 
-  void processModuleMapForHeaderToModuleCache(
+  void processModuleMapForIndex(
       const modulemap::ModuleMapFile &MMF, DirectoryEntryRef MMDir,
       StringRef PathPrefix, ModuleMapDirectoryState &MMState);
 
-  void processExternModuleDeclForHeaderToModuleCache(
+  void processExternModuleDeclForIndex(
       const modulemap::ExternModuleDecl &EMD, DirectoryEntryRef MMDir,
       StringRef PathPrefix, ModuleMapDirectoryState &MMState);
 
-  void processModuleDeclForHeaderToModuleCache(
+  void processModuleDeclForIndex(
       const modulemap::ModuleDecl &MD, StringRef ModuleName,
       DirectoryEntryRef MMDir, StringRef PathPrefix,
       ModuleMapDirectoryState &MMState);
 
-  void addToHeaderToModuleCache(StringRef RelPath, StringRef ModuleName,
+  void addToModuleMapIndex(StringRef RelPath, StringRef ModuleName,
                                 StringRef PathPrefix,
                                 ModuleMapDirectoryState &MMState);
 
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 56f82e04a9601..0e8898245eaea 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1619,7 +1619,7 @@ StringRef HeaderSearch::getIncludeNameForHeader(const 
FileEntry *File) const {
   return It->second;
 }
 
-void HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
+void HeaderSearch::buildModuleMapIndex(DirectoryEntryRef Dir,
                                             ModuleMapDirectoryState &MMState) {
   if (!MMState.ModuleMapFile)
     return;
@@ -1631,12 +1631,12 @@ void 
HeaderSearch::buildHeaderToModuleCache(DirectoryEntryRef Dir,
   if (MMState.PrivateModuleMapFile)
     ParsedPrivateMM = ModMap.getParsedModuleMap(*MMState.PrivateModuleMapFile);
 
-  processModuleMapForHeaderToModuleCache(*ParsedMM, Dir, "", MMState);
+  processModuleMapForIndex(*ParsedMM, Dir, "", MMState);
   if (ParsedPrivateMM)
-    processModuleMapForHeaderToModuleCache(*ParsedPrivateMM, Dir, "", MMState);
+    processModuleMapForIndex(*ParsedPrivateMM, Dir, "", MMState);
 }
 
-void HeaderSearch::addToHeaderToModuleCache(StringRef RelPath,
+void HeaderSearch::addToModuleMapIndex(StringRef RelPath,
                                             StringRef ModuleName,
                                             StringRef PathPrefix,
                                             ModuleMapDirectoryState &MMState) {
@@ -1646,7 +1646,7 @@ void HeaderSearch::addToHeaderToModuleCache(StringRef 
RelPath,
   MMState.HeaderToModules[RelFromRootPath].push_back(ModuleName);
 }
 
-void HeaderSearch::processExternModuleDeclForHeaderToModuleCache(
+void HeaderSearch::processExternModuleDeclForIndex(
     const modulemap::ExternModuleDecl &EMD, DirectoryEntryRef MMDir,
     StringRef PathPrefix, ModuleMapDirectoryState &MMState) {
   StringRef FileNameRef = EMD.Path;
@@ -1666,62 +1666,63 @@ void 
HeaderSearch::processExternModuleDeclForHeaderToModuleCache(
         llvm::sys::path::append(NewPrefix, ExternDir);
         llvm::sys::path::native(NewPrefix);
       }
-      processModuleMapForHeaderToModuleCache(*ExtMMF, EFile->getDir(),
+      processModuleMapForIndex(*ExtMMF, EFile->getDir(),
                                              NewPrefix, MMState);
     }
   }
 }
 
-void HeaderSearch::processModuleDeclForHeaderToModuleCache(
+void HeaderSearch::processModuleDeclForIndex(
     const modulemap::ModuleDecl &MD, StringRef ModuleName,
     DirectoryEntryRef MMDir, StringRef PathPrefix,
     ModuleMapDirectoryState &MMState) {
   // Skip inferred submodules (module *)
   if (MD.Id.front().first == "*")
     return;
+
+  auto ProcessDecl = llvm::makeVisitor(
+      [&](const modulemap::HeaderDecl &HD) {
+        if (HD.Umbrella) {
+          MMState.UmbrellaHeaderModules.push_back(ModuleName);
+        } else {
+          addToModuleMapIndex(HD.Path, ModuleName, PathPrefix, MMState);
+        }
+      },
+      [&](const modulemap::UmbrellaDirDecl &UDD) {
+        SmallString<128> FullPath(PathPrefix);
+        llvm::sys::path::append(FullPath, UDD.Path);
+        llvm::sys::path::native(FullPath);
+        MMState.UmbrellaDirModules.push_back(
+            std::make_pair(std::string(FullPath), ModuleName));
+      },
+      [&](const modulemap::ModuleDecl &SubMD) {
+        processModuleDeclForIndex(SubMD, ModuleName, MMDir,
+                                                PathPrefix, MMState);
+      },
+      [&](const modulemap::ExternModuleDecl &EMD) {
+        processExternModuleDeclForIndex(EMD, MMDir, PathPrefix,
+                                                      MMState);
+      },
+      [](const auto &) {
+        // Ignore other decls.
+      });
+
   for (const auto &Decl : MD.Decls) {
-    std::visit(llvm::makeVisitor(
-                   [&](const modulemap::HeaderDecl &HD) {
-                     if (HD.Umbrella) {
-                       MMState.UmbrellaHeaderModules.push_back(ModuleName);
-                     } else {
-                       addToHeaderToModuleCache(HD.Path, ModuleName, 
PathPrefix,
-                                                MMState);
-                     }
-                   },
-                   [&](const modulemap::UmbrellaDirDecl &UDD) {
-                     SmallString<128> FullPath(PathPrefix);
-                     llvm::sys::path::append(FullPath, UDD.Path);
-                     llvm::sys::path::native(FullPath);
-                     MMState.UmbrellaDirModules.push_back(
-                         std::make_pair(std::string(FullPath), ModuleName));
-                   },
-                   [&](const modulemap::ModuleDecl &SubMD) {
-                     processModuleDeclForHeaderToModuleCache(
-                         SubMD, ModuleName, MMDir, PathPrefix, MMState);
-                   },
-                   [&](const modulemap::ExternModuleDecl &EMD) {
-                     processExternModuleDeclForHeaderToModuleCache(
-                         EMD, MMDir, PathPrefix, MMState);
-                   },
-                   [](const auto &) {
-                     // Ignore other decls.
-                   }),
-               Decl);
+    std::visit(ProcessDecl, Decl);
   }
 }
 
-void HeaderSearch::processModuleMapForHeaderToModuleCache(
+void HeaderSearch::processModuleMapForIndex(
     const modulemap::ModuleMapFile &MMF, DirectoryEntryRef MMDir,
     StringRef PathPrefix, ModuleMapDirectoryState &MMState) {
   for (const auto &Decl : MMF.Decls) {
     std::visit(llvm::makeVisitor(
                    [&](const modulemap::ModuleDecl &MD) {
-                     processModuleDeclForHeaderToModuleCache(
+                     processModuleDeclForIndex(
                          MD, MD.Id.front().first, MMDir, PathPrefix, MMState);
                    },
                    [&](const modulemap::ExternModuleDecl &EMD) {
-                     processExternModuleDeclForHeaderToModuleCache(
+                     processExternModuleDeclForIndex(
                          EMD, MMDir, PathPrefix, MMState);
                    }),
                Decl);
@@ -1763,10 +1764,10 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
 
     auto &MMState = DirState->second;
 
-    // Build cache if not already built
+    // Build index if not already built
     if (MMState.HeaderToModules.empty() && MMState.UmbrellaDirModules.empty() 
&&
         MMState.UmbrellaHeaderModules.empty()) {
-      buildHeaderToModuleCache(*Dir, MMState);
+      buildModuleMapIndex(*Dir, MMState);
     }
 
     // Compute relative path from directory to the file. Use DirName (which
@@ -1781,7 +1782,7 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
     llvm::sys::path::native(RelativePathNative);
     RelativePath = RelativePathNative;
 
-    // Check for exact matches in cache
+    // Check for exact matches in index
     llvm::SmallVector<StringRef, 4> ModulesToLoad;
     auto CachedMods = MMState.HeaderToModules.find(RelativePath);
     if (CachedMods != MMState.HeaderToModules.end()) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to