diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp | 689 |
1 files changed, 404 insertions, 285 deletions
diff --git a/contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp index c642af1849bc..a25aa88bd85e 100644 --- a/contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/CompilerInstance.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangStandard.h" #include "clang/Basic/SourceManager.h" @@ -23,7 +24,9 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/LogDiagnosticPrinter.h" +#include "clang/Frontend/SARIFDiagnosticPrinter.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" @@ -36,12 +39,14 @@ #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/BuryPointer.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" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -50,6 +55,8 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include <optional> #include <time.h> #include <utility> @@ -107,26 +114,26 @@ bool CompilerInstance::createTarget() { // Check whether AuxTarget exists, if not, then create TargetInfo for the // other side of CUDA/OpenMP/SYCL compilation. if (!getAuxTarget() && - (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + (getLangOpts().CUDA || getLangOpts().OpenMPIsTargetDevice || getLangOpts().SYCLIsDevice) && !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared<TargetOptions>(); TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple); if (getFrontendOpts().AuxTargetCPU) - TO->CPU = getFrontendOpts().AuxTargetCPU.getValue(); + TO->CPU = *getFrontendOpts().AuxTargetCPU; if (getFrontendOpts().AuxTargetFeatures) - TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.getValue(); + TO->FeaturesAsWritten = *getFrontendOpts().AuxTargetFeatures; TO->HostTriple = getTarget().getTriple().str(); setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO)); } if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) { - if (getLangOpts().getFPRoundingMode() != - llvm::RoundingMode::NearestTiesToEven) { + if (getLangOpts().RoundingMath) { getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_rounding); - getLangOpts().setFPRoundingMode(llvm::RoundingMode::NearestTiesToEven); + getLangOpts().RoundingMath = false; } - if (getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore) { + auto FPExc = getLangOpts().getFPExceptionMode(); + if (FPExc != LangOptions::FPE_Default && FPExc != LangOptions::FPE_Ignore) { getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_exceptions); getLangOpts().setFPExceptionMode(LangOptions::FPE_Ignore); } @@ -144,9 +151,6 @@ bool CompilerInstance::createTarget() { // created. This complexity should be lifted elsewhere. getTarget().adjust(getDiagnostics(), getLangOpts()); - // Adjust target options based on codegen options. - getTarget().adjustTargetOptions(getCodeGenOpts(), getTargetOpts()); - if (auto *Aux = getAuxTarget()) getTarget().setAuxTarget(Aux); @@ -230,7 +234,7 @@ static void collectIncludePCH(CompilerInstance &CI, StringRef PCHInclude = PPOpts.ImplicitPCHInclude; FileManager &FileMgr = CI.getFileManager(); - auto PCHDir = FileMgr.getDirectory(PCHInclude); + auto PCHDir = FileMgr.getOptionalDirectoryRef(PCHInclude); if (!PCHDir) { MDC->addFile(PCHInclude); return; @@ -238,7 +242,7 @@ static void collectIncludePCH(CompilerInstance &CI, std::error_code EC; SmallString<128> DirNative; - llvm::sys::path::native((*PCHDir)->getName(), DirNative); + llvm::sys::path::native(PCHDir->getName(), DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); SimpleASTReaderListener Validator(CI.getPreprocessor()); for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; @@ -247,7 +251,8 @@ static void collectIncludePCH(CompilerInstance &CI, // used here since we're not interested in validating the PCH at this time, // but only to check whether this is a file containing an AST. if (!ASTReader::readASTFileControlBlock( - Dir->path(), FileMgr, CI.getPCHContainerReader(), + Dir->path(), FileMgr, CI.getModuleCache(), + CI.getPCHContainerReader(), /*FindModuleFileExtensions=*/false, Validator, /*ValidateDiagnosticOptions=*/false)) MDC->addFile(Dir->path()); @@ -344,6 +349,8 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, // implementing -verify. if (Client) { Diags->setClient(Client, ShouldOwnClient); + } else if (Opts->getFormat() == DiagnosticOptions::SARIF) { + Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts)); } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); @@ -393,14 +400,8 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags, // 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; - } + FileEntryRef FromFile = + FileMgr.getVirtualFileRef(RB.first, RB.second->getBufferSize(), 0); // Override the contents of the "from" file with the contents of the // "to" file. If the caller owns the buffers, then pass a MemoryBufferRef; @@ -417,7 +418,7 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags, // Remap files in the source manager (with other files). for (const auto &RF : InitOpts.RemappedFiles) { // Find the file that we're mapping to. - auto ToFile = FileMgr.getFile(RF.second); + OptionalFileEntryRef ToFile = FileMgr.getOptionalFileRef(RF.second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second; continue; @@ -425,7 +426,7 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags, // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = - FileMgr.getVirtualFile(RF.first, (*ToFile)->getSize(), 0); + FileMgr.getVirtualFile(RF.first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << RF.first; continue; @@ -469,7 +470,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { // Predefine macros and configure the preprocessor. InitializePreprocessor(*PP, PPOpts, getPCHContainerReader(), - getFrontendOpts()); + getFrontendOpts(), getCodeGenOpts()); // Initialize the header search object. In CUDA compilations, we use the aux // triple (the host triple) to initialize our header search, since we need to @@ -542,7 +543,7 @@ std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { SmallString<256> SpecificModuleCache(getHeaderSearchOpts().ModuleCachePath); if (!SpecificModuleCache.empty() && !getHeaderSearchOpts().DisableModuleHash) llvm::sys::path::append(SpecificModuleCache, ModuleHash); - return std::string(SpecificModuleCache.str()); + return std::string(SpecificModuleCache); } // ASTContext @@ -558,6 +559,55 @@ void CompilerInstance::createASTContext() { // ExternalASTSource +namespace { +// Helper to recursively read the module names for all modules we're adding. +// We mark these as known and redirect any attempt to load that module to +// the files we were handed. +struct ReadModuleNames : ASTReaderListener { + Preprocessor &PP; + llvm::SmallVector<std::string, 8> LoadedModules; + + ReadModuleNames(Preprocessor &PP) : PP(PP) {} + + void ReadModuleName(StringRef ModuleName) override { + // Keep the module name as a string for now. It's not safe to create a new + // IdentifierInfo from an ASTReader callback. + LoadedModules.push_back(ModuleName.str()); + } + + void registerAll() { + ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap(); + for (const std::string &LoadedModule : LoadedModules) + MM.cacheModuleLoad(*PP.getIdentifierInfo(LoadedModule), + MM.findModule(LoadedModule)); + LoadedModules.clear(); + } + + void markAllUnavailable() { + for (const std::string &LoadedModule : LoadedModules) { + if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule( + LoadedModule)) { + M->HasIncompatibleModuleFile = true; + + // Mark module as available if the only reason it was unavailable + // was missing headers. + SmallVector<Module *, 2> Stack; + Stack.push_back(M); + while (!Stack.empty()) { + Module *Current = Stack.pop_back_val(); + if (Current->IsUnimportable) continue; + Current->IsAvailable = true; + auto SubmodulesRange = Current->submodules(); + Stack.insert(Stack.end(), SubmodulesRange.begin(), + SubmodulesRange.end()); + } + } + } + LoadedModules.clear(); + } +}; +} // namespace + void CompilerInstance::createPCHExternalASTSource( StringRef Path, DisableValidationForModuleKind DisableValidation, bool AllowPCHWithCompilerErrors, void *DeserializationListener, @@ -602,6 +652,11 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*Reader); + auto Listener = std::make_unique<ReadModuleNames>(PP); + auto &ListenerRef = *Listener; + ASTReader::ListenerScope ReadModuleNamesListener(*Reader, + std::move(Listener)); + switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, @@ -611,6 +666,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); + ListenerRef.registerAll(); return Reader; case ASTReader::Failure: @@ -626,6 +682,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( break; } + ListenerRef.markAllUnavailable(); Context.setExternalSource(nullptr); return nullptr; } @@ -638,7 +695,7 @@ static bool EnableCodeCompletion(Preprocessor &PP, unsigned Column) { // Tell the source manager to chop off the given file at a specific // line and column. - auto Entry = PP.getFileManager().getFile(Filename); + auto Entry = PP.getFileManager().getOptionalFileRef(Filename); if (!Entry) { PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) << Filename; @@ -653,13 +710,10 @@ static bool EnableCodeCompletion(Preprocessor &PP, void CompilerInstance::createCodeCompletionConsumer() { const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; if (!CompletionConsumer) { - setCodeCompletionConsumer( - createCodeCompletionConsumer(getPreprocessor(), - Loc.FileName, Loc.Line, Loc.Column, - getFrontendOpts().CodeCompleteOpts, - llvm::outs())); - if (!CompletionConsumer) - return; + setCodeCompletionConsumer(createCodeCompletionConsumer( + getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().CodeCompleteOpts, llvm::outs())); + return; } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column)) { setCodeCompletionConsumer(nullptr); @@ -693,16 +747,30 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer) { TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), TUKind, CompletionConsumer)); + + // Set up API notes. + TheSema->APINotes.setSwiftVersion(getAPINotesOpts().SwiftVersion); + // Attach the external sema source if there is any. if (ExternalSemaSrc) { TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } + + // If we're building a module and are supposed to load API notes, + // notify the API notes manager. + if (auto *currentModule = getPreprocessor().getCurrentModule()) { + (void)TheSema->APINotes.loadCurrentModuleAPINotes( + currentModule, getLangOpts().APINotesModules, + getAPINotesOpts().ModuleSearchPaths); + } } // Output Files void CompilerInstance::clearOutputFiles(bool EraseFiles) { + // The ASTConsumer can own streams that write to the output files. + assert(!hasASTConsumer() && "ASTConsumer should be reset"); // Ignore errors that occur when trying to discard the temp file. for (OutputFile &OF : OutputFiles) { if (EraseFiles) { @@ -721,12 +789,7 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { continue; } - // If '-working-directory' was passed, the output filename should be - // relative to that. - SmallString<128> NewOutFile(OF.Filename); - FileMgr->FixupRelativePath(NewOutFile); - - llvm::Error E = OF.File->keep(NewOutFile); + llvm::Error E = OF.File->keep(OF.Filename); if (!E) continue; @@ -747,7 +810,7 @@ std::unique_ptr<raw_pwrite_stream> CompilerInstance::createDefaultOutputFile( bool Binary, StringRef InFile, StringRef Extension, bool RemoveFileOnSignal, bool CreateMissingDirectories, bool ForceUseTemporary) { StringRef OutputPath = getFrontendOpts().OutputFile; - Optional<SmallString<128>> PathStorage; + std::optional<SmallString<128>> PathStorage; if (OutputPath.empty()) { if (InFile == "-" || Extension.empty()) { OutputPath = "-"; @@ -789,8 +852,20 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, assert((!CreateMissingDirectories || UseTemporary) && "CreateMissingDirectories is only allowed when using temporary files"); + // If '-working-directory' was passed, the output filename should be + // relative to that. + std::optional<SmallString<128>> AbsPath; + if (OutputPath != "-" && !llvm::sys::path::is_absolute(OutputPath)) { + assert(hasFileManager() && + "File Manager is required to fix up relative path.\n"); + + AbsPath.emplace(OutputPath); + FileMgr->FixupRelativePath(*AbsPath); + OutputPath = *AbsPath; + } + std::unique_ptr<llvm::raw_fd_ostream> OS; - Optional<StringRef> OSFile; + std::optional<StringRef> OSFile; if (UseTemporary) { if (OutputPath == "-") @@ -812,7 +887,7 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, } } - Optional<llvm::sys::fs::TempFile> Temp; + std::optional<llvm::sys::fs::TempFile> Temp; if (UseTemporary) { // Create a temporary file. // Insert -%%%%%%%% before the extension (if any), and because some tools @@ -824,10 +899,12 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, TempPath += "-%%%%%%%%"; TempPath += OutputExtension; TempPath += ".tmp"; + llvm::sys::fs::OpenFlags BinaryFlags = + Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text; Expected<llvm::sys::fs::TempFile> ExpectedFile = llvm::sys::fs::TempFile::create( TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, - Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text); + BinaryFlags); llvm::Error E = handleErrors( ExpectedFile.takeError(), [&](const llvm::ECError &E) -> llvm::Error { @@ -837,7 +914,9 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, StringRef Parent = llvm::sys::path::parent_path(OutputPath); EC = llvm::sys::fs::create_directories(Parent); if (!EC) { - ExpectedFile = llvm::sys::fs::TempFile::create(TempPath); + ExpectedFile = llvm::sys::fs::TempFile::create( + TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, + BinaryFlags); if (!ExpectedFile) return llvm::errorCodeToError( llvm::errc::no_such_file_or_directory); @@ -911,10 +990,9 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, ? FileMgr.getSTDIN() : FileMgr.getFileRef(InputFile, /*OpenFile=*/true); if (!FileOrErr) { - // FIXME: include the error in the diagnostic even when it's not stdin. auto EC = llvm::errorToErrorCode(FileOrErr.takeError()); if (InputFile != "-") - Diags.Report(diag::err_fe_error_reading) << InputFile; + Diags.Report(diag::err_fe_error_reading) << InputFile << EC.message(); else Diags.Report(diag::err_fe_error_reading_stdin) << EC.message(); return false; @@ -940,6 +1018,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // DesiredStackSpace available. noteBottomOfStack(); + auto FinishDiagnosticClient = llvm::make_scope_exit([&]() { + // Notify the diagnostic client that all files were processed. + getDiagnosticClient().finish(); + }); + raw_ostream &OS = getVerboseOutputStream(); if (!Act.PrepareToExecute(*this)) @@ -954,9 +1037,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // Validate/process some options. if (getHeaderSearchOpts().Verbose) - OS << "clang -cc1 version " CLANG_VERSION_STRING - << " based upon " << BACKEND_PACKAGE_STRING - << " default target " << llvm::sys::getDefaultTargetTriple() << "\n"; + OS << "clang -cc1 version " CLANG_VERSION_STRING << " based upon LLVM " + << LLVM_VERSION_STRING << " default target " + << llvm::sys::getDefaultTargetTriple() << "\n"; if (getCodeGenOpts().TimePasses) createFrontendTimer(); @@ -978,9 +1061,6 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } } - // Notify the diagnostic client that all files were processed. - getDiagnostics().getClient()->finish(); - if (getDiagnosticOpts().ShowCarets) { // We can have multiple diagnostics sharing one diagnostic client. // Get the total number of warnings/errors from the client. @@ -1015,9 +1095,12 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } StringRef StatsFile = getFrontendOpts().StatsFile; if (!StatsFile.empty()) { + llvm::sys::fs::OpenFlags FileFlags = llvm::sys::fs::OF_TextWithCRLF; + if (getFrontendOpts().AppendStats) + FileFlags |= llvm::sys::fs::OF_Append; std::error_code EC; - auto StatS = std::make_unique<llvm::raw_fd_ostream>( - StatsFile, EC, llvm::sys::fs::OF_TextWithCRLF); + auto StatS = + std::make_unique<llvm::raw_fd_ostream>(StatsFile, EC, FileFlags); if (EC) { getDiagnostics().Report(diag::warn_fe_unable_to_open_stats_file) << StatsFile << EC.message(); @@ -1029,6 +1112,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { return !getDiagnostics().getClient()->getNumErrors(); } +void CompilerInstance::LoadRequestedPlugins() { + // Load any requested plugins. + for (const std::string &Path : getFrontendOpts().Plugins) { + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) + getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << Error; + } + + // Check if any of the loaded plugins replaces the main AST action + for (const FrontendPluginRegistry::entry &Plugin : + FrontendPluginRegistry::entries()) { + std::unique_ptr<PluginASTAction> P(Plugin.instantiate()); + if (P->getActionType() == PluginASTAction::ReplaceAction) { + getFrontendOpts().ProgramAction = clang::frontend::PluginAction; + getFrontendOpts().ActionName = Plugin.getName().str(); + break; + } + } +} + /// Determine the appropriate source input kind based on language /// options. static Language getLanguageFromOptions(const LangOptions &LangOpts) { @@ -1071,27 +1175,24 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // For any options that aren't intended to affect how a module is built, // reset them to their default values. - Invocation->getLangOpts()->resetNonModularOptions(); - PPOpts.resetNonModularOptions(); + Invocation->resetNonModularOptions(); // Remove any macro definitions that are explicitly ignored by the module. // They aren't supposed to affect how the module is built anyway. HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); - 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( - llvm::CachedHashString(MacroDef.split('=').first)) > 0; - }), - PPOpts.Macros.end()); + llvm::erase_if(PPOpts.Macros, + [&HSOpts](const std::pair<std::string, bool> &def) { + StringRef MacroDef = def.first; + return HSOpts.ModulesIgnoreMacros.contains( + llvm::CachedHashString(MacroDef.split('=').first)); + }); // If the original compiler invocation had -fmodule-name, pass it through. - Invocation->getLangOpts()->ModuleName = - ImportingInstance.getInvocation().getLangOpts()->ModuleName; + Invocation->getLangOpts().ModuleName = + ImportingInstance.getInvocation().getLangOpts().ModuleName; // Note the name of the module we're building. - Invocation->getLangOpts()->CurrentModule = std::string(ModuleName); + Invocation->getLangOpts().CurrentModule = std::string(ModuleName); // Make sure that the failed-module structure has been allocated in // the importing instance, and propagate the pointer to the newly-created @@ -1119,7 +1220,9 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; - Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; + DiagnosticOptions &DiagOpts = Invocation->getDiagnosticOpts(); + + DiagOpts.VerifyDiagnostics = 0; assert(ImportingInstance.getInvocation().getModuleHash() == Invocation->getModuleHash() && "Module hash mismatch!"); @@ -1136,11 +1239,19 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, ImportingInstance.getDiagnosticClient()), /*ShouldOwnClient=*/true); - // Note that this module is part of the module build stack, so that we - // can detect cycles in the module graph. - Instance.setFileManager(&ImportingInstance.getFileManager()); + if (llvm::is_contained(DiagOpts.SystemHeaderWarningsModules, ModuleName)) + Instance.getDiagnostics().setSuppressSystemWarnings(false); + + if (FrontendOpts.ModulesShareFileManager) { + Instance.setFileManager(&ImportingInstance.getFileManager()); + } else { + Instance.createFileManager(&ImportingInstance.getVirtualFileSystem()); + } Instance.createSourceManager(Instance.getFileManager()); SourceManager &SourceMgr = Instance.getSourceManager(); + + // Note that this module is part of the module build stack, so that we + // can detect cycles in the module graph. SourceMgr.setModuleBuildStack( ImportingInstance.getSourceManager().getModuleBuildStack()); SourceMgr.pushModuleBuildStack(ModuleName, @@ -1160,8 +1271,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. - llvm::CrashRecoveryContext CRC; - CRC.RunSafelyOnThread( + bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread( [&]() { GenerateModuleFromModuleMapAction Action; Instance.ExecuteAction(Action); @@ -1174,9 +1284,15 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, diag::remark_module_build_done) << ModuleName; - // Delete any remaining temporary files related to Instance, in case the - // module generation thread crashed. - Instance.clearOutputFiles(/*EraseFiles=*/true); + if (Crashed) { + // Clear the ASTConsumer if it hasn't been already, in case it owns streams + // that must be closed before clearing output files. + Instance.setSema(nullptr); + Instance.setASTConsumer(nullptr); + + // Delete any remaining temporary files related to Instance. + Instance.clearOutputFiles(/*EraseFiles=*/true); + } // If \p AllowPCMWithCompilerErrors is set return 'success' even if errors // occurred. @@ -1184,19 +1300,17 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, Instance.getFrontendOpts().AllowPCMWithCompilerErrors; } -static const FileEntry *getPublicModuleMap(const FileEntry *File, - FileManager &FileMgr) { - StringRef Filename = llvm::sys::path::filename(File->getName()); - SmallString<128> PublicFilename(File->getDir()->getName()); +static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File, + FileManager &FileMgr) { + StringRef Filename = llvm::sys::path::filename(File.getName()); + SmallString<128> PublicFilename(File.getDir().getName()); if (Filename == "module_private.map") llvm::sys::path::append(PublicFilename, "module.map"); else if (Filename == "module.private.modulemap") llvm::sys::path::append(PublicFilename, "module.modulemap"); else - return nullptr; - if (auto FE = FileMgr.getFile(PublicFilename)) - return *FE; - return nullptr; + return std::nullopt; + return FileMgr.getOptionalFileRef(PublicFilename); } /// Compile a module file for the given module in a separate compiler instance, @@ -1212,21 +1326,22 @@ static bool compileModule(CompilerInstance &ImportingInstance, ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); bool Result; - if (const FileEntry *ModuleMapFile = + if (OptionalFileEntryRef ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Canonicalize compilation to start with the public module map. This is // vital for submodules declarations in the private module maps to be // correctly parsed when depending on a top level module in the public one. - if (const FileEntry *PublicMMFile = getPublicModuleMap( - ModuleMapFile, ImportingInstance.getFileManager())) + if (OptionalFileEntryRef PublicMMFile = getPublicModuleMap( + *ModuleMapFile, ImportingInstance.getFileManager())) ModuleMapFile = PublicMMFile; + StringRef ModuleMapFilePath = ModuleMapFile->getNameAsRequested(); + // 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); + FrontendInputFile(ModuleMapFilePath, 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 @@ -1248,7 +1363,7 @@ static bool compileModule(CompilerInstance &ImportingInstance, [&](CompilerInstance &Instance) { std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); - ModuleMapFile = Instance.getFileManager().getVirtualFile( + FileEntryRef ModuleMapFile = Instance.getFileManager().getVirtualFileRef( FakeModuleMapFile, InferredModuleMapContent.size(), 0); Instance.getSourceManager().overrideFileContents( ModuleMapFile, std::move(ModuleMapBuffer)); @@ -1264,31 +1379,82 @@ static bool compileModule(CompilerInstance &ImportingInstance, return Result; } +/// Read the AST right after compiling the module. +static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, StringRef ModuleFileName, + bool *OutOfDate) { + DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics(); + + unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing; + if (OutOfDate) + ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; + + // Try to read the module file, now that we've compiled it. + ASTReader::ASTReadResult ReadResult = + ImportingInstance.getASTReader()->ReadAST( + ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, + ModuleLoadCapabilities); + if (ReadResult == ASTReader::Success) + return true; + + // The caller wants to handle out-of-date failures. + if (OutOfDate && ReadResult == ASTReader::OutOfDate) { + *OutOfDate = true; + return false; + } + + // The ASTReader didn't diagnose the error, so conservatively report it. + if (ReadResult == ASTReader::Missing || !Diags.hasErrorOccurred()) + Diags.Report(ModuleNameLoc, diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + + return false; +} + /// Compile a module in a separate compiler instance and read the AST, /// returning true if the module compiles without errors. +static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, + StringRef ModuleFileName) { + if (!compileModule(ImportingInstance, ModuleNameLoc, Module, + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report(ModuleNameLoc, + diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + return false; + } + + return readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc, + Module, ModuleFileName, + /*OutOfDate=*/nullptr); +} + +/// Compile a module in a separate compiler instance and read the AST, +/// returning true if the module compiles without errors, using a lock manager +/// to avoid building the same module in multiple compiler instances. /// /// Uses a lock file manager and exponential backoff to reduce the chances that /// multiple instances will compete to create the same module. On timeout, /// deletes the lock file in order to avoid deadlock from crashing processes or /// bugs in the lock file manager. -static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - SourceLocation ModuleNameLoc, - Module *Module, StringRef ModuleFileName) { +static bool compileModuleAndReadASTBehindLock( + CompilerInstance &ImportingInstance, SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, Module *Module, StringRef ModuleFileName) { DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics(); - auto diagnoseBuildFailure = [&] { - Diags.Report(ModuleNameLoc, diag::err_module_not_built) - << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); - }; + Diags.Report(ModuleNameLoc, diag::remark_module_lock) + << ModuleFileName << Module->Name; // 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; + while (true) { llvm::LockFileManager Locked(ModuleFileName); switch (Locked) { case llvm::LockFileManager::LFS_Error: @@ -1299,61 +1465,67 @@ static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, << Module->Name << Locked.getErrorMessage(); // Clear out any potential leftover. Locked.unsafeRemoveLockFile(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case llvm::LockFileManager::LFS_Owned: // We're responsible for building the module ourselves. - if (!compileModule(ImportingInstance, ModuleNameLoc, Module, - ModuleFileName)) { - diagnoseBuildFailure(); - return false; - } - break; + return compileModuleAndReadASTImpl(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, ModuleFileName); case llvm::LockFileManager::LFS_Shared: - // Someone else is responsible for building the module. Wait for them to - // finish. - switch (Locked.waitForUnlock()) { - case llvm::LockFileManager::Res_Success: - ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; - break; - case llvm::LockFileManager::Res_OwnerDied: - continue; // try again to get the lock. - case llvm::LockFileManager::Res_Timeout: - // Since ModuleCache takes care of correctness, we try waiting for - // another process to complete the build so clang does not do it done - // twice. If case of timeout, build it ourselves. - Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout) - << Module->Name; - // Clear the lock file so that future invocations can make progress. - Locked.unsafeRemoveLockFile(); - continue; - } - break; + break; // The interesting case. } - // Try to read the module file, now that we've compiled it. - ASTReader::ASTReadResult ReadResult = - ImportingInstance.getASTReader()->ReadAST( - ModuleFileName, serialization::MK_ImplicitModule, 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... + // Someone else is responsible for building the module. Wait for them to + // finish. + switch (Locked.waitForUnlock()) { + case llvm::LockFileManager::Res_Success: + break; // The interesting case. + case llvm::LockFileManager::Res_OwnerDied: + continue; // try again to get the lock. + case llvm::LockFileManager::Res_Timeout: + // Since ModuleCache takes care of correctness, we try waiting for + // another process to complete the build so clang does not do it done + // twice. If case of timeout, build it ourselves. + Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout) + << Module->Name; + // Clear the lock file so that future invocations can make progress. + Locked.unsafeRemoveLockFile(); continue; - } else if (ReadResult == ASTReader::Missing) { - diagnoseBuildFailure(); - } else if (ReadResult != ASTReader::Success && - !Diags.hasErrorOccurred()) { - // The ASTReader didn't diagnose the error, so conservatively report it. - diagnoseBuildFailure(); } - return ReadResult == ASTReader::Success; + + // Read the module that was just written by someone else. + bool OutOfDate = false; + if (readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc, + Module, ModuleFileName, &OutOfDate)) + return true; + if (!OutOfDate) + return false; + + // 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... } } +/// Compile a module in a separate compiler instance and read the AST, +/// returning true if the module compiles without errors, potentially using a +/// lock manager to avoid building the same module in multiple compiler +/// instances. +static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, StringRef ModuleFileName) { + return ImportingInstance.getInvocation() + .getFrontendOpts() + .BuildingImplicitModuleUsesLock + ? compileModuleAndReadASTBehindLock(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, + ModuleFileName) + : compileModuleAndReadASTImpl(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, + ModuleFileName); +} + /// Diagnose differences between the current definition of the given /// configuration macro and the definition provided on the command line. static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, @@ -1548,59 +1720,14 @@ void CompilerInstance::createASTReader() { Listener->attachToASTReader(*TheASTReader); } -bool CompilerInstance::loadModuleFile(StringRef FileName) { +bool CompilerInstance::loadModuleFile( + StringRef FileName, serialization::ModuleFile *&LoadedModuleFile) { llvm::Timer Timer; if (FrontendTimerGroup) Timer.init("preloading." + FileName.str(), "Preloading " + FileName.str(), *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - // Helper to recursively read the module names for all modules we're adding. - // We mark these as known and redirect any attempt to load that module to - // the files we were handed. - struct ReadModuleNames : ASTReaderListener { - CompilerInstance &CI; - llvm::SmallVector<IdentifierInfo*, 8> LoadedModules; - - ReadModuleNames(CompilerInstance &CI) : CI(CI) {} - - void ReadModuleName(StringRef ModuleName) override { - LoadedModules.push_back( - CI.getPreprocessor().getIdentifierInfo(ModuleName)); - } - - void registerAll() { - ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - for (auto *II : LoadedModules) - MM.cacheModuleLoad(*II, MM.findModule(II->getName())); - LoadedModules.clear(); - } - - void markAllUnavailable() { - for (auto *II : LoadedModules) { - if (Module *M = CI.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .findModule(II->getName())) { - M->HasIncompatibleModuleFile = true; - - // Mark module as available if the only reason it was unavailable - // was missing headers. - SmallVector<Module *, 2> Stack; - Stack.push_back(M); - while (!Stack.empty()) { - Module *Current = Stack.pop_back_val(); - if (Current->IsUnimportable) continue; - Current->IsAvailable = true; - Stack.insert(Stack.end(), - Current->submodule_begin(), Current->submodule_end()); - } - } - } - LoadedModules.clear(); - } - }; - // If we don't already have an ASTReader, create one now. if (!TheASTReader) createASTReader(); @@ -1612,7 +1739,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { SourceLocation()) <= DiagnosticsEngine::Warning; - auto Listener = std::make_unique<ReadModuleNames>(*this); + auto Listener = std::make_unique<ReadModuleNames>(*PP); auto &ListenerRef = *Listener; ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader, std::move(Listener)); @@ -1620,7 +1747,8 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { // Try to load the module file. switch (TheASTReader->ReadAST( FileName, serialization::MK_ExplicitModule, SourceLocation(), - ConfigMismatchIsRecoverable ? ASTReader::ARR_ConfigurationMismatch : 0)) { + ConfigMismatchIsRecoverable ? ASTReader::ARR_ConfigurationMismatch : 0, + &LoadedModuleFile)) { case ASTReader::Success: // We successfully loaded the module file; remember the set of provided // modules so that we don't try to load implicit modules for them. @@ -1691,7 +1819,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( SourceLocation ModuleNameLoc, bool IsInclusionDirective) { // Search for a module with the given name. HeaderSearch &HS = PP->getHeaderSearchInfo(); - Module *M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + Module *M = + HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective); // Select the source and filename for loading the named module. std::string ModuleFilename; @@ -1750,7 +1879,7 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( // A prebuilt module is indexed as a ModuleFile; the Module does not exist // until the first call to ReadAST. Look it up now. - M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + M = HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective); // Check whether M refers to the file in the prebuilt module path. if (M && M->getASTFile()) @@ -1776,7 +1905,7 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( diag::warn_module_config_mismatch) << ModuleFilename; // Fall through to error out. - LLVM_FALLTHROUGH; + [[fallthrough]]; case ASTReader::VersionMismatch: case ASTReader::HadErrors: ModuleLoader::HadFatalFailure = true; @@ -1873,16 +2002,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. Module = PP->getHeaderSearchInfo().lookupModule( - ModuleName, /*AllowSearch*/ true, + ModuleName, ImportLoc, /*AllowSearch*/ true, /*AllowExtraModuleMapSearch*/ !IsInclusionDirective); - /// FIXME: perhaps we should (a) look for a module using the module name - // to file map (PrebuiltModuleFiles) and (b) diagnose if still not found? - //if (Module == nullptr) { - // getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - // << ModuleName; - // DisableGeneratingGlobalModuleIndex = true; - // return ModuleLoadResult(); - //} + MM.cacheModuleLoad(*Path[0].first, Module); } else { ModuleLoadResult Result = findOrCompileModuleAndReadAST( @@ -1903,90 +2025,88 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Verify that the rest of the module path actually corresponds to // a submodule. bool MapPrivateSubModToTopLevel = false; - 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); - - // If the user is requesting Foo.Private and it doesn't exist, try to - // match Foo_Private and emit a warning asking for the user to write - // @import Foo_Private instead. FIXME: remove this when existing clients - // migrate off of Foo.Private syntax. - if (!Sub && PP->getLangOpts().ImplicitModules && Name == "Private" && - Module == Module->getTopLevelModule()) { - SmallString<128> PrivateModule(Module->Name); - PrivateModule.append("_Private"); - - SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> PrivPath; - auto &II = PP->getIdentifierTable().get( - PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID()); - PrivPath.push_back(std::make_pair(&II, Path[0].second)); - - if (PP->getHeaderSearchInfo().lookupModule(PrivateModule, true, - !IsInclusionDirective)) - Sub = - loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective); - if (Sub) { - MapPrivateSubModToTopLevel = true; - if (!getDiagnostics().isIgnored( - diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) { - getDiagnostics().Report(Path[I].second, - diag::warn_no_priv_submodule_use_toplevel) - << Path[I].first << Module->getFullModuleName() << PrivateModule - << SourceRange(Path[0].second, Path[I].second) - << FixItHint::CreateReplacement(SourceRange(Path[0].second), - PrivateModule); - getDiagnostics().Report(Sub->DefinitionLoc, - diag::note_private_top_level_defined); - } + for (unsigned I = 1, N = Path.size(); I != N; ++I) { + StringRef Name = Path[I].first->getName(); + clang::Module *Sub = Module->findSubmodule(Name); + + // If the user is requesting Foo.Private and it doesn't exist, try to + // match Foo_Private and emit a warning asking for the user to write + // @import Foo_Private instead. FIXME: remove this when existing clients + // migrate off of Foo.Private syntax. + if (!Sub && Name == "Private" && Module == Module->getTopLevelModule()) { + SmallString<128> PrivateModule(Module->Name); + PrivateModule.append("_Private"); + + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> PrivPath; + auto &II = PP->getIdentifierTable().get( + PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID()); + PrivPath.push_back(std::make_pair(&II, Path[0].second)); + + std::string FileName; + // If there is a modulemap module or prebuilt module, load it. + if (PP->getHeaderSearchInfo().lookupModule(PrivateModule, ImportLoc, true, + !IsInclusionDirective) || + selectModuleSource(nullptr, PrivateModule, FileName, BuiltModules, + PP->getHeaderSearchInfo()) != MS_ModuleNotFound) + Sub = loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective); + if (Sub) { + MapPrivateSubModToTopLevel = true; + PP->markClangModuleAsAffecting(Module); + if (!getDiagnostics().isIgnored( + diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) { + getDiagnostics().Report(Path[I].second, + diag::warn_no_priv_submodule_use_toplevel) + << Path[I].first << Module->getFullModuleName() << PrivateModule + << SourceRange(Path[0].second, Path[I].second) + << FixItHint::CreateReplacement(SourceRange(Path[0].second), + PrivateModule); + getDiagnostics().Report(Sub->DefinitionLoc, + diag::note_private_top_level_defined); } } + } - if (!Sub) { - // Attempt to perform typo correction to find a module name that works. - SmallVector<StringRef, 2> Best; - unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)(); - - for (clang::Module::submodule_iterator J = Module->submodule_begin(), - JEnd = Module->submodule_end(); - J != JEnd; ++J) { - unsigned ED = Name.edit_distance((*J)->Name, - /*AllowReplacements=*/true, - BestEditDistance); - if (ED <= BestEditDistance) { - if (ED < BestEditDistance) { - Best.clear(); - BestEditDistance = ED; - } - - Best.push_back((*J)->Name); + if (!Sub) { + // Attempt to perform typo correction to find a module name that works. + SmallVector<StringRef, 2> Best; + unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)(); + + for (class Module *SubModule : Module->submodules()) { + unsigned ED = + Name.edit_distance(SubModule->Name, + /*AllowReplacements=*/true, BestEditDistance); + if (ED <= BestEditDistance) { + if (ED < BestEditDistance) { + Best.clear(); + BestEditDistance = ED; } + + Best.push_back(SubModule->Name); } + } - // If there was a clear winner, user it. - if (Best.size() == 1) { - getDiagnostics().Report(Path[I].second, - diag::err_no_submodule_suggest) + // If there was a clear winner, user it. + if (Best.size() == 1) { + getDiagnostics().Report(Path[I].second, diag::err_no_submodule_suggest) << Path[I].first << Module->getFullModuleName() << Best[0] - << SourceRange(Path[0].second, Path[I-1].second) + << SourceRange(Path[0].second, Path[I - 1].second) << FixItHint::CreateReplacement(SourceRange(Path[I].second), Best[0]); - Sub = Module->findSubmodule(Best[0]); - } + Sub = Module->findSubmodule(Best[0]); } + } - if (!Sub) { - // No submodule by this name. Complain, and don't look for further - // submodules. - getDiagnostics().Report(Path[I].second, diag::err_no_submodule) + if (!Sub) { + // No submodule by this name. Complain, and don't look for further + // submodules. + getDiagnostics().Report(Path[I].second, diag::err_no_submodule) << Path[I].first << Module->getFullModuleName() - << SourceRange(Path[0].second, Path[I-1].second); - break; - } - - Module = Sub; + << SourceRange(Path[0].second, Path[I - 1].second); + break; } + + Module = Sub; } // Make the named module visible, if it's not already part of the module @@ -2003,12 +2123,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, << Module->getFullModuleName() << SourceRange(Path.front().second, Path.back().second); - return ModuleLoadResult::MissingExpected; + return ModuleLoadResult(Module, ModuleLoadResult::MissingExpected); } // Check whether this module is available. if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(), - getDiagnostics(), Module)) { + *Module, getDiagnostics())) { getDiagnostics().Report(ImportLoc, diag::note_module_import_here) << SourceRange(Path.front().second, Path.back().second); LastModuleImportLoc = ImportLoc; @@ -2060,7 +2180,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, FrontendInputFile Input( ModuleMapFileName, - InputKind(getLanguageFromOptions(*Invocation->getLangOpts()), + InputKind(getLanguageFromOptions(Invocation->getLangOpts()), InputKind::ModuleMap, /*Preprocessed*/true)); std::string NullTerminatedSource(Source.str()); @@ -2068,11 +2188,10 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, 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( + FileEntryRef ModuleMapFile = Other.getFileManager().getVirtualFileRef( ModuleMapFileName, NullTerminatedSource.size(), 0); Other.getSourceManager().overrideFileContents( - ModuleMapFile, - llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str())); + ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource)); Other.BuiltModules = std::move(BuiltModules); Other.DeleteBuiltModules = false; @@ -2085,7 +2204,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, // Build the module, inheriting any modules that we've built locally. if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(), ModuleFileName, PreBuildStep, PostBuildStep)) { - BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName.str()); + BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName); llvm::sys::RemoveFileOnSignal(ModuleFileName); } } @@ -2141,7 +2260,7 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( for (ModuleMap::module_iterator I = MMap.module_begin(), E = MMap.module_end(); I != E; ++I) { Module *TheModule = I->second; - const FileEntry *Entry = TheModule->getASTFile(); + OptionalFileEntryRef Entry = TheModule->getASTFile(); if (!Entry) { SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; Path.push_back(std::make_pair( |