r301610 - Move functionality for handling module maps as inputs from the -emit-module

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 27 18:49:43 PDT 2017


Author: rsmith
Date: Thu Apr 27 20:49:42 2017
New Revision: 301610

URL: http://llvm.org/viewvc/llvm-project?rev=301610&view=rev
Log:
Move functionality for handling module maps as inputs from the -emit-module
action to the general FrontendAction infrastructure.

This permits applying -E, -ast-dump, -fsyntax-only, and so on to a module map
compilation. (The -E form is not currently especially useful yet as there's no
good way to take the output and use it to actually build a module.)

In order to support this, -cc1 now accepts -x <lang>-module-map in all cases
where it accepts -x <lang> for a language we can parse (not ir/ast). And for
uniformity, we also accept -x <lang>-header for all such languages (we used
to reject for cuda and renderscript), and -x <lang>-cpp-output for all such
languages (we used to reject for c, cl, and renderscript).

(None of these new alternatives are accepted by the driver yet, so no
user-visible changes.)

Added:
    cfe/trunk/test/Modules/preprocess-module.cpp
Modified:
    cfe/trunk/include/clang/Frontend/FrontendActions.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendAction.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Frontend/FrontendOptions.cpp

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Thu Apr 27 20:49:42 2017
@@ -99,8 +99,6 @@ class GenerateModuleAction : public ASTF
   CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;
 
 protected:
-  bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
-
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
 
@@ -112,20 +110,11 @@ protected:
 };
 
 class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
-  clang::Module *Module = nullptr;
-  const FileEntry *ModuleMapForUniquing = nullptr;
-  bool IsSystem = false;
-
 private:
   bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
 
   std::unique_ptr<raw_pwrite_stream>
   CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
-
-public:
-  GenerateModuleFromModuleMapAction() {}
-  GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem)
-      : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {}
 };
 
 class GenerateModuleInterfaceAction : public GenerateModuleAction {

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Thu Apr 27 20:49:42 2017
@@ -23,6 +23,7 @@ class MemoryBuffer;
 }
 
 namespace clang {
+class FileEntry;
 
 namespace frontend {
   enum ActionKind {
@@ -100,9 +101,8 @@ public:
     Precompiled
   };
 
-  constexpr InputKind(Language L = Unknown, bool PP = false)
-      : Lang(L), Fmt(Source), Preprocessed(PP) {}
-  constexpr InputKind(Language L, Format F, bool PP = false)
+  constexpr InputKind(Language L = Unknown, Format F = Source,
+                      bool PP = false)
       : Lang(L), Fmt(F), Preprocessed(PP) {}
 
   Language getLanguage() const { return static_cast<Language>(Lang); }
@@ -118,6 +118,9 @@ public:
   InputKind getPreprocessed() const {
     return InputKind(getLanguage(), getFormat(), true);
   }
+  InputKind withFormat(Format F) const {
+    return InputKind(getLanguage(), F, isPreprocessed());
+  }
 };
 
 /// \brief An input file for the front end.
@@ -256,6 +259,10 @@ public:
   /// The input files and their types.
   std::vector<FrontendInputFile> Inputs;
 
+  /// When the input is a module map, the original module map file from which
+  /// that map was inferred, if any (for umbrella modules).
+  std::string OriginalModuleMap;
+
   /// The output file, if any.
   std::string OutputFile;
 

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Thu Apr 27 20:49:42 2017
@@ -1080,6 +1080,8 @@ static bool compileModuleImpl(CompilerIn
   FrontendOpts.DisableFree = false;
   FrontendOpts.GenerateGlobalModuleIndex = false;
   FrontendOpts.BuildingImplicitModule = true;
+  FrontendOpts.OriginalModuleMap =
+      ModMap.getModuleMapFileForUniquing(Module)->getName();
   // Force implicitly-built modules to hash the content of the module file.
   HSOpts.ModulesHashContent = true;
   FrontendOpts.Inputs.clear();
@@ -1129,11 +1131,12 @@ static bool compileModuleImpl(CompilerIn
   if (const FileEntry *ModuleMapFile =
           ModMap.getContainingModuleMapFile(Module)) {
     // Use the module map where this module resides.
-    FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK);
+    FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK,
+                                     +Module->IsSystem);
   } else {
     SmallString<128> FakeModuleMapFile(Module->Directory->getName());
     llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
-    FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK);
+    FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK, +Module->IsSystem);
 
     llvm::raw_string_ostream OS(InferredModuleMapContent);
     Module->print(OS);
