PR21215: Support -fmodule-map-file being specified multiple times. Support
loading multiple module map files from the same directory.

llvm-svn: 220020
diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h
index ad76714..086d348 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -231,7 +231,11 @@
   
   /// \brief Describes whether a given directory has a module map in it.
   llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap;
-  
+
+  /// \brief Set of module map files we've already loaded, and a flag indicating
+  /// whether they were valid or not.
+  llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps;
+
   /// \brief Uniqued set of framework names, which is used to track which 
   /// headers were included as framework headers.
   llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index da2b651..28cb4df 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -3826,13 +3826,11 @@
 
   // -fmodule-name specifies the module that is currently being built (or
   // used for header checking by -fmodule-maps).
-  if (Arg *A = Args.getLastArg(options::OPT_fmodule_name))
-    A->render(Args, CmdArgs);
+  Args.AddLastArg(CmdArgs, options::OPT_fmodule_name);
 
-  // -fmodule-map-file can be used to specify a file containing module
+  // -fmodule-map-file can be used to specify files containing module
   // definitions.
-  if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file))
-    A->render(Args, CmdArgs);
+  Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
 
   // -fmodule-cache-path specifies where our module files should be written.
   SmallString<128> ModuleCachePath;
@@ -3867,9 +3865,8 @@
     CmdArgs.push_back(Args.MakeArgString(VFSDir));
   }
 
-  if (Arg *A = Args.getLastArg(options::OPT_fmodules_user_build_path))
-    if (HaveModules)
-      A->render(Args, CmdArgs);
+  if (HaveModules)
+    Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
 
   // Pass through all -fmodules-ignore-macro arguments.
   Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index bdec26f..e16b537 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1146,27 +1146,27 @@
 HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem) {
   assert(File && "expected FileEntry");
 
-  const DirectoryEntry *Dir = File->getDir();
-  auto KnownDir = DirectoryHasModuleMap.find(Dir);
-  if (KnownDir != DirectoryHasModuleMap.end())
-    return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+  // 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));
+  if (!AddResult.second)
+    return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
 
   if (ModMap.parseModuleMapFile(File, IsSystem)) {
-    DirectoryHasModuleMap[Dir] = false;
+    LoadedModuleMaps[File] = false;
     return LMM_InvalidModuleMap;
   }
 
   // Try to load a corresponding private module map.
   if (const FileEntry *PMMFile =
-        getPrivateModuleMap(File->getName(), Dir, FileMgr)) {
+          getPrivateModuleMap(File->getName(), File->getDir(), FileMgr)) {
     if (ModMap.parseModuleMapFile(PMMFile, IsSystem)) {
-      DirectoryHasModuleMap[Dir] = false;
+      LoadedModuleMaps[File] = false;
       return LMM_InvalidModuleMap;
     }
   }
 
   // This directory has a module map.
-  DirectoryHasModuleMap[Dir] = true;
   return LMM_NewlyLoaded;
 }
 
@@ -1226,7 +1226,7 @@
                                 bool IsFramework) {
   auto KnownDir = DirectoryHasModuleMap.find(Dir);
   if (KnownDir != DirectoryHasModuleMap.end())
-    return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+    return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
 
   if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
     LoadModuleMapResult Result = loadModuleMapFileImpl(ModuleMapFile, IsSystem);
@@ -1235,6 +1235,8 @@
     //      ^Dir                  ^ModuleMapFile
     if (Result == LMM_NewlyLoaded)
       DirectoryHasModuleMap[Dir] = true;
+    else if (Result == LMM_InvalidModuleMap)
+      DirectoryHasModuleMap[Dir] = false;
     return Result;
   }
   return LMM_InvalidModuleMap;
diff --git a/clang/test/Driver/modules.m b/clang/test/Driver/modules.m
index fbd41d8..dafb934 100644
--- a/clang/test/Driver/modules.m
+++ b/clang/test/Driver/modules.m
@@ -33,3 +33,8 @@
 
 // RUN: %clang -fmodules-validate-system-headers -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_SYSTEM_HEADERS %s
 // MODULES_VALIDATE_SYSTEM_HEADERS: -fmodules-validate-system-headers
+
+// RUN: %clang -fmodules -fmodule-map-file=foo.map -fmodule-map-file=bar.map -### %s 2>&1 | FileCheck -check-prefix=CHECK-MODULE-MAP-FILES %s
+// CHECK-MODULE-MAP-FILES: "-fmodules"
+// CHECK-MODULE-MAP-FILES: "-fmodule-map-file=" "foo.map"
+// CHECK-MODULE-MAP-FILES: "-fmodule-map-file=" "bar.map"
diff --git a/clang/test/Modules/Inputs/modular_maps/c.h b/clang/test/Modules/Inputs/modular_maps/c.h
new file mode 100644
index 0000000..6e3468e
--- /dev/null
+++ b/clang/test/Modules/Inputs/modular_maps/c.h
@@ -0,0 +1,4 @@
+#ifndef C_H
+#define C_H
+const int c = 5;
+#endif
diff --git a/clang/test/Modules/Inputs/modular_maps/common.h b/clang/test/Modules/Inputs/modular_maps/common.h
index f690bcb..349bf5f 100644
--- a/clang/test/Modules/Inputs/modular_maps/common.h
+++ b/clang/test/Modules/Inputs/modular_maps/common.h
@@ -1,4 +1,4 @@
 #ifndef COMMON_H
 #define COMMON_H
-const int c = 2;
+const int x = 2;
 #endif
diff --git a/clang/test/Modules/Inputs/modular_maps/modulec.map b/clang/test/Modules/Inputs/modular_maps/modulec.map
new file mode 100644
index 0000000..c5a1ffe
--- /dev/null
+++ b/clang/test/Modules/Inputs/modular_maps/modulec.map
@@ -0,0 +1,3 @@
+module C {
+  header "c.h"
+}
diff --git a/clang/test/Modules/modular_maps.cpp b/clang/test/Modules/modular_maps.cpp
index 9c9aba8..484e727 100644
--- a/clang/test/Modules/modular_maps.cpp
+++ b/clang/test/Modules/modular_maps.cpp
@@ -1,8 +1,10 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -fmodule-map-file=%S/Inputs/modular_maps/modulec.map -I %S/Inputs/modular_maps %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulec.map -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
 
 #include "common.h"
 #include "a.h"
 #include "b.h" // expected-error {{private header}}
-const int v = a + c;
-const int val = a + b + c; // expected-error {{undeclared identifier}}
+@import C;
+const int v = a + c + x;
+const int val = a + b + c + x; // expected-error {{undeclared identifier}}