diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp | 532 |
1 files changed, 488 insertions, 44 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 39fc137..704d5150 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -19,6 +19,7 @@ #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/ParseAST.h" @@ -135,6 +136,12 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput, CurrentASTUnit = std::move(AST); } +Module *FrontendAction::getCurrentModule() const { + CompilerInstance &CI = getCompilerInstance(); + return CI.getPreprocessor().getHeaderSearchInfo().lookupModule( + CI.getLangOpts().CurrentModule, /*AllowSearch*/false); +} + std::unique_ptr<ASTConsumer> FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, StringRef InFile) { @@ -187,8 +194,324 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } +/// For preprocessed files, if the first line is the linemarker and specifies +/// the original source file name, use that name as the input file name. +/// Returns the location of the first token after the line marker directive. +/// +/// \param CI The compiler instance. +/// \param InputFile Populated with the filename from the line marker. +/// \param IsModuleMap If \c true, add a line note corresponding to this line +/// directive. (We need to do this because the directive will not be +/// visited by the preprocessor.) +static SourceLocation ReadOriginalFileName(CompilerInstance &CI, + std::string &InputFile, + bool IsModuleMap = false) { + auto &SourceMgr = CI.getSourceManager(); + auto MainFileID = SourceMgr.getMainFileID(); + + bool Invalid = false; + const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); + if (Invalid) + return SourceLocation(); + + std::unique_ptr<Lexer> RawLexer( + new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); + + // If the first line has the syntax of + // + // # NUM "FILENAME" + // + // we use FILENAME as the input file name. + Token T; + if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash) + return SourceLocation(); + if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() || + T.getKind() != tok::numeric_constant) + return SourceLocation(); + + unsigned LineNo; + SourceLocation LineNoLoc = T.getLocation(); + if (IsModuleMap) { + llvm::SmallString<16> Buffer; + if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts()) + .getAsInteger(10, LineNo)) + return SourceLocation(); + } + + RawLexer->LexFromRawLexer(T); + if (T.isAtStartOfLine() || T.getKind() != tok::string_literal) + return SourceLocation(); + + StringLiteralParser Literal(T, CI.getPreprocessor()); + if (Literal.hadError) + return SourceLocation(); + RawLexer->LexFromRawLexer(T); + if (T.isNot(tok::eof) && !T.isAtStartOfLine()) + return SourceLocation(); + InputFile = Literal.GetString().str(); + + if (IsModuleMap) + CI.getSourceManager().AddLineNote( + LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false, + false, SrcMgr::C_User_ModuleMap); + + return T.getLocation(); +} + +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, DiagnosticsEngine &Diag, + ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) { + // Don't collect any headers for unavailable modules. + if (!Module->isAvailable()) + return std::error_code(); + + // Resolve all lazy header directives to header files. + ModMap.resolveHeaderDirectives(Module); + + // If any headers are missing, we can't build this module. In most cases, + // diagnostics for this should have already been produced; we only get here + // if explicit stat information was provided. + // FIXME: If the name resolves to a file with different stat information, + // produce a better diagnostic. + if (!Module->MissingHeaders.empty()) { + auto &MissingHeader = Module->MissingHeaders.front(); + Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + 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, Diag, ModMap, *Sub, Includes)) + return Err; + + return std::error_code(); +} + +static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, + bool IsPreprocessed, + std::string &PresumedModuleMapFile, + unsigned &Offset) { + auto &SrcMgr = CI.getSourceManager(); + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + + // Map the current input to a file. + FileID ModuleMapID = SrcMgr.getMainFileID(); + const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID); + + // If the module map is preprocessed, handle the initial line marker; + // line directives are not part of the module map syntax in general. + Offset = 0; + if (IsPreprocessed) { + SourceLocation EndOfLineMarker = + ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true); + if (EndOfLineMarker.isValid()) + Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; + } + + // Load the module map file. + if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset, + PresumedModuleMapFile)) + return true; + + if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset) + Offset = 0; + + return false; +} + +static Module *prepareToBuildModule(CompilerInstance &CI, + StringRef ModuleMapFilename) { + 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; + } + + // Dig out the module definition. + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, + /*AllowSearch=*/false); + if (!M) { + CI.getDiagnostics().Report(diag::err_missing_module) + << CI.getLangOpts().CurrentModule << ModuleMapFilename; + + return nullptr; + } + + // Check whether we can build this module at all. + if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(), + CI.getDiagnostics(), M)) + 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); + + // If the module was inferred from a different module map (via an expanded + // umbrella module definition), track that fact. + // FIXME: It would be preferable to fill this in as part of processing + // the module map, rather than adding it after the fact. + StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; + if (!OriginalModuleMapName.empty()) { + auto *OriginalModuleMap = + CI.getFileManager().getFile(OriginalModuleMapName, + /*openFile*/ true); + if (!OriginalModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << OriginalModuleMapName; + return nullptr; + } + if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID( + CI.getSourceManager().getMainFileID())) { + M->IsInferred = true; + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMap); + } + } + + // 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)); + return M; +} + +/// Compute the input buffer that should be used to build the specified module. +static std::unique_ptr<llvm::MemoryBuffer> +getInputBufferForModule(CompilerInstance &CI, Module *M) { + 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.getDiagnostics(), + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M, + HeaderContents); + + if (Err) { + CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) + << M->getFullModuleName() << Err.message(); + return nullptr; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + HeaderContents, Module::getModuleInputBufferName()); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, - const FrontendInputFile &Input) { + const FrontendInputFile &RealInput) { + FrontendInputFile Input(RealInput); assert(!Instance && "Already processing a source file!"); assert(!Input.isEmpty() && "Unexpected empty filename!"); setCurrentInput(Input); @@ -196,22 +519,88 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, StringRef InputFile = Input.getFile(); bool HasBegunSourceFile = false; + bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled && + usesPreprocessorOnly(); if (!BeginInvocation(CI)) goto failure; + // If we're replaying the build of an AST file, import it and set up + // the initial state from its build. + if (ReplayASTFile) { + IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); + + // The AST unit populates its own diagnostics engine rather than ours. + IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags( + new DiagnosticsEngine(Diags->getDiagnosticIDs(), + &Diags->getDiagnosticOptions())); + ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false); + + std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, + ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); + if (!AST) + goto failure; + + // Options relating to how we treat the input (but not what we do with it) + // are inherited from the AST unit. + CI.getHeaderSearchOpts() = AST->getHeaderSearchOpts(); + CI.getPreprocessorOpts() = AST->getPreprocessorOpts(); + CI.getLangOpts() = AST->getLangOpts(); + + // Set the shared objects, these are reset when we finish processing the + // file, otherwise the CompilerInstance will happily destroy them. + CI.setFileManager(&AST->getFileManager()); + CI.createSourceManager(CI.getFileManager()); + CI.getSourceManager().initializeForReplay(AST->getSourceManager()); + + // Preload all the module files loaded transitively by the AST unit. Also + // load all module map files that were parsed as part of building the AST + // unit. + if (auto ASTReader = AST->getASTReader()) { + auto &MM = ASTReader->getModuleManager(); + auto &PrimaryModule = MM.getPrimaryModule(); + + for (ModuleFile &MF : MM) + if (&MF != &PrimaryModule) + CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); + + ASTReader->visitTopLevelModuleMaps(PrimaryModule, + [&](const FileEntry *FE) { + CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName()); + }); + } + + // Set up the input file for replay purposes. + auto Kind = AST->getInputKind(); + if (Kind.getFormat() == InputKind::ModuleMap) { + Module *ASTModule = + AST->getPreprocessor().getHeaderSearchInfo().lookupModule( + AST->getLangOpts().CurrentModule, /*AllowSearch*/ false); + assert(ASTModule && "module file does not define its own module"); + Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind); + } else { + auto &SM = CI.getSourceManager(); + FileID ID = SM.getMainFileID(); + if (auto *File = SM.getFileEntryForID(ID)) + Input = FrontendInputFile(File->getName(), Kind); + else + Input = FrontendInputFile(SM.getBuffer(ID), Kind); + } + setCurrentInput(Input, std::move(AST)); + } + // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.getKind() == IK_AST) { - assert(!usesPreprocessorOnly() && - "Attempt to pass AST file to preprocessor only action!"); + if (Input.getKind().getFormat() == InputKind::Precompiled) { + assert(!usesPreprocessorOnly() && "this case was handled above"); assert(hasASTFileSupport() && "This action does not have AST file support!"); IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( - InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(), - CI.getCodeGenOpts().DebugTypeExtRefs); + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, + CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) goto failure; @@ -225,12 +614,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setFileManager(&AST->getFileManager()); CI.setSourceManager(&AST->getSourceManager()); CI.setPreprocessor(AST->getPreprocessorPtr()); + Preprocessor &PP = CI.getPreprocessor(); + PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), + PP.getLangOpts()); CI.setASTContext(&AST->getASTContext()); setCurrentInput(Input, std::move(AST)); // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + if (!BeginSourceFileAction(CI)) goto failure; // Create the AST consumer. @@ -256,8 +648,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 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() == IK_LLVM_IR) { + if (Input.getKind().getLanguage() == InputKind::LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -266,7 +669,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + if (!BeginSourceFileAction(CI)) goto failure; // Initialize the main file entry. @@ -319,13 +722,47 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; - // Initialize the action. - if (!BeginSourceFileAction(CI, InputFile)) + // Initialize the main file entry. + if (!CI.InitializeSourceManager(Input)) 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)) + // 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); + + std::string PresumedModuleMapFile; + unsigned OffsetToContents; + if (loadModuleMapForModuleBuild(CI, Input.isSystem(), + Input.isPreprocessed(), + PresumedModuleMapFile, OffsetToContents)) + goto failure; + + auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); + if (!CurrentModule) + goto failure; + + CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile; + + if (OffsetToContents) + // If the module contents are in the same file, skip to them. + CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true); + else { + // Otherwise, convert the module description to a suitable input buffer. + auto Buffer = getInputBufferForModule(CI, CurrentModule); + if (!Buffer) + goto failure; + + // Reinitialize the main file entry to refer to the new input. + if (!CI.InitializeSourceManager(FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem))) + goto failure; + } + } + + // Initialize the action. + if (!BeginSourceFileAction(CI)) goto failure; // Create the AST context and consumer unless this is a preprocessor only @@ -335,8 +772,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!isModelParsingAction()) CI.createASTContext(); + // For preprocessed files, check if the first line specifies the original + // source file name with a linemarker. + std::string PresumedInputFile = InputFile; + if (Input.isPreprocessed()) + ReadOriginalFileName(CI, PresumedInputFile); + std::unique_ptr<ASTConsumer> Consumer = - CreateWrappedASTConsumer(CI, InputFile); + CreateWrappedASTConsumer(CI, PresumedInputFile); if (!Consumer) goto failure; @@ -352,8 +795,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get())); CI.getASTContext().setExternalSource(source); - } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { - // Use PCH. + } else if (CI.getLangOpts().Modules || + !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + // Use PCM or PCH. assert(hasPCHSupport() && "This action does not have PCH support!"); ASTDeserializationListener *DeserialListener = Consumer->GetASTDeserializationListener(); @@ -370,13 +814,24 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, DeserialListener, DeleteDeserialListener); DeleteDeserialListener = true; } - CI.createPCHExternalASTSource( - CI.getPreprocessorOpts().ImplicitPCHInclude, - CI.getPreprocessorOpts().DisablePCHValidation, + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + CI.createPCHExternalASTSource( + CI.getPreprocessorOpts().ImplicitPCHInclude, + CI.getPreprocessorOpts().DisablePCHValidation, CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener, - DeleteDeserialListener); - if (!CI.getASTContext().getExternalSource()) - goto failure; + DeleteDeserialListener); + if (!CI.getASTContext().getExternalSource()) + goto failure; + } + // If modules are enabled, create the module manager before creating + // any builtins, so that all declarations know that they might be + // extended by an external source. + if (CI.getLangOpts().Modules || !CI.hasASTContext() || + !CI.getASTContext().getExternalSource()) { + CI.createModuleManager(); + CI.getModuleManager()->setDeserializationListener(DeserialListener, + DeleteDeserialListener); + } } CI.setASTConsumer(std::move(Consumer)); @@ -386,15 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize built-in info as long as we aren't using an external AST // source. - if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { + if (CI.getLangOpts().Modules || !CI.hasASTContext() || + !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); - - // If modules are enabled, create the module manager before creating - // any builtins, so that all declarations know that they might be - // extended by an external source. - if (CI.getLangOpts().Modules) - CI.createModuleManager(); - PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), PP.getLangOpts()); } else { @@ -421,9 +870,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. - if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && + if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { - IntrusiveRefCntPtr<ExternalASTSource> + IntrusiveRefCntPtr<ExternalASTSource> Override(new LayoutOverrideSource( CI.getFrontendOpts().OverrideRecordLayoutsFile)); CI.getASTContext().setExternalSource(Override); @@ -433,17 +882,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If we failed, reset state since the client will not end up calling the // matching EndSourceFile(). - failure: - if (isCurrentFileAST()) { - CI.setASTContext(nullptr); - CI.setPreprocessor(nullptr); - CI.setSourceManager(nullptr); - CI.setFileManager(nullptr); - } - +failure: if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); CI.clearOutputFiles(/*EraseFiles=*/true); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); setCurrentInput(FrontendInputFile()); setCompilerInstance(nullptr); return false; @@ -517,6 +960,7 @@ void FrontendAction::EndSourceFile() { CI.resetAndLeakPreprocessor(); CI.resetAndLeakSourceManager(); CI.resetAndLeakFileManager(); + BuryPointer(CurrentASTUnit.release()); } else { CI.setPreprocessor(nullptr); CI.setSourceManager(nullptr); @@ -526,6 +970,7 @@ void FrontendAction::EndSourceFile() { setCompilerInstance(nullptr); setCurrentInput(FrontendInputFile()); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); } bool FrontendAction::shouldEraseOutputFiles() { @@ -575,11 +1020,10 @@ WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { return WrappedAction->BeginInvocation(CI); } -bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { +bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) { WrappedAction->setCurrentInput(getCurrentInput()); WrappedAction->setCompilerInstance(&CI); - auto Ret = WrappedAction->BeginSourceFileAction(CI, Filename); + auto Ret = WrappedAction->BeginSourceFileAction(CI); // BeginSourceFileAction may change CurrentInput, e.g. during module builds. setCurrentInput(WrappedAction->getCurrentInput()); return Ret; |