@@ -1146,11 +1149,6 @@ static bool compileModuleImpl(CompilerIn
     SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
   }
 
-  // Construct a module-generating action. Passing through the module map is
-  // safe because the FileManager is shared between the compiler instances.
-  GenerateModuleFromModuleMapAction CreateModuleAction(
-      ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
-
   ImportingInstance.getDiagnostics().Report(ImportLoc,
                                             diag::remark_module_build)
     << Module->Name << ModuleFileName;
@@ -1159,8 +1157,12 @@ static bool compileModuleImpl(CompilerIn
   // thread so that we get a stack large enough.
   const unsigned ThreadStackSize = 8 << 20;
   llvm::CrashRecoveryContext CRC;
-  CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
-                        ThreadStackSize);
+  CRC.RunSafelyOnThread(
+      [&]() {
+        GenerateModuleFromModuleMapAction Action;
+        Instance.ExecuteAction(Action);
+      },
+      ThreadStackSize);
 
   ImportingInstance.getDiagnostics().Report(ImportLoc,
                                             diag::remark_module_build_done)

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Apr 27 20:49:42 2017
@@ -1350,30 +1350,51 @@ static InputKind ParseFrontendArgs(Front
   InputKind DashX(InputKind::Unknown);
   if (const Arg *A = Args.getLastArg(OPT_x)) {
     StringRef XValue = A->getValue();
+
+    // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'.
+    // FIXME: Supporting '<lang>-header-cpp-output' would be useful.
+    bool Preprocessed = XValue.consume_back("-cpp-output");
+    bool ModuleMap = XValue.consume_back("-module-map");
+    IsHeaderFile =
+        !Preprocessed && !ModuleMap && XValue.consume_back("-header");
+
+    // Principal languages.
     DashX = llvm::StringSwitch<InputKind>(XValue)
-      .Cases("c", "c-header", "cpp-output", InputKind::C)
-      .Cases("cl", "cl-header", InputKind::OpenCL)
-      .Cases("cuda", "cuda-cpp-output", InputKind::CUDA)
-      .Cases("c++", "c++-header", "c++-cpp-output", InputKind::CXX)
-      .Cases("objective-c", "objective-c-header",
-             "objective-c-cpp-output", "objc-cpp-output",
-             InputKind::ObjC)
-      .Cases("objective-c++", "objective-c++-header",
-             "objective-c++-cpp-output", "objc++-cpp-output",
-             InputKind::ObjCXX)
-      .Case("renderscript", InputKind::RenderScript)
-      .Case("assembler-with-cpp", InputKind::Asm)
-      .Cases("ast", "pcm",
-             InputKind(InputKind::Unknown, InputKind::Precompiled))
-      .Case("ir", InputKind::LLVM_IR)
-      .Default(InputKind::Unknown);
+                .Case("c", InputKind::C)
+                .Case("cl", InputKind::OpenCL)
+                .Case("cuda", InputKind::CUDA)
+                .Case("c++", InputKind::CXX)
+                .Case("objective-c", InputKind::ObjC)
+                .Case("objective-c++", InputKind::ObjCXX)
+                .Case("renderscript", InputKind::RenderScript)
+                .Default(InputKind::Unknown);
+
+    // "objc[++]-cpp-output" is an acceptable synonym for
+    // "objective-c[++]-cpp-output".
+    if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap)
+      DashX = llvm::StringSwitch<InputKind>(XValue)
+                  .Case("objc", InputKind::ObjC)
+                  .Case("objc++", InputKind::ObjCXX)
+                  .Default(InputKind::Unknown);
+
+    // Some special cases cannot be combined with suffixes.
+    if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile)
+      DashX = llvm::StringSwitch<InputKind>(XValue)
+                  .Case("cpp-output", InputKind(InputKind::C).getPreprocessed())
+                  .Case("assembler-with-cpp", InputKind::Asm)
+                  .Cases("ast", "pcm",
+                         InputKind(InputKind::Unknown, InputKind::Precompiled))
+                  .Case("ir", InputKind::LLVM_IR)
+                  .Default(InputKind::Unknown);
+
     if (DashX.isUnknown())
       Diags.Report(diag::err_drv_invalid_value)
         << A->getAsString(Args) << A->getValue();
 
-    if (XValue.endswith("cpp-output"))
+    if (Preprocessed)
       DashX = DashX.getPreprocessed();
-    IsHeaderFile = XValue.endswith("-header");
+    if (ModuleMap)
+      DashX = DashX.withFormat(InputKind::ModuleMap);
   }
 
   // '-' is the default input if none is given.
