r305101 - Add #pragma clang module build/endbuild pragmas for performing a module build
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 9 12:22:32 PDT 2017
Author: rsmith
Date: Fri Jun 9 14:22:32 2017
New Revision: 305101
URL: http://llvm.org/viewvc/llvm-project?rev=305101&view=rev
Log:
Add #pragma clang module build/endbuild pragmas for performing a module build
as part of a compilation.
This is intended for two purposes:
1) Writing self-contained test cases for modules: we can now write a single
source file test that builds some number of module files on the side and
imports them.
2) Debugging / test case reduction. A single-source testcase is much more
amenable to reduction, compared to a VFS tarball or .pcm files.
Added:
cfe/trunk/test/Modules/preprocess-build.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Frontend/ASTUnit.h
cfe/trunk/include/clang/Frontend/CompilerInstance.h
cfe/trunk/include/clang/Lex/ModuleLoader.h
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Frontend/ASTUnit.cpp
cfe/trunk/lib/Frontend/CompilerInstance.cpp
cfe/trunk/lib/Lex/Pragma.cpp
cfe/trunk/unittests/Basic/SourceManagerTest.cpp
cfe/trunk/unittests/Lex/LexerTest.cpp
cfe/trunk/unittests/Lex/PPCallbacksTest.cpp
cfe/trunk/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Jun 9 14:22:32 2017
@@ -527,6 +527,10 @@ def err_pp_module_end_without_module_beg
"'#pragma clang module end'">;
def note_pp_module_begin_here : Note<
"entering module '%0' due to this pragma">;
+def err_pp_module_build_pth : Error<
+ "'#pragma clang module build' not supported in pretokenized header">;
+def err_pp_module_build_missing_end : Error<
+ "no matching '#pragma clang module endbuild' for this '#pragma clang module build'">;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
def err_paste_at_start : Error<
Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Fri Jun 9 14:22:32 2017
@@ -67,7 +67,7 @@ class FileSystem;
/// \brief Utility class for loading a ASTContext from an AST file.
///
-class ASTUnit : public ModuleLoader {
+class ASTUnit {
public:
struct StandaloneFixIt {
std::pair<unsigned, unsigned> RemoveRange;
@@ -119,10 +119,13 @@ private:
/// LoadFromCommandLine available.
std::shared_ptr<CompilerInvocation> Invocation;
+ /// Fake module loader: the AST unit doesn't need to load any modules.
+ TrivialModuleLoader ModuleLoader;
+
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.
- bool OnlyLocalDecls;
+ bool OnlyLocalDecls;
/// \brief Whether to capture any diagnostics produced.
bool CaptureDiagnostics;
@@ -496,7 +499,7 @@ public:
};
friend class ConcurrencyCheck;
- ~ASTUnit() override;
+ ~ASTUnit();
bool isMainFileAST() const { return MainFileIsAST; }
@@ -945,21 +948,6 @@ public:
///
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
-
- ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- // ASTUnit doesn't know how to load modules (not that this matters).
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override {}
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
};
} // namespace clang
Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original)
+++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Fri Jun 9 14:22:32 2017
@@ -136,6 +136,10 @@ class CompilerInstance : public ModuleLo
/// along with the module map
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
+ /// \brief The set of top-level modules that has already been built on the
+ /// fly as part of this overall compilation action.
+ std::map<std::string, std::string> BuiltModules;
+
/// \brief The location of the module-import keyword for the last module
/// import.
SourceLocation LastModuleImportLoc;
@@ -773,6 +777,9 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override;
+
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) override;
Modified: cfe/trunk/include/clang/Lex/ModuleLoader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleLoader.h?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleLoader.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleLoader.h Fri Jun 9 14:22:32 2017
@@ -109,6 +109,16 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) = 0;
+ /// Attempt to load the given module from the specified source buffer. Does
+ /// not make any submodule visible; for that, use loadModule or
+ /// makeModuleVisible.
+ ///
+ /// \param Loc The location at which the module was loaded.
+ /// \param ModuleName The name of the module to build.
+ /// \param Source The source of the module: a (preprocessed) module map.
+ virtual void loadModuleFromSource(SourceLocation Loc, StringRef ModuleName,
+ StringRef Source) = 0;
+
/// \brief Make the given module visible.
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
@@ -136,6 +146,30 @@ public:
bool HadFatalFailure;
};
+
+/// A module loader that doesn't know how to load modules.
+class TrivialModuleLoader : public ModuleLoader {
+public:
+ ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
+ return ModuleLoadResult();
+ }
+
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override {}
+
+ void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc) override {}
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override {
+ return nullptr;
+ }
+ bool lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) override {
+ return 0;
+ }
+};
}
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Jun 9 14:22:32 2017
@@ -2028,6 +2028,7 @@ public:
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
void HandlePragmaIncludeAlias(Token &Tok);
+ void HandlePragmaModuleBuild(Token &Tok);
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
// Return true and store the first token only if any CommentHandler
Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Fri Jun 9 14:22:32 2017
@@ -716,7 +716,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFr
AST->PP = std::make_shared<Preprocessor>(
AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts,
- AST->getSourceManager(), *AST->PCMCache, HeaderInfo, *AST,
+ AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader,
/*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Fri Jun 9 14:22:32 2017
@@ -667,6 +667,8 @@ void CompilerInstance::clearOutputFiles(
llvm::sys::fs::remove(OF.Filename);
}
OutputFiles.clear();
+ for (auto &Module : BuiltModules)
+ llvm::sys::fs::remove(Module.second);
NonSeekStream.reset();
}
@@ -1029,13 +1031,14 @@ static InputKind::Language getLanguageFr
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance. Returns true if the module
/// was built without errors.
-static bool compileModuleImpl(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
- ModuleMap &ModMap
- = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-
+static bool
+compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
+ StringRef ModuleName, FrontendInputFile Input,
+ StringRef OriginalModuleMapFile, StringRef ModuleFileName,
+ llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
+ [](CompilerInstance &) {},
+ llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
+ [](CompilerInstance &) {}) {
// Construct a compiler invocation for creating this module.
auto Invocation =
std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1060,7 +1063,7 @@ static bool compileModuleImpl(CompilerIn
PPOpts.Macros.end());
// Note the name of the module we're building.
- Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
+ Invocation->getLangOpts()->CurrentModule = ModuleName;
// Make sure that the failed-module structure has been allocated in
// the importing instance, and propagate the pointer to the newly-created
@@ -1080,13 +1083,10 @@ static bool compileModuleImpl(CompilerIn
FrontendOpts.DisableFree = false;
FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.BuildingImplicitModule = true;
- FrontendOpts.OriginalModuleMap =
- ModMap.getModuleMapFileForUniquing(Module)->getName();
+ FrontendOpts.OriginalModuleMap = OriginalModuleMapFile;
// Force implicitly-built modules to hash the content of the module file.
HSOpts.ModulesHashContent = true;
- FrontendOpts.Inputs.clear();
- InputKind IK(getLanguageFromOptions(*Invocation->getLangOpts()),
- InputKind::ModuleMap);
+ FrontendOpts.Inputs = {Input};
// Don't free the remapped file buffers; they are owned by our caller.
PPOpts.RetainRemappedFileBuffers = true;
@@ -1117,7 +1117,7 @@ static bool compileModuleImpl(CompilerIn
SourceManager &SourceMgr = Instance.getSourceManager();
SourceMgr.setModuleBuildStack(
ImportingInstance.getSourceManager().getModuleBuildStack());
- SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ SourceMgr.pushModuleBuildStack(ModuleName,
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
// If we're collecting module dependencies, we need to share a collector
@@ -1126,32 +1126,11 @@ static bool compileModuleImpl(CompilerIn
Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
Inv.getDependencyOutputOpts() = DependencyOutputOptions();
- // Get or create the module map that we'll use to build this module.
- std::string InferredModuleMapContent;
- if (const FileEntry *ModuleMapFile =
- ModMap.getContainingModuleMapFile(Module)) {
- // Use the module map where this module resides.
- 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, +Module->IsSystem);
-
- llvm::raw_string_ostream OS(InferredModuleMapContent);
- Module->print(OS);
- OS.flush();
-
- std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
- llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- ModuleMapFile = Instance.getFileManager().getVirtualFile(
- FakeModuleMapFile, InferredModuleMapContent.size(), 0);
- SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
- }
-
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build)
- << Module->Name << ModuleFileName;
+ << ModuleName << ModuleFileName;
+
+ PreBuildStep(Instance);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
@@ -1164,9 +1143,11 @@ static bool compileModuleImpl(CompilerIn
},
ThreadStackSize);
+ PostBuildStep(Instance);
+
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build_done)
- << Module->Name;
+ << ModuleName;
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
@@ -1174,13 +1155,66 @@ static bool compileModuleImpl(CompilerIn
// doesn't make sense for all clients, so clean this up manually.
Instance.clearOutputFiles(/*EraseFiles=*/true);
+ return !Instance.getDiagnostics().hasErrorOccurred();
+}
+
+/// \brief Compile a module file for the given module, using the options
+/// provided by the importing compiler instance. Returns true if the module
+/// was built without errors.
+static bool compileModuleImpl(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
+ InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
+ InputKind::ModuleMap);
+
+ // Get or create the module map that we'll use to build this module.
+ ModuleMap &ModMap
+ = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool Result;
+ if (const FileEntry *ModuleMapFile =
+ ModMap.getContainingModuleMapFile(Module)) {
+ // Use the module map where this module resides.
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName);
+ } else {
+ // FIXME: We only need to fake up an input file here as a way of
+ // transporting the module's directory to the module map parser. We should
+ // be able to do that more directly, and parse from a memory buffer without
+ // inventing this file.
+ SmallString<128> FakeModuleMapFile(Module->Directory->getName());
+ llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
+
+ std::string InferredModuleMapContent;
+ llvm::raw_string_ostream OS(InferredModuleMapContent);
+ Module->print(OS);
+ OS.flush();
+
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName,
+ [&](CompilerInstance &Instance) {
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ FakeModuleMapFile, InferredModuleMapContent.size(), 0);
+ Instance.getSourceManager().overrideFileContents(
+ ModuleMapFile, std::move(ModuleMapBuffer));
+ });
+ }
+
// We've rebuilt a module. If we're allowed to generate or update the global
// module index, record that fact in the importing compiler instance.
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
ImportingInstance.setBuildGlobalModuleIndex(true);
}
- return !Instance.getDiagnostics().hasErrorOccurred();
+ return Result;
}
static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
@@ -1586,24 +1620,36 @@ CompilerInstance::loadModule(SourceLocat
PP->getHeaderSearchInfo().getHeaderSearchOpts();
std::string ModuleFileName;
- bool LoadFromPrebuiltModulePath = false;
- // We try to load the module from the prebuilt module paths. If not
- // successful, we then try to find it in the module cache.
- if (!HSOpts.PrebuiltModulePaths.empty()) {
- // Load the module from the prebuilt module path.
+ enum ModuleSource {
+ ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma
+ } Source = ModuleNotFound;
+
+ // Check to see if the module has been built as part of this compilation
+ // via a module build pragma.
+ auto BuiltModuleIt = BuiltModules.find(ModuleName);
+ if (BuiltModuleIt != BuiltModules.end()) {
+ ModuleFileName = BuiltModuleIt->second;
+ Source = ModuleBuildPragma;
+ }
+
+ // Try to load the module from the prebuilt module path.
+ if (Source == ModuleNotFound && !HSOpts.PrebuiltModulePaths.empty()) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(
ModuleName, "", /*UsePrebuiltPath*/ true);
if (!ModuleFileName.empty())
- LoadFromPrebuiltModulePath = true;
+ Source = PrebuiltModulePath;
}
- if (!LoadFromPrebuiltModulePath && Module) {
- // Load the module from the module cache.
+
+ // Try to load the module from the module cache.
+ if (Source == ModuleNotFound && Module) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- } else if (!LoadFromPrebuiltModulePath) {
+ Source = ModuleCache;
+ }
+
+ if (Source == ModuleNotFound) {
// We can't find a module, error out here.
getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
ModuleBuildFailed = true;
return ModuleLoadResult();
}
@@ -1631,20 +1677,20 @@ CompilerInstance::loadModule(SourceLocat
*FrontendTimerGroup);
llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
- // Try to load the module file. If we are trying to load from the prebuilt
- // module path, we don't have the module map files and don't know how to
- // rebuild modules.
- unsigned ARRFlags = LoadFromPrebuiltModulePath ?
- ASTReader::ARR_ConfigurationMismatch :
- ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ // Try to load the module file. If we are not trying to load from the
+ // module cache, we don't know how to rebuild modules.
+ unsigned ARRFlags = Source == ModuleCache ?
+ ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing :
+ ASTReader::ARR_ConfigurationMismatch;
switch (ModuleManager->ReadAST(ModuleFileName,
- LoadFromPrebuiltModulePath ?
- serialization::MK_PrebuiltModule :
- serialization::MK_ImplicitModule,
- ImportLoc,
- ARRFlags)) {
+ Source == PrebuiltModulePath
+ ? serialization::MK_PrebuiltModule
+ : Source == ModuleBuildPragma
+ ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success: {
- if (LoadFromPrebuiltModulePath && !Module) {
+ if (Source != ModuleCache && !Module) {
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
if (!Module || !Module->getASTFile() ||
FileMgr->getFile(ModuleFileName) != Module->getASTFile()) {
@@ -1662,10 +1708,10 @@ CompilerInstance::loadModule(SourceLocat
case ASTReader::OutOfDate:
case ASTReader::Missing: {
- if (LoadFromPrebuiltModulePath) {
- // We can't rebuild the module without a module map. Since ReadAST
- // already produces diagnostics for these two cases, we simply
- // error out here.
+ if (Source != ModuleCache) {
+ // We don't know the desired configuration for this module and don't
+ // necessarily even have a module map. Since ReadAST already produces
+ // diagnostics for these two cases, we simply error out here.
ModuleBuildFailed = true;
KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
@@ -1722,7 +1768,9 @@ CompilerInstance::loadModule(SourceLocat
}
case ASTReader::ConfigurationMismatch:
- if (LoadFromPrebuiltModulePath)
+ if (Source == PrebuiltModulePath)
+ // FIXME: We shouldn't be setting HadFatalFailure below if we only
+ // produce a warning here!
getDiagnostics().Report(SourceLocation(),
diag::warn_module_config_mismatch)
<< ModuleFileName;
@@ -1751,7 +1799,7 @@ CompilerInstance::loadModule(SourceLocat
// If we never found the module, fail.
if (!Module)
return ModuleLoadResult();
-
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
if (Path.size() > 1) {
@@ -1848,6 +1896,54 @@ CompilerInstance::loadModule(SourceLocat
return LastModuleImportResult;
}
+void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
+ StringRef ModuleName,
+ StringRef Source) {
+ // FIXME: Using a randomized filename here means that our intermediate .pcm
+ // output is nondeterministic (as .pcm files refer to each other by name).
+ // Can this affect the output in any way?
+ SmallString<128> ModuleFileName;
+ if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
+ ModuleName, "pcm", ModuleFileName)) {
+ getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
+ << ModuleFileName << EC.message();
+ return;
+ }
+ std::string ModuleMapFileName = (ModuleName + ".map").str();
+
+ FrontendInputFile Input(
+ ModuleMapFileName,
+ InputKind(getLanguageFromOptions(*Invocation->getLangOpts()),
+ InputKind::ModuleMap, /*Preprocessed*/true));
+
+ std::string NullTerminatedSource(Source.str());
+
+ auto PreBuildStep = [&](CompilerInstance &Other) {
+ // Create a virtual file containing our desired source.
+ // FIXME: We shouldn't need to do this.
+ const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile(
+ ModuleMapFileName, NullTerminatedSource.size(), 0);
+ Other.getSourceManager().overrideFileContents(
+ ModuleMapFile,
+ llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str()));
+
+ Other.BuiltModules = std::move(BuiltModules);
+ };
+
+ auto PostBuildStep = [this](CompilerInstance &Other) {
+ BuiltModules = std::move(Other.BuiltModules);
+ // Make sure the child build action doesn't delete the .pcms.
+ Other.BuiltModules.clear();
+ };
+
+ // Build the module, inheriting any modules that we've built locally.
+ if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
+ ModuleFileName, PreBuildStep, PostBuildStep)) {
+ BuiltModules[ModuleName] = ModuleFileName.str();
+ llvm::sys::RemoveFileOnSignal(ModuleFileName);
+ }
+}
+
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Fri Jun 9 14:22:32 2017
@@ -754,6 +754,88 @@ void Preprocessor::HandlePragmaIncludeAl
getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
}
+void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
+ SourceLocation Loc = Tok.getLocation();
+
+ LexUnexpandedToken(Tok);
+ if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
+ Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << true;
+ return;
+ }
+ IdentifierInfo *ModuleName = Tok.getIdentifierInfo();
+
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod)) {
+ Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+ DiscardUntilEndOfDirective();
+ }
+
+ if (CurPTHLexer) {
+ // FIXME: Support this somehow?
+ Diag(Loc, diag::err_pp_module_build_pth);
+ return;
+ }
+
+ CurLexer->LexingRawMode = true;
+
+ auto TryConsumeIdentifier = [&](StringRef Ident) -> bool {
+ if (Tok.getKind() != tok::raw_identifier ||
+ Tok.getRawIdentifier() != Ident)
+ return false;
+ CurLexer->Lex(Tok);
+ return true;
+ };
+
+ // Scan forward looking for the end of the module.
+ const char *Start = CurLexer->getBufferLocation();
+ const char *End = nullptr;
+ unsigned NestingLevel = 1;
+ while (true) {
+ End = CurLexer->getBufferLocation();
+ CurLexer->Lex(Tok);
+
+ if (Tok.is(tok::eof)) {
+ Diag(Loc, diag::err_pp_module_build_missing_end);
+ break;
+ }
+
+ if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) {
+ // Token was part of module; keep going.
+ continue;
+ }
+
+ // We hit something directive-shaped; check to see if this is the end
+ // of the module build.
+ CurLexer->ParsingPreprocessorDirective = true;
+ CurLexer->Lex(Tok);
+ if (TryConsumeIdentifier("pragma") && TryConsumeIdentifier("clang") &&
+ TryConsumeIdentifier("module")) {
+ if (TryConsumeIdentifier("build"))
+ // #pragma clang module build -> entering a nested module build.
+ ++NestingLevel;
+ else if (TryConsumeIdentifier("endbuild")) {
+ // #pragma clang module endbuild -> leaving a module build.
+ if (--NestingLevel == 0)
+ break;
+ }
+ // We should either be looking at the EOD or more of the current directive
+ // preceding the EOD. Either way we can ignore this token and keep going.
+ assert(Tok.getKind() != tok::eof && "missing EOD before EOF");
+ }
+ }
+
+ CurLexer->LexingRawMode = false;
+
+ // Load the extracted text as a preprocessed module.
+ assert(CurLexer->getBuffer().begin() <= Start &&
+ Start <= CurLexer->getBuffer().end() &&
+ CurLexer->getBuffer().begin() <= End &&
+ End <= CurLexer->getBuffer().end() &&
+ "module source range not contained within same file buffer");
+ TheModuleLoader.loadModuleFromSource(Loc, ModuleName->getName(),
+ StringRef(Start, End - Start));
+}
+
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -1442,6 +1524,39 @@ struct PragmaModuleEndHandler : public P
}
};
+/// Handle the clang \#pragma module build extension.
+struct PragmaModuleBuildHandler : public PragmaHandler {
+ PragmaModuleBuildHandler() : PragmaHandler("build") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ PP.HandlePragmaModuleBuild(Tok);
+ }
+};
+
+/// Handle the clang \#pragma module load extension.
+struct PragmaModuleLoadHandler : public PragmaHandler {
+ PragmaModuleLoadHandler() : PragmaHandler("load") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation Loc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // Load the module, don't make it visible.
+ PP.getModuleLoader().loadModule(Loc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ }
+};
+
/// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the
/// macro on the top of the stack.
struct PragmaPushMacroHandler : public PragmaHandler {
@@ -1671,6 +1786,8 @@ void Preprocessor::RegisterBuiltinPragma
ModuleHandler->AddPragma(new PragmaModuleImportHandler());
ModuleHandler->AddPragma(new PragmaModuleBeginHandler());
ModuleHandler->AddPragma(new PragmaModuleEndHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBuildHandler());
+ ModuleHandler->AddPragma(new PragmaModuleLoadHandler());
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
Added: cfe/trunk/test/Modules/preprocess-build.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-build.cpp?rev=305101&view=auto
==============================================================================
--- cfe/trunk/test/Modules/preprocess-build.cpp (added)
+++ cfe/trunk/test/Modules/preprocess-build.cpp Fri Jun 9 14:22:32 2017
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++1z %s -verify
+
+#pragma clang module build baz
+ module baz {}
+#pragma clang module endbuild // baz
+
+#pragma clang module build foo
+ module foo { module bar {} }
+#pragma clang module contents
+ #pragma clang module begin foo.bar
+
+ // Can import baz here even though it was created in an outer build.
+ #pragma clang module import baz
+
+ #pragma clang module build bar
+ module bar {}
+ #pragma clang module contents
+ #pragma clang module begin bar
+ extern int n;
+ #pragma clang module end
+ #pragma clang module endbuild // bar
+
+ #pragma clang module import bar
+
+ constexpr int *f() { return &n; }
+
+ #pragma clang module end
+#pragma clang module endbuild // foo
+
+#pragma clang module import bar
+#pragma clang module import foo.bar
+static_assert(f() == &n);
+
+#pragma clang module build // expected-error {{expected module name}}
+#pragma clang module build unterminated // expected-error {{no matching '#pragma clang module endbuild'}}
Modified: cfe/trunk/unittests/Basic/SourceManagerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/SourceManagerTest.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/unittests/Basic/SourceManagerTest.cpp (original)
+++ cfe/trunk/unittests/Basic/SourceManagerTest.cpp Fri Jun 9 14:22:32 2017
@@ -51,24 +51,6 @@ protected:
IntrusiveRefCntPtr<TargetInfo> Target;
};
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
const char *source =
"#define M(x) [x]\n"
@@ -78,7 +60,7 @@ TEST_F(SourceManagerTest, isBeforeInTran
FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
SourceMgr.setMainFileID(mainFileID);
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
@@ -199,7 +181,7 @@ TEST_F(SourceManagerTest, getMacroArgExp
HeaderBuf->getBufferSize(), 0);
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
@@ -318,7 +300,7 @@ TEST_F(SourceManagerTest, isBeforeInTran
HeaderBuf->getBufferSize(), 0);
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Modified: cfe/trunk/unittests/Lex/LexerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Lex/LexerTest.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/unittests/Lex/LexerTest.cpp (original)
+++ cfe/trunk/unittests/Lex/LexerTest.cpp Fri Jun 9 14:22:32 2017
@@ -27,24 +27,6 @@ using namespace clang;
namespace {
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
// The test fixture.
class LexerTest : public ::testing::Test {
protected:
@@ -64,7 +46,7 @@ protected:
llvm::MemoryBuffer::getMemBuffer(Source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Modified: cfe/trunk/unittests/Lex/PPCallbacksTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Lex/PPCallbacksTest.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/unittests/Lex/PPCallbacksTest.cpp (original)
+++ cfe/trunk/unittests/Lex/PPCallbacksTest.cpp Fri Jun 9 14:22:32 2017
@@ -32,25 +32,6 @@ using namespace clang;
namespace {
-// Stub out module loading.
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
// Stub to collect data from InclusionDirective callbacks.
class InclusionDirectiveCallbacks : public PPCallbacks {
public:
@@ -161,7 +142,7 @@ protected:
llvm::MemoryBuffer::getMemBuffer(SourceText);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
@@ -199,7 +180,7 @@ protected:
llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, OpenCLLangOpts, Target.get());
Modified: cfe/trunk/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Lex/PPConditionalDirectiveRecordTest.cpp?rev=305101&r1=305100&r2=305101&view=diff
==============================================================================
--- cfe/trunk/unittests/Lex/PPConditionalDirectiveRecordTest.cpp (original)
+++ cfe/trunk/unittests/Lex/PPConditionalDirectiveRecordTest.cpp Fri Jun 9 14:22:32 2017
@@ -51,24 +51,6 @@ protected:
IntrusiveRefCntPtr<TargetInfo> Target;
};
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
const char *source =
"0 1\n"
@@ -93,7 +75,7 @@ TEST_F(PPConditionalDirectiveRecordTest,
llvm::MemoryBuffer::getMemBuffer(source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
More information about the cfe-commits
mailing list