[modules] Load .pcm files specified by -fmodule-file lazily.

llvm-svn: 220731
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 03ab20b..366884e 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1257,51 +1257,61 @@
   }
 }
 
-ModuleLoadResult
-CompilerInstance::loadModuleFile(StringRef FileName, SourceLocation Loc) {
-  if (!ModuleManager)
-    createModuleManager();
-  if (!ModuleManager)
-    return ModuleLoadResult();
+bool CompilerInstance::loadModuleFile(StringRef FileName) {
+  // Helper to recursively read the module names for all modules we're adding.
+  // We mark these as known and redirect any attempt to load that module to
+  // the files we were handed.
+  struct ReadModuleNames : ASTReaderListener {
+    CompilerInstance &CI;
+    std::vector<StringRef> ModuleFileStack;
+    bool Failed;
+    bool TopFileIsModule;
 
-  // Load the module if this is the first time we've been told about this file.
-  auto *MF = ModuleManager->getModuleManager().lookup(FileName);
-  if (!MF) {
-    struct ReadModuleNameListener : ASTReaderListener {
-      std::function<void(StringRef)> OnRead;
-      ReadModuleNameListener(std::function<void(StringRef)> F) : OnRead(F) {}
-      void ReadModuleName(StringRef ModuleName) override { OnRead(ModuleName); }
-    };
+    ReadModuleNames(CompilerInstance &CI)
+        : CI(CI), Failed(false), TopFileIsModule(false) {}
 
-    // Register listener to track the modules that are loaded by explicitly
-    // loading a module file. We suppress any attempts to implicitly load
-    // module files for any such module.
-    ASTReader::ListenerScope OnReadModuleName(
-        *ModuleManager,
-        llvm::make_unique<ReadModuleNameListener>([&](StringRef ModuleName) {
-      auto &PP = getPreprocessor();
-      auto *NameII = PP.getIdentifierInfo(ModuleName);
-      auto *Module = PP.getHeaderSearchInfo().lookupModule(ModuleName, false);
-      if (!KnownModules.insert(std::make_pair(NameII, Module)).second)
-        getDiagnostics().Report(Loc, diag::err_module_already_loaded)
-            << ModuleName << FileName;
-    }));
+    bool needsImportVisitation() const override { return true; }
 
-    if (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule, Loc,
-                               ASTReader::ARR_None) != ASTReader::Success)
-      return ModuleLoadResult();
+    void visitImport(StringRef FileName) override {
+      ModuleFileStack.push_back(FileName);
+      if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(),
+                                             *this)) {
+        CI.getDiagnostics().Report(SourceLocation(),
+                                   diag::err_module_file_not_found)
+            << FileName;
+        // FIXME: Produce a note stack explaining how we got here.
+        Failed = true;
+      }
+      ModuleFileStack.pop_back();
+    }
 
-    MF = ModuleManager->getModuleManager().lookup(FileName);
-    assert(MF && "unexpectedly failed to load module file");
-  }
+    void ReadModuleName(StringRef ModuleName) override {
+      if (ModuleFileStack.size() == 1)
+        TopFileIsModule = true;
 
-  if (MF->ModuleName.empty()) {
-    getDiagnostics().Report(Loc, diag::err_module_file_not_module)
+      auto &ModuleFile = CI.ModuleFileOverrides[ModuleName];
+      if (!ModuleFile.empty() && ModuleFile != ModuleFileStack.back())
+        CI.getDiagnostics().Report(SourceLocation(),
+                                   diag::err_conflicting_module_files)
+            << ModuleName << ModuleFile << ModuleFileStack.back();
+      ModuleFile = ModuleFileStack.back();
+    }
+  } RMN(*this);
+
+  RMN.visitImport(FileName);
+
+  if (RMN.Failed)
+    return false;
+
+  // If we never found a module name for the top file, then it's not a module,
+  // it's a PCH or preamble or something.
+  if (!RMN.TopFileIsModule) {
+    getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_module)
       << FileName;
-    return ModuleLoadResult();
+    return false;
   }
-  auto *Module = PP->getHeaderSearchInfo().lookupModule(MF->ModuleName, false);
-  return ModuleLoadResult(Module, false);
+
+  return true;
 }
 
 ModuleLoadResult
@@ -1349,8 +1359,12 @@
       return ModuleLoadResult();
     }
 
+    auto Override = ModuleFileOverrides.find(ModuleName);
+    bool Explicit = Override != ModuleFileOverrides.end();
+
     std::string ModuleFileName =
-        PP->getHeaderSearchInfo().getModuleFileName(Module);
+        Explicit ? Override->second
+                 : PP->getHeaderSearchInfo().getModuleFileName(Module);
 
     // If we don't already have an ASTReader, create one now.
     if (!ModuleManager)
@@ -1366,15 +1380,24 @@
       Listener->attachToASTReader(*ModuleManager);
 
     // Try to load the module file.
-    unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+    unsigned ARRFlags =
+        Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
     switch (ModuleManager->ReadAST(ModuleFileName,
-                                   serialization::MK_ImplicitModule, ImportLoc,
-                                   ARRFlags)) {
+                                   Explicit ? serialization::MK_ExplicitModule
+                                            : serialization::MK_ImplicitModule,
+                                   ImportLoc, ARRFlags)) {
     case ASTReader::Success:
       break;
 
     case ASTReader::OutOfDate:
     case ASTReader::Missing: {
+      if (Explicit) {
+        // ReadAST has already complained for us.
+        ModuleLoader::HadFatalFailure = true;
+        KnownModules[Path[0].first] = nullptr;
+        return ModuleLoadResult();
+      }
+
       // The module file is missing or out-of-date. Build it.
       assert(Module && "missing module file");
       // Check whether there is a cycle in the module graph.
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 1c93842..c81c81a 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -383,16 +383,10 @@
            "doesn't support modules");
   }
 
-  // If we were asked to load any module files, do so now. Don't make any names
-  // from those modules visible.
-  for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) {
-    // FIXME: Use a better source location here. Perhaps inject something
-    // into the predefines buffer to represent these module files.
-    if (!CI.loadModuleFile(ModuleFile,
-                           CI.getSourceManager().getLocForStartOfFile(
-                               CI.getSourceManager().getMainFileID())))
+  // If we were asked to load any module files, do so now.
+  for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles)
+    if (!CI.loadModuleFile(ModuleFile))
       goto failure;
-  }
 
   // If there is a layout overrides file, attach an external AST source that
   // provides the layouts from that file.