@@ -1393,6 +1414,12 @@ static InputKind ParseFrontendArgs(Front
       if (i == 0)
         DashX = IK;
     }
+
+    // The -emit-module action implicitly takes a module map.
+    if (Opts.ProgramAction == frontend::GenerateModule &&
+        IK.getFormat() == InputKind::Source)
+      IK = IK.withFormat(InputKind::ModuleMap);
+
     Opts.Inputs.emplace_back(std::move(Inputs[i]), IK);
   }
 

Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendAction.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendAction.cpp Thu Apr 27 20:49:42 2017
@@ -224,6 +224,231 @@ static bool ReadOriginalFileName(Compile
   return true;
 }
 
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+  Includes.append(RHS.begin(), RHS.end());
+  return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+                             SmallVectorImpl<char> &Includes,
+                             const LangOptions &LangOpts,
+                             bool IsExternC) {
+  if (IsExternC && LangOpts.CPlusPlus)
+    Includes += "extern \"C\" {\n";
+  if (LangOpts.ObjC1)
+    Includes += "#import \"";
+  else
+    Includes += "#include \"";
+
+  Includes += HeaderName;
+
+  Includes += "\"\n";
+  if (IsExternC && LangOpts.CPlusPlus)
+    Includes += "}\n";
+}
+
+/// \brief Collect the set of header includes needed to construct the given 
+/// module and update the TopHeaders file set of the module.
+///
+/// \param Module The module we're collecting includes from.
+///
+/// \param Includes Will be augmented with the set of \#includes or \#imports
+/// needed to load all of the named headers.
+static std::error_code
+collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
+                            ModuleMap &ModMap, clang::Module *Module,
+                            SmallVectorImpl<char> &Includes) {
+  // Don't collect any headers for unavailable modules.
+  if (!Module->isAvailable())
+    return std::error_code();
+
+  // Add includes for each of these headers.
+  for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+    for (Module::Header &H : Module->Headers[HK]) {
+      Module->addTopHeader(H.Entry);
+      // Use the path as specified in the module map file. We'll look for this
+      // file relative to the module build directory (the directory containing
+      // the module map file) so this will find the same file that we found
+      // while parsing the module map.
+      addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
+    }
+  }
+  // Note that Module->PrivateHeaders will not be a TopHeader.
+
+  if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
+    Module->addTopHeader(UmbrellaHeader.Entry);
+    if (Module->Parent)
+      // Include the umbrella header for submodules.
+      addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
+                       Module->IsExternC);
+  } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
+    // Add all of the headers we find in this subdirectory.
+    std::error_code EC;
+    SmallString<128> DirNative;
+    llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
+
+    vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+    for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
+         Dir != End && !EC; Dir.increment(EC)) {
+      // Check whether this entry has an extension typically associated with 
+      // headers.
+      if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
+          .Cases(".h", ".H", ".hh", ".hpp", true)
+          .Default(false))
+        continue;
+
+      const FileEntry *Header = FileMgr.getFile(Dir->getName());
+      // FIXME: This shouldn't happen unless there is a file system race. Is
+      // that worth diagnosing?
+      if (!Header)
+        continue;
+
+      // If this header is marked 'unavailable' in this module, don't include 
+      // it.
+      if (ModMap.isHeaderUnavailableInModule(Header, Module))
+        continue;
+
+      // Compute the relative path from the directory to this file.
+      SmallVector<StringRef, 16> Components;
+      auto PathIt = llvm::sys::path::rbegin(Dir->getName());
+      for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
+        Components.push_back(*PathIt);
+      SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
+      for (auto It = Components.rbegin(), End = Components.rend(); It != End;
+           ++It)
+        llvm::sys::path::append(RelativeHeader, *It);
+
+      // Include this header as part of the umbrella directory.
+      Module->addTopHeader(Header);
+      addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
+    }
+
+    if (EC)
+      return EC;
+  }
+
+  // Recurse into submodules.
+  for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+                                      SubEnd = Module->submodule_end();
+       Sub != SubEnd; ++Sub)
+    if (std::error_code Err = collectModuleHeaderIncludes(
+            LangOpts, FileMgr, ModMap, *Sub, Includes))
+      return Err;
+
+  return std::error_code();
+}
+
+/// Parse a module map and compute the corresponding real input buffer that
+/// should be used to build the module described by that module map and the
+/// current module name.
+static std::unique_ptr<llvm::MemoryBuffer>
+getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename,
+                           bool IsSystem) {
+  // Find the module map file.
+  const FileEntry *ModuleMap =
+      CI.getFileManager().getFile(Filename, /*openFile*/true);
+  if (!ModuleMap)  {
+    CI.getDiagnostics().Report(diag::err_module_map_not_found)
+      << Filename;
+    return nullptr;
+  }
+
+  // Find the module map file from which it was generated, if different.
+  const FileEntry *OriginalModuleMap = ModuleMap;
+  StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap;
+  if (!OriginalModuleMapName.empty()) {
+    OriginalModuleMap = CI.getFileManager().getFile(OriginalModuleMapName,
+                                                    /*openFile*/ true);
+    if (!OriginalModuleMap) {
+      CI.getDiagnostics().Report(diag::err_module_map_not_found)
+        << OriginalModuleMapName;
+      return nullptr;
+    }
+  }
+  
+  // Parse the module map file.
+  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  if (HS.loadModuleMapFile(ModuleMap, IsSystem))
+    return nullptr;
+  
+  if (CI.getLangOpts().CurrentModule.empty()) {
+    CI.getDiagnostics().Report(diag::err_missing_module_name);
+    
+    // FIXME: Eventually, we could consider asking whether there was just
+    // a single module described in the module map, and use that as a 
+    // default. Then it would be fairly trivial to just "compile" a module
+    // map with a single module (the common case).
+    return nullptr;
+  }
+
+  // If we're being run from the command-line, the module build stack will not
+  // have been filled in yet, so complete it now in order to allow us to detect
+  // module cycles.
+  SourceManager &SourceMgr = CI.getSourceManager();
+  if (SourceMgr.getModuleBuildStack().empty())
+    SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
+                                   FullSourceLoc(SourceLocation(), SourceMgr));
+
+  // Dig out the module definition.
+  Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule,
+                              /*AllowSearch=*/false);
+  if (!M) {
+    CI.getDiagnostics().Report(diag::err_missing_module)
+      << CI.getLangOpts().CurrentModule << Filename;
+    
+    return nullptr;
+  }
+
+  // Check whether we can build this module at all.
+  clang::Module::Requirement Requirement;
+  clang::Module::UnresolvedHeaderDirective MissingHeader;
+  if (!M->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
+                      MissingHeader)) {
+    if (MissingHeader.FileNameLoc.isValid()) {
+      CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
+                                 diag::err_module_header_missing)
+        << MissingHeader.IsUmbrella << MissingHeader.FileName;
+    } else {
+      CI.getDiagnostics().Report(diag::err_module_unavailable)
+        << M->getFullModuleName() << Requirement.second << Requirement.first;
+    }
+
+    return nullptr;
+  }
+
+  if (OriginalModuleMap != ModuleMap) {
+    M->IsInferred = true;
+    HS.getModuleMap().setInferredModuleAllowedBy(M, OriginalModuleMap);
+  }
+
+  FileManager &FileMgr = CI.getFileManager();
+
+  // Collect the set of #includes we need to build the module.
+  SmallString<256> HeaderContents;
+  std::error_code Err = std::error_code();
+  if (Module::Header UmbrellaHeader = M->getUmbrellaHeader())
+    addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
+                     CI.getLangOpts(), M->IsExternC);
+  Err = collectModuleHeaderIncludes(
+      CI.getLangOpts(), FileMgr,
+      CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M,
+      HeaderContents);
+
+  if (Err) {
+    CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
+      << M->getFullModuleName() << Err.message();
+    return nullptr;
+  }
+
+  // Inform the preprocessor that includes from within the input buffer should
+  // be resolved relative to the build directory of the module map file.
+  CI.getPreprocessor().setMainFileDir(M->Directory);
+
+  return llvm::MemoryBuffer::getMemBufferCopy(
+      HeaderContents, Module::getModuleInputBufferName());
+}
+
 bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
                                      const FrontendInputFile &Input) {
   assert(!Instance && "Already processing a source file!");
@@ -232,6 +457,7 @@ bool FrontendAction::BeginSourceFile(Com
   setCompilerInstance(&CI);
 
   StringRef InputFile = Input.getFile();
+  FrontendInputFile FileToProcess = Input;
   bool HasBegunSourceFile = false;
   if (!BeginInvocation(CI))
     goto failure;
@@ -297,6 +523,17 @@ bool FrontendAction::BeginSourceFile(Com
   if (!CI.hasSourceManager())
     CI.createSourceManager(CI.getFileManager());
 
+  // Set up embedding for any specified files. Do this before we load any
+  // source files, including the primary module map for the compilation.
+  for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+    if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+      CI.getSourceManager().setFileIsTransient(FE);
+    else
+      CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+  }
+  if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+    CI.getSourceManager().setAllFilesAreTransient(true);
+
   // IR files bypass the rest of initialization.
   if (Input.getKind().getLanguage() == InputKind::LLVM_IR) {
     assert(hasIRSupport() &&
@@ -360,13 +597,34 @@ bool FrontendAction::BeginSourceFile(Com
                                            &CI.getPreprocessor());
   HasBegunSourceFile = true;
 
+  // For module map files, we first parse the module map and synthesize a
+  // "<module-includes>" buffer before more conventional processing.
+  if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+    CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
+
+    auto Buffer = getInputBufferForModuleMap(CI, InputFile, Input.isSystem());
+    if (!Buffer)
+      goto failure;
+
+    Module *CurrentModule =
+        CI.getPreprocessor().getHeaderSearchInfo().lookupModule(
+            CI.getLangOpts().CurrentModule,
+            /*AllowSearch=*/false);
+    assert(CurrentModule && "no module info for current module");
+
+    // The input that we end up processing is the generated buffer, not the
+    // module map file itself.
+    FileToProcess = FrontendInputFile(
+        Buffer.release(), Input.getKind().withFormat(InputKind::Source),
+        CurrentModule->IsSystem);
+  }
+
   // Initialize the action.
   if (!BeginSourceFileAction(CI, InputFile))
     goto failure;
 
-  // Initialize the main file entry. It is important that this occurs after
-  // BeginSourceFileAction, which may change CurrentInput during module builds.
-  if (!CI.InitializeSourceManager(CurrentInput))
+  // Initialize the main file entry.
+  if (!CI.InitializeSourceManager(FileToProcess))
     goto failure;
 
   // Create the AST context and consumer unless this is a preprocessor only
@@ -498,6 +756,7 @@ bool FrontendAction::BeginSourceFile(Com
   if (HasBegunSourceFile)
     CI.getDiagnosticClient().EndSourceFile();
   CI.clearOutputFiles(/*EraseFiles=*/true);
+  CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
   setCurrentInput(FrontendInputFile());
   setCompilerInstance(nullptr);
   return false;
@@ -580,6 +839,7 @@ void FrontendAction::EndSourceFile() {
 
   setCompilerInstance(nullptr);
   setCurrentInput(FrontendInputFile());
+  CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
 }
 
 bool FrontendAction::shouldEraseOutputFiles() {

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Thu Apr 27 20:49:42 2017
@@ -164,242 +164,9 @@ GenerateModuleAction::CreateASTConsumer(
   return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
 }
 
-bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 
-                                                 StringRef Filename) {
-  // Set up embedding for any specified files. Do this before we load any
-  // source files, including the primary module map for the compilation.
-  for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
-    if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
-      CI.getSourceManager().setFileIsTransient(FE);
-    else
-      CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
-  }
-  if (CI.getFrontendOpts().ModulesEmbedAllFiles)
-    CI.getSourceManager().setAllFilesAreTransient(true);
-
-  return true;
-}
-
-
-static SmallVectorImpl<char> &
-operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
-  Includes.append(RHS.begin(), RHS.end());
-  return Includes;
-}
-
-static void addHeaderInclude(StringRef HeaderName,
-                             SmallVectorImpl<char> &Includes,
-                             const LangOptions &LangOpts,
-                             bool IsExternC) {
-  if (IsExternC && LangOpts.CPlusPlus)
-    Includes += "extern \"C\" {\n";
-  if (LangOpts.ObjC1)
-    Includes += "#import \"";
-  else
-    Includes += "#include \"";
-
-  Includes += HeaderName;
-
-  Includes += "\"\n";
-  if (IsExternC && LangOpts.CPlusPlus)
-    Includes += "}\n";
-}
-
-/// \brief Collect the set of header includes needed to construct the given 
-/// module and update the TopHeaders file set of the module.
-///
-/// \param Module The module we're collecting includes from.
-///
-/// \param Includes Will be augmented with the set of \#includes or \#imports
-/// needed to load all of the named headers.
-static std::error_code
-collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
-                            ModuleMap &ModMap, clang::Module *Module,
-                            SmallVectorImpl<char> &Includes) {
-  // Don't collect any headers for unavailable modules.
-  if (!Module->isAvailable())
-    return std::error_code();
-
-  // Add includes for each of these headers.
-  for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
-    for (Module::Header &H : Module->Headers[HK]) {
-      Module->addTopHeader(H.Entry);
-      // Use the path as specified in the module map file. We'll look for this
-      // file relative to the module build directory (the directory containing
-      // the module map file) so this will find the same file that we found
-      // while parsing the module map.
-      addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
-    }
-  }
-  // Note that Module->PrivateHeaders will not be a TopHeader.
-
-  if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
-    Module->addTopHeader(UmbrellaHeader.Entry);
-    if (Module->Parent)
-      // Include the umbrella header for submodules.
-      addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
-                       Module->IsExternC);
-  } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
-    // Add all of the headers we find in this subdirectory.
-    std::error_code EC;
-    SmallString<128> DirNative;
-    llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
-
-    vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
-    for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
-         Dir != End && !EC; Dir.increment(EC)) {
-      // Check whether this entry has an extension typically associated with 
-      // headers.
-      if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
-          .Cases(".h", ".H", ".hh", ".hpp", true)
-          .Default(false))
-        continue;
-
-      const FileEntry *Header = FileMgr.getFile(Dir->getName());
-      // FIXME: This shouldn't happen unless there is a file system race. Is
-      // that worth diagnosing?
-      if (!Header)
-        continue;
-
-      // If this header is marked 'unavailable' in this module, don't include 
-      // it.
-      if (ModMap.isHeaderUnavailableInModule(Header, Module))
-        continue;
-
-      // Compute the relative path from the directory to this file.
-      SmallVector<StringRef, 16> Components;
-      auto PathIt = llvm::sys::path::rbegin(Dir->getName());
-      for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
-        Components.push_back(*PathIt);
-      SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
-      for (auto It = Components.rbegin(), End = Components.rend(); It != End;
-           ++It)
-        llvm::sys::path::append(RelativeHeader, *It);
-
-      // Include this header as part of the umbrella directory.
-      Module->addTopHeader(Header);
-      addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
-    }
-
-    if (EC)
-      return EC;
-  }
-
-  // Recurse into submodules.
-  for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
-                                      SubEnd = Module->submodule_end();
-       Sub != SubEnd; ++Sub)
-    if (std::error_code Err = collectModuleHeaderIncludes(
-            LangOpts, FileMgr, ModMap, *Sub, Includes))
-      return Err;
-
-  return std::error_code();
-}
-
 bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
     CompilerInstance &CI, StringRef Filename) {
-  CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
-
-  if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename))
-    return false;
-
-  // Find the module map file.
-  const FileEntry *ModuleMap =
-      CI.getFileManager().getFile(Filename, /*openFile*/true);
-  if (!ModuleMap)  {
-    CI.getDiagnostics().Report(diag::err_module_map_not_found)
-      << Filename;
-    return false;
-  }
-  
-  // Parse the module map file.
-  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
-  if (HS.loadModuleMapFile(ModuleMap, IsSystem))
-    return false;
-  
-  if (CI.getLangOpts().CurrentModule.empty()) {
-    CI.getDiagnostics().Report(diag::err_missing_module_name);
-    
-    // FIXME: Eventually, we could consider asking whether there was just
-    // a single module described in the module map, and use that as a 
-    // default. Then it would be fairly trivial to just "compile" a module
-    // map with a single module (the common case).
-    return false;
-  }
-
-  // If we're being run from the command-line, the module build stack will not
-  // have been filled in yet, so complete it now in order to allow us to detect
-  // module cycles.
-  SourceManager &SourceMgr = CI.getSourceManager();
-  if (SourceMgr.getModuleBuildStack().empty())
-    SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
-                                   FullSourceLoc(SourceLocation(), SourceMgr));
-
-  // Dig out the module definition.
-  Module = HS.lookupModule(CI.getLangOpts().CurrentModule, 
-                           /*AllowSearch=*/false);
-  if (!Module) {
-    CI.getDiagnostics().Report(diag::err_missing_module)
-      << CI.getLangOpts().CurrentModule << Filename;
-    
-    return false;
-  }
-
-  // Check whether we can build this module at all.
-  clang::Module::Requirement Requirement;
-  clang::Module::UnresolvedHeaderDirective MissingHeader;
-  if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
-                           MissingHeader)) {
-    if (MissingHeader.FileNameLoc.isValid()) {
-      CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
-                                 diag::err_module_header_missing)
-        << MissingHeader.IsUmbrella << MissingHeader.FileName;
-    } else {
-      CI.getDiagnostics().Report(diag::err_module_unavailable)
-        << Module->getFullModuleName()
-        << Requirement.second << Requirement.first;
-    }
-
-    return false;
-  }
-
-  if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) {
-    Module->IsInferred = true;
-    HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing);
-  } else {
-    ModuleMapForUniquing = ModuleMap;
-  }
-
-  FileManager &FileMgr = CI.getFileManager();
-
-  // Collect the set of #includes we need to build the module.
-  SmallString<256> HeaderContents;
-  std::error_code Err = std::error_code();
-  if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader())
-    addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
-                     CI.getLangOpts(), Module->IsExternC);
-  Err = collectModuleHeaderIncludes(
-        CI.getLangOpts(), FileMgr,
-        CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module,
-        HeaderContents);
-
-  if (Err) {
-    CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
-      << Module->getFullModuleName() << Err.message();
-    return false;
-  }
-
-  // Inform the preprocessor that includes from within the input buffer should
-  // be resolved relative to the build directory of the module map file.
-  CI.getPreprocessor().setMainFileDir(Module->Directory);
-
-  std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
-      llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
-                                           Module::getModuleInputBufferName());
-  // Ownership of InputBuffer will be transferred to the SourceManager.
-  setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
-                                    Module->IsSystem));
-  return true;
+  return GenerateModuleAction::BeginSourceFileAction(CI, Filename);
 }
 
 std::unique_ptr<raw_pwrite_stream>
