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

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 27 21:44:11 PDT 2017


On Thu, Apr 27, 2017 at 6:49 PM, Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> 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.)

Yay! This is awesome Richard!!

> 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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits



-- 
Bruno Cardoso Lopes
http://www.brunocardoso.cc


More information about the cfe-commits mailing list