diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp | 695 |
1 files changed, 446 insertions, 249 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index eccb94c..6af920d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" #include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" @@ -31,9 +32,10 @@ #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Sema.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/GlobalModuleIndex.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Config/config.h" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/LockFileManager.h" @@ -43,15 +45,17 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <sys/stat.h> +#include <system_error> #include <time.h> using namespace clang; -CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()), ModuleManager(0), - BuildGlobalModuleIndex(false), ModuleBuildFailed(false) { +CompilerInstance::CompilerInstance(bool BuildingModule) + : ModuleLoader(BuildingModule), + Invocation(new CompilerInvocation()), ModuleManager(nullptr), + BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false), + ModuleBuildFailed(false) { } CompilerInstance::~CompilerInstance() { @@ -79,6 +83,10 @@ void CompilerInstance::setTarget(TargetInfo *Value) { void CompilerInstance::setFileManager(FileManager *Value) { FileMgr = Value; + if (Value) + VirtualFileSystem = Value->getVirtualFileSystem(); + else + VirtualFileSystem.reset(); } void CompilerInstance::setSourceManager(SourceManager *Value) { @@ -100,6 +108,23 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) { void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { CompletionConsumer.reset(Value); } + +IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const { + return ModuleManager; +} +void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) { + ModuleManager = Reader; +} + +std::shared_ptr<ModuleDependencyCollector> +CompilerInstance::getModuleDepCollector() const { + return ModuleDepCollector; +} + +void CompilerInstance::setModuleDepCollector( + std::shared_ptr<ModuleDependencyCollector> Collector) { + ModuleDepCollector = Collector; +} // Diagnostics static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, @@ -110,9 +135,9 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, raw_ostream *OS = &llvm::errs(); if (DiagOpts->DiagnosticLogFile != "-") { // Create the output stream. - llvm::raw_fd_ostream *FileOS( - new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo, - llvm::sys::fs::F_Append)); + llvm::raw_fd_ostream *FileOS(new llvm::raw_fd_ostream( + DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo, + llvm::sys::fs::F_Append | llvm::sys::fs::F_Text)); if (!ErrorInfo.empty()) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) << DiagOpts->DiagnosticLogFile << ErrorInfo; @@ -136,20 +161,19 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, DiagnosticsEngine &Diags, StringRef OutputFile) { std::string ErrorInfo; - OwningPtr<llvm::raw_fd_ostream> OS; + std::unique_ptr<llvm::raw_fd_ostream> OS; OS.reset(new llvm::raw_fd_ostream(OutputFile.str().c_str(), ErrorInfo, - llvm::sys::fs::F_Binary)); + llvm::sys::fs::F_None)); if (!ErrorInfo.empty()) { Diags.Report(diag::warn_fe_serialized_diag_failure) << OutputFile << ErrorInfo; return; } - + DiagnosticConsumer *SerializedConsumer = - clang::serialized_diags::create(OS.take(), DiagOpts); + clang::serialized_diags::create(OS.release(), DiagOpts); - Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), SerializedConsumer)); } @@ -197,7 +221,11 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, // File Manager void CompilerInstance::createFileManager() { - FileMgr = new FileManager(getFileSystemOpts()); + if (!hasVirtualFileSystem()) { + // TODO: choose the virtual file system based on the CompilerInvocation. + setVirtualFileSystem(vfs::getRealFileSystem()); + } + FileMgr = new FileManager(getFileSystemOpts(), VirtualFileSystem); } // Source Manager @@ -206,13 +234,63 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) { SourceMgr = new SourceManager(getDiagnostics(), FileMgr); } +// Initialize the remapping of files to alternative contents, e.g., +// those specified through other files. +static void InitializeFileRemapping(DiagnosticsEngine &Diags, + SourceManager &SourceMgr, + FileManager &FileMgr, + const PreprocessorOptions &InitOpts) { + // Remap files in the source manager (with buffers). + for (const auto &RB : InitOpts.RemappedFileBuffers) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = + FileMgr.getVirtualFile(RB.first, RB.second->getBufferSize(), 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) << RB.first; + if (!InitOpts.RetainRemappedFileBuffers) + delete RB.second; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, RB.second, + InitOpts.RetainRemappedFileBuffers); + } + + // Remap files in the source manager (with other files). + for (const auto &RF : InitOpts.RemappedFiles) { + // Find the file that we're mapping to. + const FileEntry *ToFile = FileMgr.getFile(RF.second); + if (!ToFile) { + Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = + FileMgr.getVirtualFile(RF.first, ToFile->getSize(), 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) << RF.first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, ToFile); + } + + SourceMgr.setOverridenFilesKeepOriginalName( + InitOpts.RemappedFilesKeepOriginalName); +} + // Preprocessor -void CompilerInstance::createPreprocessor() { +void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { const PreprocessorOptions &PPOpts = getPreprocessorOpts(); // Create a PTH manager if we are using some form of a token cache. - PTHManager *PTHMgr = 0; + PTHManager *PTHMgr = nullptr; if (!PPOpts.TokenCache.empty()) PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); @@ -222,10 +300,10 @@ void CompilerInstance::createPreprocessor() { getDiagnostics(), getLangOpts(), &getTarget()); - PP = new Preprocessor(&getPreprocessorOpts(), - getDiagnostics(), getLangOpts(), &getTarget(), + PP = new Preprocessor(&getPreprocessorOpts(), getDiagnostics(), getLangOpts(), getSourceManager(), *HeaderInfo, *this, PTHMgr, - /*OwnsHeaderSearch=*/true); + /*OwnsHeaderSearch=*/true, TUKind); + PP->Initialize(getTarget()); // Note that this is different then passing PTHMgr to Preprocessor's ctor. // That argument is used as the IdentifierInfoLookup argument to @@ -238,7 +316,16 @@ void CompilerInstance::createPreprocessor() { if (PPOpts.DetailedRecord) PP->createPreprocessingRecord(); - InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts()); + // Apply remappings to the source manager. + InitializeFileRemapping(PP->getDiagnostics(), PP->getSourceManager(), + PP->getFileManager(), PPOpts); + + // Predefine macros and configure the preprocessor. + InitializePreprocessor(*PP, PPOpts, getFrontendOpts()); + + // Initialize the header search object. + ApplyHeaderSearchOptions(PP->getHeaderSearchInfo(), getHeaderSearchOpts(), + PP->getLangOpts(), PP->getTargetInfo().getTriple()); PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP); @@ -254,11 +341,20 @@ void CompilerInstance::createPreprocessor() { // Handle generating dependencies, if requested. const DependencyOutputOptions &DepOpts = getDependencyOutputOpts(); if (!DepOpts.OutputFile.empty()) - AttachDependencyFileGen(*PP, DepOpts); + TheDependencyFileGenerator.reset( + DependencyFileGenerator::CreateAndAttachToPreprocessor(*PP, DepOpts)); if (!DepOpts.DOTOutputFile.empty()) AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile, getHeaderSearchOpts().Sysroot); + for (auto &Listener : DependencyCollectors) + Listener->attachToPreprocessor(*PP); + + // If we don't have a collector, but we are collecting module dependencies, + // then we're the top level compiler instance and need to create one. + if (!ModuleDepCollector && !DepOpts.ModuleDependencyOutputDir.empty()) + ModuleDepCollector = std::make_shared<ModuleDependencyCollector>( + DepOpts.ModuleDependencyOutputDir); // Handle generating header include information, if requested. if (DepOpts.ShowHeaderIncludes) @@ -282,49 +378,46 @@ void CompilerInstance::createPreprocessor() { void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); Context = new ASTContext(getLangOpts(), PP.getSourceManager(), - &getTarget(), PP.getIdentifierTable(), - PP.getSelectorTable(), PP.getBuiltinInfo(), - /*size_reserve=*/ 0); + PP.getIdentifierTable(), PP.getSelectorTable(), + PP.getBuiltinInfo()); + Context->InitBuiltinTypes(getTarget()); } // ExternalASTSource -void CompilerInstance::createPCHExternalASTSource(StringRef Path, - bool DisablePCHValidation, - bool AllowPCHWithCompilerErrors, - void *DeserializationListener){ - OwningPtr<ExternalASTSource> Source; +void CompilerInstance::createPCHExternalASTSource( + StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, + void *DeserializationListener, bool OwnDeserializationListener) { + IntrusiveRefCntPtr<ExternalASTSource> Source; bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; - Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, - DisablePCHValidation, - AllowPCHWithCompilerErrors, - getPreprocessor(), getASTContext(), - DeserializationListener, - Preamble, - getFrontendOpts().UseGlobalModuleIndex)); + Source = createPCHExternalASTSource( + Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, + AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), + DeserializationListener, OwnDeserializationListener, Preamble, + getFrontendOpts().UseGlobalModuleIndex); ModuleManager = static_cast<ASTReader*>(Source.get()); getASTContext().setExternalSource(Source); } -ExternalASTSource * -CompilerInstance::createPCHExternalASTSource(StringRef Path, - const std::string &Sysroot, - bool DisablePCHValidation, - bool AllowPCHWithCompilerErrors, - Preprocessor &PP, - ASTContext &Context, - void *DeserializationListener, - bool Preamble, - bool UseGlobalModuleIndex) { - OwningPtr<ASTReader> Reader; +ExternalASTSource *CompilerInstance::createPCHExternalASTSource( + StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, + void *DeserializationListener, bool OwnDeserializationListener, + bool Preamble, bool UseGlobalModuleIndex) { + HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + + std::unique_ptr<ASTReader> Reader; Reader.reset(new ASTReader(PP, Context, Sysroot.empty() ? "" : Sysroot.c_str(), DisablePCHValidation, AllowPCHWithCompilerErrors, + /*AllowConfigurationMismatch*/false, + HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); Reader->setDeserializationListener( - static_cast<ASTDeserializationListener *>(DeserializationListener)); + static_cast<ASTDeserializationListener *>(DeserializationListener), + /*TakeOwnership=*/OwnDeserializationListener); switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, @@ -334,7 +427,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); - return Reader.take(); + return Reader.release(); case ASTReader::Failure: // Unrecoverable failure: don't even try to process the input file. @@ -349,7 +442,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, break; } - return 0; + return nullptr; } // Code Completion @@ -384,14 +477,14 @@ void CompilerInstance::createCodeCompletionConsumer() { return; } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column)) { - setCodeCompletionConsumer(0); + setCodeCompletionConsumer(nullptr); return; } if (CompletionConsumer->isOutputBinary() && llvm::sys::ChangeStdoutToBinary()) { getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); - setCodeCompletionConsumer(0); + setCodeCompletionConsumer(nullptr); } } @@ -407,7 +500,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, const CodeCompleteOptions &Opts, raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) - return 0; + return nullptr; // Set up the creation routine for code-completion. return new PrintingCodeCompleteConsumer(Opts, OS); @@ -432,21 +525,19 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { delete it->OS; if (!it->TempFilename.empty()) { if (EraseFiles) { - bool existed; - llvm::sys::fs::remove(it->TempFilename, existed); + llvm::sys::fs::remove(it->TempFilename); } else { SmallString<128> NewOutFile(it->Filename); // If '-working-directory' was passed, the output filename should be // relative to that. FileMgr->FixupRelativePath(NewOutFile); - if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename, - NewOutFile.str())) { + if (std::error_code ec = + llvm::sys::fs::rename(it->TempFilename, NewOutFile.str())) { getDiagnostics().Report(diag::err_unable_to_rename_temp) << it->TempFilename << it->Filename << ec.message(); - bool existed; - llvm::sys::fs::remove(it->TempFilename, existed); + llvm::sys::fs::remove(it->TempFilename); } } } else if (!it->Filename.empty() && EraseFiles) @@ -465,6 +556,12 @@ CompilerInstance::createDefaultOutputFile(bool Binary, /*UseTemporary=*/true); } +llvm::raw_null_ostream *CompilerInstance::createNullOutputFile() { + llvm::raw_null_ostream *OS = new llvm::raw_null_ostream(); + addOutputFile(OutputFile("", "", OS)); + return OS; +} + llvm::raw_fd_ostream * CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, @@ -483,7 +580,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath, if (!OS) { getDiagnostics().Report(diag::err_fe_unable_to_open_output) << OutputPath << Error; - return 0; + return nullptr; } // Add the output file -- but don't try to remove "-", since this means we are @@ -521,7 +618,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath, OutFile = "-"; } - OwningPtr<llvm::raw_fd_ostream> OS; + std::unique_ptr<llvm::raw_fd_ostream> OS; std::string OSFile; if (UseTemporary) { @@ -533,7 +630,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath, if (llvm::sys::fs::exists(Status)) { // Fail early if we can't write to the final destination. if (!llvm::sys::fs::can_write(OutputPath)) - return 0; + return nullptr; // Don't use a temporary if the output is a special file. This handles // things like '-o /dev/null' @@ -549,7 +646,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath, TempPath = OutFile; TempPath += "-%%%%%%%%"; int fd; - llvm::error_code EC = + std::error_code EC = llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath); if (CreateMissingDirectories && @@ -574,9 +671,9 @@ CompilerInstance::createOutputFile(StringRef OutputPath, OSFile = OutFile; OS.reset(new llvm::raw_fd_ostream( OSFile.c_str(), Error, - (Binary ? llvm::sys::fs::F_Binary : llvm::sys::fs::F_None))); + (Binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text))); if (!Error.empty()) - return 0; + return nullptr; } // Make sure the out stream file gets removed if we crash. @@ -588,7 +685,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath, if (TempPathName) *TempPathName = TempFile; - return OS.take(); + return OS.release(); } // Initialization Utilities @@ -608,7 +705,7 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { - SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind); + SourceMgr.setMainFileID(SourceMgr.createFileID(Input.getBuffer(), Kind)); assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; @@ -642,17 +739,22 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, } } - SourceMgr.createMainFileID(File, Kind); + SourceMgr.setMainFileID( + SourceMgr.createFileID(File, SourceLocation(), Kind)); } else { - OwningPtr<llvm::MemoryBuffer> SB; - if (llvm::error_code ec = llvm::MemoryBuffer::getSTDIN(SB)) { - Diags.Report(diag::err_fe_error_reading_stdin) << ec.message(); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr = + llvm::MemoryBuffer::getSTDIN(); + if (std::error_code EC = SBOrErr.getError()) { + Diags.Report(diag::err_fe_error_reading_stdin) << EC.message(); return false; } + std::unique_ptr<llvm::MemoryBuffer> SB = std::move(SBOrErr.get()); + const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); - SourceMgr.createMainFileID(File, Kind); - SourceMgr.overrideFileContents(File, SB.take()); + SourceMgr.setMainFileID( + SourceMgr.createFileID(File, SourceLocation(), Kind)); + SourceMgr.overrideFileContents(File, SB.release()); } assert(!SourceMgr.getMainFileID().isInvalid() && @@ -672,7 +774,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { raw_ostream &OS = llvm::errs(); // Create the target instance. - setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), &getTargetOpts())); + setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), + getInvocation().TargetOpts)); if (!hasTarget()) return false; @@ -680,7 +783,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - getTarget().setForcedLangOptions(getLangOpts()); + getTarget().adjust(getLangOpts()); // rewriter project will change target built-in bool type from its default. if (getFrontendOpts().ProgramAction == frontend::RewriteObjC) @@ -689,7 +792,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // Validate/process some options. if (getHeaderSearchOpts().Verbose) OS << "clang -cc1 version " CLANG_VERSION_STRING - << " based upon " << PACKAGE_STRING + << " based upon " << BACKEND_PACKAGE_STRING << " default target " << llvm::sys::getDefaultTargetTriple() << "\n"; if (getFrontendOpts().ShowTimers) @@ -748,65 +851,13 @@ static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { return LangOpts.CPlusPlus? IK_CXX : IK_C; } -namespace { - struct CompileModuleMapData { - CompilerInstance &Instance; - GenerateModuleAction &CreateModuleAction; - }; -} - -/// \brief Helper function that executes the module-generating action under -/// a crash recovery context. -static void doCompileMapModule(void *UserData) { - CompileModuleMapData &Data - = *reinterpret_cast<CompileModuleMapData *>(UserData); - Data.Instance.ExecuteAction(Data.CreateModuleAction); -} - -namespace { - /// \brief Function object that checks with the given macro definition should - /// be removed, because it is one of the ignored macros. - class RemoveIgnoredMacro { - const HeaderSearchOptions &HSOpts; - - public: - explicit RemoveIgnoredMacro(const HeaderSearchOptions &HSOpts) - : HSOpts(HSOpts) { } - - bool operator()(const std::pair<std::string, bool> &def) const { - StringRef MacroDef = def.first; - return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0; - } - }; -} - /// \brief Compile a module file for the given module, using the options -/// provided by the importing compiler instance. -static void compileModule(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - Module *Module, - StringRef ModuleFileName) { - // FIXME: have LockFileManager return an error_code so that we can - // avoid the mkdir when the directory already exists. - StringRef Dir = llvm::sys::path::parent_path(ModuleFileName); - llvm::sys::fs::create_directories(Dir); - - llvm::LockFileManager Locked(ModuleFileName); - switch (Locked) { - case llvm::LockFileManager::LFS_Error: - return; - - case llvm::LockFileManager::LFS_Owned: - // We're responsible for building the module ourselves. Do so below. - break; - - case llvm::LockFileManager::LFS_Shared: - // Someone else is responsible for building the module. Wait for them to - // finish. - Locked.waitForUnlock(); - return; - } - +/// 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(); @@ -824,10 +875,13 @@ static void compileModule(CompilerInstance &ImportingInstance, // Remove any macro definitions that are explicitly ignored by the module. // They aren't supposed to affect how the module is built anyway. const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); - PPOpts.Macros.erase(std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), - RemoveIgnoredMacro(HSOpts)), - PPOpts.Macros.end()); - + PPOpts.Macros.erase( + std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), + [&HSOpts](const std::pair<std::string, bool> &def) { + StringRef MacroDef = def.first; + return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0; + }), + PPOpts.Macros.end()); // Note the name of the module we're building. Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName(); @@ -860,16 +914,18 @@ static void compileModule(CompilerInstance &ImportingInstance, // Construct a compiler instance that will be used to actually create the // module. - CompilerInstance Instance; + CompilerInstance Instance(/*BuildingModule=*/true); Instance.setInvocation(&*Invocation); Instance.createDiagnostics(new ForwardingDiagnosticConsumer( ImportingInstance.getDiagnosticClient()), /*ShouldOwnClient=*/true); + Instance.setVirtualFileSystem(&ImportingInstance.getVirtualFileSystem()); + // Note that this module is part of the module build stack, so that we // can detect cycles in the module graph. - Instance.createFileManager(); // FIXME: Adopt file manager from importer? + Instance.setFileManager(&ImportingInstance.getFileManager()); Instance.createSourceManager(Instance.getFileManager()); SourceManager &SourceMgr = Instance.getSourceManager(); SourceMgr.setModuleBuildStack( @@ -877,6 +933,10 @@ static void compileModule(CompilerInstance &ImportingInstance, SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(), FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + // If we're collecting module dependencies, we need to share a collector + // between all of the module CompilerInstances. + Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector()); + // Get or create the module map that we'll use to build this module. std::string InferredModuleMapContent; if (const FileEntry *ModuleMapFile = @@ -891,24 +951,24 @@ static void compileModule(CompilerInstance &ImportingInstance, FrontendOpts.Inputs.push_back( FrontendInputFile("__inferred_module.map", IK)); - const llvm::MemoryBuffer *ModuleMapBuffer = + llvm::MemoryBuffer *ModuleMapBuffer = llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); ModuleMapFile = Instance.getFileManager().getVirtualFile( "__inferred_module.map", InferredModuleMapContent.size(), 0); SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer); } - // Construct a module-generating action. - GenerateModuleAction CreateModuleAction(Module->IsSystem); + // Construct a module-generating action. Passing through Module->ModuleMap is + // safe because the FileManager is shared between the compiler instances. + GenerateModuleAction CreateModuleAction(Module->ModuleMap, Module->IsSystem); // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; - CompileModuleMapData Data = { Instance, CreateModuleAction }; - CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize); + CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); }, + ThreadStackSize); - // Delete the temporary module map file. // FIXME: Even though we're executing under crash protection, it would still // be nice to do this with RemoveFileOnSignal when we can. However, that @@ -920,6 +980,67 @@ static void compileModule(CompilerInstance &ImportingInstance, if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { ImportingInstance.setBuildGlobalModuleIndex(true); } + + return !Instance.getDiagnostics().hasErrorOccurred(); +} + +static bool compileAndLoadModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, Module *Module, + StringRef ModuleFileName) { + auto diagnoseBuildFailure = [&] { + ImportingInstance.getDiagnostics().Report(ModuleNameLoc, + diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + }; + + // FIXME: have LockFileManager return an error_code so that we can + // avoid the mkdir when the directory already exists. + StringRef Dir = llvm::sys::path::parent_path(ModuleFileName); + llvm::sys::fs::create_directories(Dir); + + while (1) { + unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing; + llvm::LockFileManager Locked(ModuleFileName); + switch (Locked) { + case llvm::LockFileManager::LFS_Error: + return false; + + case llvm::LockFileManager::LFS_Owned: + // We're responsible for building the module ourselves. + if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module, + ModuleFileName)) { + diagnoseBuildFailure(); + return false; + } + break; + + case llvm::LockFileManager::LFS_Shared: + // Someone else is responsible for building the module. Wait for them to + // finish. + if (Locked.waitForUnlock() == llvm::LockFileManager::Res_OwnerDied) + continue; // try again to get the lock. + ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; + break; + } + + // Try to read the module file, now that we've compiled it. + ASTReader::ASTReadResult ReadResult = + ImportingInstance.getModuleManager()->ReadAST( + ModuleFileName, serialization::MK_Module, ImportLoc, + ModuleLoadCapabilities); + + if (ReadResult == ASTReader::OutOfDate && + Locked == llvm::LockFileManager::LFS_Shared) { + // The module may be out of date in the presence of file system races, + // or if one of its imports depends on header search paths that are not + // consistent with this ImportingInstance. Try again... + continue; + } else if (ReadResult == ASTReader::Missing) { + diagnoseBuildFailure(); + } + return ReadResult == ASTReader::Success; + } } /// \brief Diagnose differences between the current definition of the given @@ -1012,7 +1133,7 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, static void writeTimestampFile(StringRef TimestampFile) { std::string ErrorInfo; llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo, - llvm::sys::fs::F_Binary); + llvm::sys::fs::F_None); } /// \brief Prune the module cache of modules that haven't been accessed in @@ -1035,7 +1156,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { // Check whether the time stamp is older than our pruning interval. // If not, do nothing. time_t TimeStampModTime = StatBuf.st_mtime; - time_t CurrentTime = time(0); + time_t CurrentTime = time(nullptr); if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval)) return; @@ -1046,7 +1167,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { // Walk the entire module cache, looking for unused module files and module // indices. - llvm::error_code EC; + std::error_code EC; SmallString<128> ModuleCachePathNative; llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative); for (llvm::sys::fs::directory_iterator @@ -1057,44 +1178,76 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { continue; // Walk all of the files within this directory. - bool RemovedAllFiles = true; for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { // We only care about module and global module index files. - if (llvm::sys::path::extension(File->path()) != ".pcm" && - llvm::sys::path::filename(File->path()) != "modules.idx") { - RemovedAllFiles = false; + StringRef Extension = llvm::sys::path::extension(File->path()); + if (Extension != ".pcm" && Extension != ".timestamp" && + llvm::sys::path::filename(File->path()) != "modules.idx") continue; - } // Look at this file. If we can't stat it, there's nothing interesting // there. - if (::stat(File->path().c_str(), &StatBuf)) { - RemovedAllFiles = false; + if (::stat(File->path().c_str(), &StatBuf)) continue; - } // If the file has been used recently enough, leave it there. time_t FileAccessTime = StatBuf.st_atime; if (CurrentTime - FileAccessTime <= time_t(HSOpts.ModuleCachePruneAfter)) { - RemovedAllFiles = false; continue; } // Remove the file. - bool Existed; - if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) { - RemovedAllFiles = false; - } + llvm::sys::fs::remove(File->path()); + + // Remove the timestamp file. + std::string TimpestampFilename = File->path() + ".timestamp"; + llvm::sys::fs::remove(TimpestampFilename); } // If we removed all of the files in the directory, remove the directory // itself. - if (RemovedAllFiles) { - bool Existed; - llvm::sys::fs::remove(Dir->path(), Existed); + if (llvm::sys::fs::directory_iterator(Dir->path(), EC) == + llvm::sys::fs::directory_iterator() && !EC) + llvm::sys::fs::remove(Dir->path()); + } +} + +void CompilerInstance::createModuleManager() { + if (!ModuleManager) { + if (!hasASTContext()) + createASTContext(); + + // If we're not recursively building a module, check whether we + // need to prune the module cache. + if (getSourceManager().getModuleBuildStack().empty() && + getHeaderSearchOpts().ModuleCachePruneInterval > 0 && + getHeaderSearchOpts().ModuleCachePruneAfter > 0) { + pruneModuleCache(getHeaderSearchOpts()); + } + + HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); + std::string Sysroot = HSOpts.Sysroot; + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + ModuleManager = new ASTReader(getPreprocessor(), *Context, + Sysroot.empty() ? "" : Sysroot.c_str(), + PPOpts.DisablePCHValidation, + /*AllowASTWithCompilerErrors=*/false, + /*AllowConfigurationMismatch=*/false, + HSOpts.ModulesValidateSystemHeaders, + getFrontendOpts().UseGlobalModuleIndex); + if (hasASTConsumer()) { + ModuleManager->setDeserializationListener( + getASTConsumer().GetASTDeserializationListener()); + getASTContext().setASTMutationListener( + getASTConsumer().GetASTMutationListener()); } + getASTContext().setExternalSource(ModuleManager); + if (hasSema()) + ModuleManager->InitializeSema(getSema()); + if (hasASTConsumer()) + ModuleManager->StartTranslationUnit(&getASTConsumer()); } } @@ -1118,7 +1271,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return LastModuleImportResult; } - clang::Module *Module = 0; + clang::Module *Module = nullptr; // If we don't already have information on this module, load the module now. llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known @@ -1128,51 +1281,34 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Module = Known->second; } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. - Module = PP->getHeaderSearchInfo().getModuleMap().findModule(ModuleName); + Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; } else { // Search for a module with the given name. Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); - std::string ModuleFileName; - if (Module) { - ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module); - } else - ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName); + if (!Module) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + + std::string ModuleFileName = + PP->getHeaderSearchInfo().getModuleFileName(Module); // If we don't already have an ASTReader, create one now. - if (!ModuleManager) { - if (!hasASTContext()) - createASTContext(); - - // If we're not recursively building a module, check whether we - // need to prune the module cache. - if (getSourceManager().getModuleBuildStack().empty() && - getHeaderSearchOpts().ModuleCachePruneInterval > 0 && - getHeaderSearchOpts().ModuleCachePruneAfter > 0) { - pruneModuleCache(getHeaderSearchOpts()); - } + if (!ModuleManager) + createModuleManager(); - std::string Sysroot = getHeaderSearchOpts().Sysroot; - const PreprocessorOptions &PPOpts = getPreprocessorOpts(); - ModuleManager = new ASTReader(getPreprocessor(), *Context, - Sysroot.empty() ? "" : Sysroot.c_str(), - PPOpts.DisablePCHValidation, - /*AllowASTWithCompilerErrors=*/false, - getFrontendOpts().UseGlobalModuleIndex); - if (hasASTConsumer()) { - ModuleManager->setDeserializationListener( - getASTConsumer().GetASTDeserializationListener()); - getASTContext().setASTMutationListener( - getASTConsumer().GetASTMutationListener()); - } - OwningPtr<ExternalASTSource> Source; - Source.reset(ModuleManager); - getASTContext().setExternalSource(Source); - if (hasSema()) - ModuleManager->InitializeSema(getSema()); - if (hasASTConsumer()) - ModuleManager->StartTranslationUnit(&getASTConsumer()); - } + if (TheDependencyFileGenerator) + TheDependencyFileGenerator->AttachToASTReader(*ModuleManager); + + if (ModuleDepCollector) + ModuleDepCollector->attachToASTReader(*ModuleManager); + + for (auto &Listener : DependencyCollectors) + Listener->attachToASTReader(*ModuleManager); // Try to load the module file. unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; @@ -1184,17 +1320,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, case ASTReader::OutOfDate: case ASTReader::Missing: { // The module file is missing or out-of-date. Build it. - - // If we don't have a module, we don't know how to build the module file. - // Complain and return. - if (!Module) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - + assert(Module && "missing module file"); // Check whether there is a cycle in the module graph. ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack(); ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end(); @@ -1216,6 +1342,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } + getDiagnostics().Report(ImportLoc, diag::remark_module_build) + << ModuleName << ModuleFileName; + // Check whether we have already attempted to build this module (but // failed). if (getPreprocessorOpts().FailedModules && @@ -1227,26 +1356,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } - // Try to compile the module. - compileModule(*this, ModuleNameLoc, Module, ModuleFileName); - - // Try to read the module file, now that we've compiled it. - ASTReader::ASTReadResult ReadResult - = ModuleManager->ReadAST(ModuleFileName, - serialization::MK_Module, ImportLoc, - ASTReader::ARR_Missing); - if (ReadResult != ASTReader::Success) { - if (ReadResult == ASTReader::Missing) { - getDiagnostics().Report(ModuleNameLoc, - Module? diag::err_module_not_built - : diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - } - + // Try to compile and then load the module. + if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module, + ModuleFileName)) { if (getPreprocessorOpts().FailedModules) getPreprocessorOpts().FailedModules->addFailed(ModuleName); - KnownModules[Path[0].first] = 0; + KnownModules[Path[0].first] = nullptr; ModuleBuildFailed = true; return ModuleLoadResult(); } @@ -1261,23 +1376,16 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleLoader::HadFatalFailure = true; // FIXME: The ASTReader will already have complained, but can we showhorn // that diagnostic information into a more useful form? - KnownModules[Path[0].first] = 0; + KnownModules[Path[0].first] = nullptr; return ModuleLoadResult(); case ASTReader::Failure: ModuleLoader::HadFatalFailure = true; // Already complained, but note now that we failed. - KnownModules[Path[0].first] = 0; + KnownModules[Path[0].first] = nullptr; ModuleBuildFailed = true; return ModuleLoadResult(); } - - if (!Module) { - // If we loaded the module directly, without finding a module map first, - // we'll have loaded the module's information from the module itself. - Module = PP->getHeaderSearchInfo().getModuleMap() - .findModule((Path[0].first->getName())); - } // Cache the result of this top-level module lookup for later. Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; @@ -1354,17 +1462,25 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule) << Module->getFullModuleName() << SourceRange(Path.front().second, Path.back().second); - - return ModuleLoadResult(0, true); + + return ModuleLoadResult(nullptr, true); } // Check whether this module is available. clang::Module::Requirement Requirement; - if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement)) { - getDiagnostics().Report(ImportLoc, diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first - << SourceRange(Path.front().second, Path.back().second); + clang::Module::HeaderDirective MissingHeader; + if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement, + MissingHeader)) { + if (MissingHeader.FileNameLoc.isValid()) { + getDiagnostics().Report(MissingHeader.FileNameLoc, + diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + } else { + getDiagnostics().Report(ImportLoc, diag::err_module_unavailable) + << Module->getFullModuleName() + << Requirement.second << Requirement.first + << SourceRange(Path.front().second, Path.back().second); + } LastModuleImportLoc = ImportLoc; LastModuleImportResult = ModuleLoadResult(); return ModuleLoadResult(); @@ -1405,3 +1521,84 @@ void CompilerInstance::makeModuleVisible(Module *Mod, ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain); } +GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( + SourceLocation TriggerLoc) { + if (!ModuleManager) + createModuleManager(); + // Can't do anything if we don't have the module manager. + if (!ModuleManager) + return nullptr; + // Get an existing global index. This loads it if not already + // loaded. + ModuleManager->loadGlobalIndex(); + GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex(); + // If the global index doesn't exist, create it. + if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() && + hasPreprocessor()) { + llvm::sys::fs::create_directories( + getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); + GlobalModuleIndex::writeIndex( + getFileManager(), + getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); + ModuleManager->resetForReload(); + ModuleManager->loadGlobalIndex(); + GlobalIndex = ModuleManager->getGlobalIndex(); + } + // For finding modules needing to be imported for fixit messages, + // we need to make the global index cover all modules, so we do that here. + if (!HaveFullGlobalModuleIndex && GlobalIndex && !buildingModule()) { + ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap(); + bool RecreateIndex = false; + for (ModuleMap::module_iterator I = MMap.module_begin(), + E = MMap.module_end(); I != E; ++I) { + Module *TheModule = I->second; + const FileEntry *Entry = TheModule->getASTFile(); + if (!Entry) { + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; + Path.push_back(std::make_pair( + getPreprocessor().getIdentifierInfo(TheModule->Name), TriggerLoc)); + std::reverse(Path.begin(), Path.end()); + // Load a module as hidden. This also adds it to the global index. + loadModule(TheModule->DefinitionLoc, Path, + Module::Hidden, false); + RecreateIndex = true; + } + } + if (RecreateIndex) { + GlobalModuleIndex::writeIndex( + getFileManager(), + getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); + ModuleManager->resetForReload(); + ModuleManager->loadGlobalIndex(); + GlobalIndex = ModuleManager->getGlobalIndex(); + } + HaveFullGlobalModuleIndex = true; + } + return GlobalIndex; +} + +// Check global module index for missing imports. +bool +CompilerInstance::lookupMissingImports(StringRef Name, + SourceLocation TriggerLoc) { + // Look for the symbol in non-imported modules, but only if an error + // actually occurred. + if (!buildingModule()) { + // Load global module index, or retrieve a previously loaded one. + GlobalModuleIndex *GlobalIndex = loadGlobalModuleIndex( + TriggerLoc); + + // Only if we have a global index. + if (GlobalIndex) { + GlobalModuleIndex::HitSet FoundModules; + + // Find the modules that reference the identifier. + // Note that this only finds top-level modules. + // We'll let diagnoseTypo find the actual declaration module. + if (GlobalIndex->lookupIdentifier(Name, FoundModules)) + return true; + } + } + + return false; +} |