@@ -408,10 +175,13 @@ GenerateModuleFromModuleMapAction::Creat
   // If no output file was provided, figure out where this module would go
   // in the module cache.
   if (CI.getFrontendOpts().OutputFile.empty()) {
+    StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
+    if (ModuleMapFile.empty())
+      ModuleMapFile = InFile;
+
     HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
     CI.getFrontendOpts().OutputFile =
-        HS.getModuleFileName(CI.getLangOpts().CurrentModule,
-                             ModuleMapForUniquing->getName(),
+        HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile,
                              /*UsePrebuiltPath=*/false);
   }
 

Modified: cfe/trunk/lib/Frontend/FrontendOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendOptions.cpp?rev=301610&r1=301609&r2=301610&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendOptions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendOptions.cpp Thu Apr 27 20:49:42 2017
@@ -16,17 +16,17 @@ InputKind FrontendOptions::getInputKindF
     .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled))
     .Case("c", InputKind::C)
     .Cases("S", "s", InputKind::Asm)
-    .Case("i", InputKind(InputKind::C, true))
-    .Case("ii", InputKind(InputKind::CXX, true))
-    .Case("cui", InputKind(InputKind::CUDA, true))
+    .Case("i", InputKind(InputKind::C).getPreprocessed())
+    .Case("ii", InputKind(InputKind::CXX).getPreprocessed())
+    .Case("cui", InputKind(InputKind::CUDA).getPreprocessed())
     .Case("m", InputKind::ObjC)
