diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-09-15 01:21:15 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-09-15 01:21:15 +0000 |
commit | d6509cf21dd017392f82da0eb9b0345fbfc8970b (patch) | |
tree | 2b3223d4aabe04fc1205a9e2158019bd3c87275b /clang/lib | |
parent | 66f3dc031d7922cb87b115ce8e5ca38db67aadd2 (diff) | |
download | bcm5719-llvm-d6509cf21dd017392f82da0eb9b0345fbfc8970b.tar.gz bcm5719-llvm-d6509cf21dd017392f82da0eb9b0345fbfc8970b.zip |
[modules] Frontend support for building a header module from a list of
headaer files.
llvm-svn: 342304
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Frontend/FrontendAction.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Frontend/FrontendActions.cpp | 70 | ||||
-rw-r--r-- | clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 39 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 20 |
8 files changed, 139 insertions, 29 deletions
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 38a09a0dac3..05ba3c0265a 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -911,6 +911,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // taking it as an input instead of hard-coding llvm::errs. raw_ostream &OS = llvm::errs(); + if (!Act.PrepareToExecute(*this)) + return false; + // Create the target instance. setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getInvocation().TargetOpts)); @@ -1615,22 +1618,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) { // Determine what file we're searching from. - // FIXME: Should we be deciding whether this is a submodule (here and - // below) based on -fmodules-ts or should we pass a flag and make the - // caller decide? - std::string ModuleName; - if (getLangOpts().ModulesTS) { - // FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a - // better place/way to do this. - for (auto &Piece : Path) { - if (!ModuleName.empty()) - ModuleName += "."; - ModuleName += Piece.first->getName(); - } - } - else - ModuleName = Path[0].first->getName(); - + StringRef ModuleName = Path[0].first->getName(); SourceLocation ModuleNameLoc = Path[0].second; // If we've already handled this import, just return the cached result. @@ -1859,7 +1847,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Verify that the rest of the module path actually corresponds to // a submodule. bool MapPrivateSubModToTopLevel = false; - if (!getLangOpts().ModulesTS && Path.size() > 1) { + if (Path.size() > 1) { for (unsigned I = 1, N = Path.size(); I != N; ++I) { StringRef Name = Path[I].first->getName(); clang::Module *Sub = Module->findSubmodule(Name); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b11581ddf79..55745b19633 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1454,6 +1454,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::GenerateModule; break; case OPT_emit_module_interface: Opts.ProgramAction = frontend::GenerateModuleInterface; break; + case OPT_emit_header_module: + Opts.ProgramAction = frontend::GenerateHeaderModule; break; case OPT_emit_pch: Opts.ProgramAction = frontend::GeneratePCH; break; case OPT_emit_pth: @@ -2830,6 +2832,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::FixIt: case frontend::GenerateModule: case frontend::GenerateModuleInterface: + case frontend::GenerateHeaderModule: case frontend::GeneratePCH: case frontend::GeneratePTH: case frontend::ParseSyntaxOnly: diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index ddb522ae05f..10f1d1ef611 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -523,7 +523,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCurrentInput(Input); setCompilerInstance(&CI); - StringRef InputFile = Input.getFile(); bool HasBegunSourceFile = false; bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled && usesPreprocessorOnly(); @@ -541,6 +540,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &Diags->getDiagnosticOptions())); ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false); + // FIXME: What if the input is a memory buffer? + StringRef InputFile = Input.getFile(); + std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); @@ -604,6 +606,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); + // FIXME: What if the input is a memory buffer? + StringRef InputFile = Input.getFile(); + std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); @@ -791,7 +796,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // For preprocessed files, check if the first line specifies the original // source file name with a linemarker. - std::string PresumedInputFile = InputFile; + std::string PresumedInputFile = getCurrentFileOrBufferName(); if (Input.isPreprocessed()) ReadOriginalFileName(CI, PresumedInputFile); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 40008bf3cdd..d0d83076f1d 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -242,6 +242,76 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI, return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm"); } +bool GenerateHeaderModuleAction::PrepareToExecuteAction( + CompilerInstance &CI) { + if (!CI.getLangOpts().Modules && !CI.getLangOpts().ModulesTS) { + CI.getDiagnostics().Report(diag::err_header_module_requires_modules); + return false; + } + + auto &Inputs = CI.getFrontendOpts().Inputs; + if (Inputs.empty()) + return GenerateModuleAction::BeginInvocation(CI); + + auto Kind = Inputs[0].getKind(); + + // Convert the header file inputs into a single module input buffer. + SmallString<256> HeaderContents; + ModuleHeaders.reserve(Inputs.size()); + for (const FrontendInputFile &FIF : Inputs) { + // FIXME: We should support re-compiling from an AST file. + if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) { + CI.getDiagnostics().Report(diag::err_module_header_file_not_found) + << (FIF.isFile() ? FIF.getFile() + : FIF.getBuffer()->getBufferIdentifier()); + return true; + } + + HeaderContents += "#include \""; + HeaderContents += FIF.getFile(); + HeaderContents += "\"\n"; + ModuleHeaders.push_back(FIF.getFile()); + } + Buffer = llvm::MemoryBuffer::getMemBufferCopy( + HeaderContents, Module::getModuleInputBufferName()); + + // Set that buffer up as our "real" input. + Inputs.clear(); + Inputs.push_back(FrontendInputFile(Buffer.get(), Kind, /*IsSystem*/false)); + + return GenerateModuleAction::PrepareToExecuteAction(CI); +} + +bool GenerateHeaderModuleAction::BeginSourceFileAction( + CompilerInstance &CI) { + CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule); + + // Synthesize a Module object for the given headers. + auto &HS = CI.getPreprocessor().getHeaderSearchInfo(); + SmallVector<Module::Header, 16> Headers; + for (StringRef Name : ModuleHeaders) { + const DirectoryLookup *CurDir = nullptr; + const FileEntry *FE = HS.LookupFile( + Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, + None, nullptr, nullptr, nullptr, nullptr, nullptr); + if (!FE) { + CI.getDiagnostics().Report(diag::err_module_header_file_not_found) + << Name; + continue; + } + Headers.push_back({Name, FE}); + } + HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers); + + return GenerateModuleAction::BeginSourceFileAction(CI); +} + +std::unique_ptr<raw_pwrite_stream> +GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI, + StringRef InFile) { + return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm"); +} + SyntaxOnlyAction::~SyntaxOnlyAction() { } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 747fdd24164..4deebcd4777 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -61,6 +61,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { return llvm::make_unique<GenerateModuleFromModuleMapAction>(); case GenerateModuleInterface: return llvm::make_unique<GenerateModuleInterfaceAction>(); + case GenerateHeaderModule: + return llvm::make_unique<GenerateHeaderModuleAction>(); case GeneratePCH: return llvm::make_unique<GeneratePCHAction>(); case GeneratePTH: return llvm::make_unique<GeneratePTHAction>(); case InitOnly: return llvm::make_unique<InitOnlyAction>(); diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index a1e91382175..b6a6e26d6ad 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -806,12 +806,11 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name, } Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) { - assert(!PendingGlobalModule && "created multiple global modules"); - PendingGlobalModule.reset( + PendingSubmodules.emplace_back( new Module("<global>", Loc, nullptr, /*IsFramework*/ false, /*IsExplicit*/ true, NumCreatedModules++)); - PendingGlobalModule->Kind = Module::GlobalModuleFragment; - return PendingGlobalModule.get(); + PendingSubmodules.back()->Kind = Module::GlobalModuleFragment; + return PendingSubmodules.back().get(); } Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, @@ -827,10 +826,11 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, Modules[Name] = SourceModule = Result; // Reparent the current global module fragment as a submodule of this module. - assert(GlobalModule == PendingGlobalModule.get() && - "unexpected global module"); - GlobalModule->setParent(Result); - PendingGlobalModule.release(); // now owned by parent + for (auto &Submodule : PendingSubmodules) { + Submodule->setParent(Result); + Submodule.release(); // now owned by parent + } + PendingSubmodules.clear(); // Mark the main source file as being within the newly-created module so that // declarations and macros are properly visibility-restricted to it. @@ -841,6 +841,29 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, return Result; } +Module *ModuleMap::createHeaderModule(StringRef Name, + ArrayRef<Module::Header> Headers) { + assert(LangOpts.CurrentModule == Name && "module name mismatch"); + assert(!Modules[Name] && "redefining existing module"); + + auto *Result = + new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false, + /*IsExplicit*/ false, NumCreatedModules++); + Result->Kind = Module::ModuleInterfaceUnit; + Modules[Name] = SourceModule = Result; + + for (const Module::Header &H : Headers) { + auto *M = new Module(H.NameAsWritten, SourceLocation(), Result, + /*IsFramework*/ false, + /*IsExplicit*/ true, NumCreatedModules++); + // Header modules are implicitly 'export *'. + M->Exports.push_back(Module::ExportDecl(nullptr, true)); + addHeader(M, H, NormalHeader); + } + + return Result; +} + /// For a framework module, infer the framework against which we /// should link. static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 82a04e1070d..4b0e69c7f65 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -977,7 +977,8 @@ void Sema::ActOnEndOfTranslationUnit() { // module declaration by now. if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface && - ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) { + (ModuleScopes.empty() || + ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) { // FIXME: Make a better guess as to where to put the module declaration. Diag(getSourceManager().getLocForStartOfFile( getSourceManager().getMainFileID()), diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f1e9286b7ec..eacf713b9d0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16832,6 +16832,10 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, case LangOptions::CMK_ModuleMap: Diag(ModuleLoc, diag::err_module_decl_in_module_map_module); return nullptr; + + case LangOptions::CMK_HeaderModule: + Diag(ModuleLoc, diag::err_module_decl_in_header_module); + return nullptr; } assert(ModuleScopes.size() == 1 && "expected to be at global module scope"); @@ -16900,7 +16904,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, case ModuleDeclKind::Implementation: std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( PP.getIdentifierInfo(ModuleName), Path[0].second); - Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible, + Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, + Module::AllVisible, /*IsIncludeDirective=*/false); if (!Mod) { Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; @@ -16930,6 +16935,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ImportLoc, ModuleIdPath Path) { + // Flatten the module path for a Modules TS module name. + std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc; + if (getLangOpts().ModulesTS) { + std::string ModuleName; + for (auto &Piece : Path) { + if (!ModuleName.empty()) + ModuleName += "."; + ModuleName += Piece.first->getName(); + } + ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; + Path = ModuleIdPath(ModuleNameLoc); + } + Module *Mod = getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); |