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