-    .Case("mi", InputKind(InputKind::ObjC, true))
+    .Case("mi", InputKind(InputKind::ObjC).getPreprocessed())
     .Cases("mm", "M", InputKind::ObjCXX)
-    .Case("mii", InputKind(InputKind::ObjCXX, true))
+    .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed())
     .Cases("C", "cc", "cp", InputKind::CXX)
     .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX)
     .Case("cppm", InputKind::CXX)
-    .Case("iim", InputKind(InputKind::CXX, true))
+    .Case("iim", InputKind(InputKind::CXX).getPreprocessed())
     .Case("cl", InputKind::OpenCL)
     .Case("cu", InputKind::CUDA)
     .Cases("ll", "bc", InputKind::LLVM_IR)

Added: cfe/trunk/test/Modules/preprocess-module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-module.cpp?rev=301610&view=auto
==============================================================================
--- cfe/trunk/test/Modules/preprocess-module.cpp (added)
+++ cfe/trunk/test/Modules/preprocess-module.cpp Thu Apr 27 20:49:42 2017
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+
+// RUN: not %clang_cc1 -fmodules -fmodule-name=file -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E 2>&1 | FileCheck %s --check-prefix=MISSING-FWD
+// MISSING-FWD: module 'fwd' is needed
+
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodules-cache-path=%t -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E | FileCheck %s
+// CHECK: # 1 "<module-includes>"
+// CHECK: # 1 "{{.*}}file.h" 1
+// CHECK: struct __FILE;
+// CHECK: #include "fwd.h" /* clang -E: implicit import for module fwd */
+// CHECK: typedef struct __FILE FILE;
+// CHECK: # 2 "<module-includes>" 2




More information about the cfe-commits mailing list