diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index f79b37ebfd50..cd3043d25919 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -1,817 +1,832 @@ //===-- CompilerInstance.h - Clang Compiler Instance ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_ #define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringRef.h" #include #include #include #include #include namespace llvm { class raw_fd_ostream; class Timer; class TimerGroup; } namespace clang { class ASTContext; class ASTReader; class CodeCompleteConsumer; class DiagnosticsEngine; class DiagnosticConsumer; class ExternalASTSource; class FileEntry; class FileManager; class FrontendAction; class MemoryBufferCache; class Module; class Preprocessor; class Sema; class SourceManager; class TargetInfo; /// CompilerInstance - Helper class for managing a single instance of the Clang /// compiler. /// /// The CompilerInstance serves two purposes: /// (1) It manages the various objects which are necessary to run the compiler, /// for example the preprocessor, the target information, and the AST /// context. /// (2) It provides utility routines for constructing and manipulating the /// common Clang objects. /// /// The compiler instance generally owns the instance of all the objects that it /// manages. However, clients can still share objects by manually setting the /// object and retaking ownership prior to destroying the CompilerInstance. /// /// The compiler instance is intended to simplify clients, but not to lock them /// in to the compiler instance for everything. When possible, utility functions /// come in two forms; a short form that reuses the CompilerInstance objects, /// and a long form that takes explicit instances of any required objects. class CompilerInstance : public ModuleLoader { /// The options used in this compiler instance. std::shared_ptr Invocation; /// The diagnostics engine instance. IntrusiveRefCntPtr Diagnostics; /// The target being compiled for. IntrusiveRefCntPtr Target; /// Auxiliary Target info. IntrusiveRefCntPtr AuxTarget; /// The virtual file system. IntrusiveRefCntPtr VirtualFileSystem; /// The file manager. IntrusiveRefCntPtr FileMgr; /// The source manager. IntrusiveRefCntPtr SourceMgr; /// The cache of PCM files. IntrusiveRefCntPtr PCMCache; /// The preprocessor. std::shared_ptr PP; /// The AST context. IntrusiveRefCntPtr Context; /// An optional sema source that will be attached to sema. IntrusiveRefCntPtr ExternalSemaSrc; /// The AST consumer. std::unique_ptr Consumer; /// The code completion consumer. std::unique_ptr CompletionConsumer; /// \brief The semantic analysis object. std::unique_ptr TheSema; /// \brief The frontend timer group. std::unique_ptr FrontendTimerGroup; /// \brief The frontend timer. std::unique_ptr FrontendTimer; /// \brief The ASTReader, if one exists. IntrusiveRefCntPtr ModuleManager; /// \brief The module dependency collector for crashdumps std::shared_ptr ModuleDepCollector; /// \brief The module provider. std::shared_ptr ThePCHContainerOperations; /// \brief The dependency file generator. std::unique_ptr TheDependencyFileGenerator; std::vector> DependencyCollectors; /// \brief The set of top-level modules that has already been loaded, /// along with the module map llvm::DenseMap KnownModules; /// \brief The set of top-level modules that has already been built on the /// fly as part of this overall compilation action. std::map BuiltModules; /// Should we delete the BuiltModules when we're done? bool DeleteBuiltModules = true; /// \brief The location of the module-import keyword for the last module /// import. SourceLocation LastModuleImportLoc; /// \brief The result of the last module import. /// ModuleLoadResult LastModuleImportResult; /// \brief Whether we should (re)build the global module index once we /// have finished with this translation unit. bool BuildGlobalModuleIndex = false; /// \brief We have a full global module index, with all modules. bool HaveFullGlobalModuleIndex = false; /// \brief One or more modules failed to build. bool ModuleBuildFailed = false; /// \brief Holds information about the output file. /// /// If TempFilename is not empty we must rename it to Filename at the end. /// TempFilename may be empty and Filename non-empty if creating the temporary /// failed. struct OutputFile { std::string Filename; std::string TempFilename; OutputFile(std::string filename, std::string tempFilename) : Filename(std::move(filename)), TempFilename(std::move(tempFilename)) { } }; /// If the output doesn't support seeking (terminal, pipe). we switch /// the stream to a buffer_ostream. These are the buffer and the original /// stream. std::unique_ptr NonSeekStream; /// The list of active output files. std::list OutputFiles; + /// \brief An optional callback function used to wrap all FrontendActions + /// produced to generate imported modules before they are executed. + std::function + (const FrontendOptions &opts, std::unique_ptr action)> + GenModuleActionWrapper; + CompilerInstance(const CompilerInstance &) = delete; void operator=(const CompilerInstance &) = delete; public: explicit CompilerInstance( std::shared_ptr PCHContainerOps = std::make_shared(), MemoryBufferCache *SharedPCMCache = nullptr); ~CompilerInstance() override; /// @name High-Level Operations /// { /// ExecuteAction - Execute the provided action against the compiler's /// CompilerInvocation object. /// /// This function makes the following assumptions: /// /// - The invocation options should be initialized. This function does not /// handle the '-help' or '-version' options, clients should handle those /// directly. /// /// - The diagnostics engine should have already been created by the client. /// /// - No other CompilerInstance state should have been initialized (this is /// an unchecked error). /// /// - Clients should have initialized any LLVM target features that may be /// required. /// /// - Clients should eventually call llvm_shutdown() upon the completion of /// this routine to ensure that any managed objects are properly destroyed. /// /// Note that this routine may write output to 'stderr'. /// /// \param Act - The action to execute. /// \return - True on success. // // FIXME: This function should take the stream to write any debugging / // verbose output to as an argument. // // FIXME: Eliminate the llvm_shutdown requirement, that should either be part // of the context or else not CompilerInstance specific. bool ExecuteAction(FrontendAction &Act); /// } /// @name Compiler Invocation and Options /// { bool hasInvocation() const { return Invocation != nullptr; } CompilerInvocation &getInvocation() { assert(Invocation && "Compiler instance has no invocation!"); return *Invocation; } /// setInvocation - Replace the current invocation. void setInvocation(std::shared_ptr Value); /// \brief Indicates whether we should (re)build the global module index. bool shouldBuildGlobalModuleIndex() const; /// \brief Set the flag indicating whether we should (re)build the global /// module index. void setBuildGlobalModuleIndex(bool Build) { BuildGlobalModuleIndex = Build; } /// } /// @name Forwarding Methods /// { AnalyzerOptionsRef getAnalyzerOpts() { return Invocation->getAnalyzerOpts(); } CodeGenOptions &getCodeGenOpts() { return Invocation->getCodeGenOpts(); } const CodeGenOptions &getCodeGenOpts() const { return Invocation->getCodeGenOpts(); } DependencyOutputOptions &getDependencyOutputOpts() { return Invocation->getDependencyOutputOpts(); } const DependencyOutputOptions &getDependencyOutputOpts() const { return Invocation->getDependencyOutputOpts(); } DiagnosticOptions &getDiagnosticOpts() { return Invocation->getDiagnosticOpts(); } const DiagnosticOptions &getDiagnosticOpts() const { return Invocation->getDiagnosticOpts(); } FileSystemOptions &getFileSystemOpts() { return Invocation->getFileSystemOpts(); } const FileSystemOptions &getFileSystemOpts() const { return Invocation->getFileSystemOpts(); } FrontendOptions &getFrontendOpts() { return Invocation->getFrontendOpts(); } const FrontendOptions &getFrontendOpts() const { return Invocation->getFrontendOpts(); } HeaderSearchOptions &getHeaderSearchOpts() { return Invocation->getHeaderSearchOpts(); } const HeaderSearchOptions &getHeaderSearchOpts() const { return Invocation->getHeaderSearchOpts(); } std::shared_ptr getHeaderSearchOptsPtr() const { return Invocation->getHeaderSearchOptsPtr(); } APINotesOptions &getAPINotesOpts() { return Invocation->getAPINotesOpts(); } const APINotesOptions &getAPINotesOpts() const { return Invocation->getAPINotesOpts(); } LangOptions &getLangOpts() { return *Invocation->getLangOpts(); } const LangOptions &getLangOpts() const { return *Invocation->getLangOpts(); } PreprocessorOptions &getPreprocessorOpts() { return Invocation->getPreprocessorOpts(); } const PreprocessorOptions &getPreprocessorOpts() const { return Invocation->getPreprocessorOpts(); } PreprocessorOutputOptions &getPreprocessorOutputOpts() { return Invocation->getPreprocessorOutputOpts(); } const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { return Invocation->getPreprocessorOutputOpts(); } TargetOptions &getTargetOpts() { return Invocation->getTargetOpts(); } const TargetOptions &getTargetOpts() const { return Invocation->getTargetOpts(); } /// } /// @name Diagnostics Engine /// { bool hasDiagnostics() const { return Diagnostics != nullptr; } /// Get the current diagnostics engine. DiagnosticsEngine &getDiagnostics() const { assert(Diagnostics && "Compiler instance has no diagnostics!"); return *Diagnostics; } /// setDiagnostics - Replace the current diagnostics engine. void setDiagnostics(DiagnosticsEngine *Value); DiagnosticConsumer &getDiagnosticClient() const { assert(Diagnostics && Diagnostics->getClient() && "Compiler instance has no diagnostic client!"); return *Diagnostics->getClient(); } /// } /// @name Target Info /// { bool hasTarget() const { return Target != nullptr; } TargetInfo &getTarget() const { assert(Target && "Compiler instance has no target!"); return *Target; } /// Replace the current Target. void setTarget(TargetInfo *Value); /// } /// @name AuxTarget Info /// { TargetInfo *getAuxTarget() const { return AuxTarget.get(); } /// Replace the current AuxTarget. void setAuxTarget(TargetInfo *Value); /// } /// @name Virtual File System /// { bool hasVirtualFileSystem() const { return VirtualFileSystem != nullptr; } vfs::FileSystem &getVirtualFileSystem() const { assert(hasVirtualFileSystem() && "Compiler instance has no virtual file system"); return *VirtualFileSystem; } /// \brief Replace the current virtual file system. /// /// \note Most clients should use setFileManager, which will implicitly reset /// the virtual file system to the one contained in the file manager. void setVirtualFileSystem(IntrusiveRefCntPtr FS) { VirtualFileSystem = std::move(FS); } /// } /// @name File Manager /// { bool hasFileManager() const { return FileMgr != nullptr; } /// Return the current file manager to the caller. FileManager &getFileManager() const { assert(FileMgr && "Compiler instance has no file manager!"); return *FileMgr; } void resetAndLeakFileManager() { BuryPointer(FileMgr.get()); FileMgr.resetWithoutRelease(); } /// \brief Replace the current file manager and virtual file system. void setFileManager(FileManager *Value); /// } /// @name Source Manager /// { bool hasSourceManager() const { return SourceMgr != nullptr; } /// Return the current source manager. SourceManager &getSourceManager() const { assert(SourceMgr && "Compiler instance has no source manager!"); return *SourceMgr; } void resetAndLeakSourceManager() { BuryPointer(SourceMgr.get()); SourceMgr.resetWithoutRelease(); } /// setSourceManager - Replace the current source manager. void setSourceManager(SourceManager *Value); /// } /// @name Preprocessor /// { bool hasPreprocessor() const { return PP != nullptr; } /// Return the current preprocessor. Preprocessor &getPreprocessor() const { assert(PP && "Compiler instance has no preprocessor!"); return *PP; } std::shared_ptr getPreprocessorPtr() { return PP; } void resetAndLeakPreprocessor() { BuryPointer(new std::shared_ptr(PP)); } /// Replace the current preprocessor. void setPreprocessor(std::shared_ptr Value); /// } /// @name ASTContext /// { bool hasASTContext() const { return Context != nullptr; } ASTContext &getASTContext() const { assert(Context && "Compiler instance has no AST context!"); return *Context; } void resetAndLeakASTContext() { BuryPointer(Context.get()); Context.resetWithoutRelease(); } /// setASTContext - Replace the current AST context. void setASTContext(ASTContext *Value); /// \brief Replace the current Sema; the compiler instance takes ownership /// of S. void setSema(Sema *S); /// } /// @name ASTConsumer /// { bool hasASTConsumer() const { return (bool)Consumer; } ASTConsumer &getASTConsumer() const { assert(Consumer && "Compiler instance has no AST consumer!"); return *Consumer; } /// takeASTConsumer - Remove the current AST consumer and give ownership to /// the caller. std::unique_ptr takeASTConsumer() { return std::move(Consumer); } /// setASTConsumer - Replace the current AST consumer; the compiler instance /// takes ownership of \p Value. void setASTConsumer(std::unique_ptr Value); /// } /// @name Semantic analysis /// { bool hasSema() const { return (bool)TheSema; } Sema &getSema() const { assert(TheSema && "Compiler instance has no Sema object!"); return *TheSema; } std::unique_ptr takeSema(); void resetAndLeakSema(); /// } /// @name Module Management /// { IntrusiveRefCntPtr getModuleManager() const; void setModuleManager(IntrusiveRefCntPtr Reader); std::shared_ptr getModuleDepCollector() const; void setModuleDepCollector( std::shared_ptr Collector); std::shared_ptr getPCHContainerOperations() const { return ThePCHContainerOperations; } /// Return the appropriate PCHContainerWriter depending on the /// current CodeGenOptions. const PCHContainerWriter &getPCHContainerWriter() const { assert(Invocation && "cannot determine module format without invocation"); StringRef Format = getHeaderSearchOpts().ModuleFormat; auto *Writer = ThePCHContainerOperations->getWriterOrNull(Format); if (!Writer) { if (Diagnostics) Diagnostics->Report(diag::err_module_format_unhandled) << Format; llvm::report_fatal_error("unknown module format"); } return *Writer; } /// Return the appropriate PCHContainerReader depending on the /// current CodeGenOptions. const PCHContainerReader &getPCHContainerReader() const { assert(Invocation && "cannot determine module format without invocation"); StringRef Format = getHeaderSearchOpts().ModuleFormat; auto *Reader = ThePCHContainerOperations->getReaderOrNull(Format); if (!Reader) { if (Diagnostics) Diagnostics->Report(diag::err_module_format_unhandled) << Format; llvm::report_fatal_error("unknown module format"); } return *Reader; } /// } /// @name Code Completion /// { bool hasCodeCompletionConsumer() const { return (bool)CompletionConsumer; } CodeCompleteConsumer &getCodeCompletionConsumer() const { assert(CompletionConsumer && "Compiler instance has no code completion consumer!"); return *CompletionConsumer; } /// setCodeCompletionConsumer - Replace the current code completion consumer; /// the compiler instance takes ownership of \p Value. void setCodeCompletionConsumer(CodeCompleteConsumer *Value); /// } /// @name Frontend timer /// { bool hasFrontendTimer() const { return (bool)FrontendTimer; } llvm::Timer &getFrontendTimer() const { assert(FrontendTimer && "Compiler instance has no frontend timer!"); return *FrontendTimer; } /// } /// @name Output Files /// { /// addOutputFile - Add an output file onto the list of tracked output files. /// /// \param OutFile - The output file info. void addOutputFile(OutputFile &&OutFile); /// clearOutputFiles - Clear the output file list. The underlying output /// streams must have been closed beforehand. /// /// \param EraseFiles - If true, attempt to erase the files from disk. void clearOutputFiles(bool EraseFiles); /// } /// @name Construction Utility Methods /// { /// Create the diagnostics engine using the invocation's diagnostic options /// and replace any existing one with it. /// /// Note that this routine also replaces the diagnostic client, /// allocating one if one is not provided. /// /// \param Client If non-NULL, a diagnostic client that will be /// attached to (and, then, owned by) the DiagnosticsEngine inside this AST /// unit. /// /// \param ShouldOwnClient If Client is non-NULL, specifies whether /// the diagnostic object should take ownership of the client. void createDiagnostics(DiagnosticConsumer *Client = nullptr, bool ShouldOwnClient = true); /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter. /// /// If no diagnostic client is provided, this creates a /// DiagnosticConsumer that is owned by the returned diagnostic /// object, if using directly the caller is responsible for /// releasing the returned DiagnosticsEngine's client eventually. /// /// \param Opts - The diagnostic options; note that the created text /// diagnostic object contains a reference to these options. /// /// \param Client If non-NULL, a diagnostic client that will be /// attached to (and, then, owned by) the returned DiagnosticsEngine /// object. /// /// \param CodeGenOpts If non-NULL, the code gen options in use, which may be /// used by some diagnostics printers (for logging purposes only). /// /// \return The new object on success, or null on failure. static IntrusiveRefCntPtr createDiagnostics(DiagnosticOptions *Opts, DiagnosticConsumer *Client = nullptr, bool ShouldOwnClient = true, const CodeGenOptions *CodeGenOpts = nullptr); /// Create the file manager and replace any existing one with it. /// /// \return The new file manager on success, or null on failure. FileManager *createFileManager(); /// Create the source manager and replace any existing one with it. void createSourceManager(FileManager &FileMgr); /// Create the preprocessor, using the invocation, file, and source managers, /// and replace any existing one with it. void createPreprocessor(TranslationUnitKind TUKind); std::string getSpecificModuleCachePath(); /// Create the AST context. void createASTContext(); /// Create an external AST source to read a PCH file and attach it to the AST /// context. void createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, void *DeserializationListener, bool OwnDeserializationListener); /// Create an external AST source to read a PCH file. /// /// \return - The new object on success, or null on failure. static IntrusiveRefCntPtr createPCHExternalASTSource( StringRef Path, StringRef Sysroot, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerReader &PCHContainerRdr, ArrayRef> Extensions, DependencyFileGenerator *DependencyFile, ArrayRef> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex); /// Create a code completion consumer using the invocation; note that this /// will cause the source manager to truncate the input source file at the /// completion point. void createCodeCompletionConsumer(); /// Create a code completion consumer to print code completion results, at /// \p Filename, \p Line, and \p Column, to the given output stream \p OS. static CodeCompleteConsumer *createCodeCompletionConsumer( Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column, const CodeCompleteOptions &Opts, raw_ostream &OS); /// \brief Create the Sema object to be used for parsing. void createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer); /// Create the frontend timer and replace any existing one with it. void createFrontendTimer(); /// Create the default output file (from the invocation's options) and add it /// to the list of tracked output files. /// /// The files created by this function always use temporary files to write to /// their result (that is, the data is written to a temporary file which will /// atomically replace the target output on success). /// /// \return - Null on error. std::unique_ptr createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "", StringRef Extension = ""); /// Create a new output file and add it to the list of tracked output files, /// optionally deriving the output path name. /// /// \return - Null on error. std::unique_ptr createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, StringRef BaseInput, StringRef Extension, bool UseTemporary, bool CreateMissingDirectories = false); /// Create a new output file, optionally deriving the output path name. /// /// If \p OutputPath is empty, then createOutputFile will derive an output /// path location as \p BaseInput, with any suffix removed, and \p Extension /// appended. If \p OutputPath is not stdout and \p UseTemporary /// is true, createOutputFile will create a new temporary file that must be /// renamed to \p OutputPath in the end. /// /// \param OutputPath - If given, the path to the output file. /// \param Error [out] - On failure, the error. /// \param BaseInput - If \p OutputPath is empty, the input path name to use /// for deriving the output path. /// \param Extension - The extension to use for derived output names. /// \param Binary - The mode to open the file in. /// \param RemoveFileOnSignal - Whether the file should be registered with /// llvm::sys::RemoveFileOnSignal. Note that this is not safe for /// multithreaded use, as the underlying signal mechanism is not reentrant /// \param UseTemporary - Create a new temporary file that must be renamed to /// OutputPath in the end. /// \param CreateMissingDirectories - When \p UseTemporary is true, create /// missing directories in the output path. /// \param ResultPathName [out] - If given, the result path name will be /// stored here on success. /// \param TempPathName [out] - If given, the temporary file path name /// will be stored here on success. std::unique_ptr createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary, bool RemoveFileOnSignal, StringRef BaseInput, StringRef Extension, bool UseTemporary, bool CreateMissingDirectories, std::string *ResultPathName, std::string *TempPathName); std::unique_ptr createNullOutputFile(); /// } /// @name Initialization Utility Methods /// { /// InitializeSourceManager - Initialize the source manager to set InputFile /// as the main file. /// /// \return True on success. bool InitializeSourceManager(const FrontendInputFile &Input); /// InitializeSourceManager - Initialize the source manager to set InputFile /// as the main file. /// /// \return True on success. static bool InitializeSourceManager(const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS, DependencyOutputOptions &DepOpts, const FrontendOptions &Opts); /// } // Create module manager. void createModuleManager(); bool loadModuleFile(StringRef FileName); ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override; void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, StringRef Source) override; void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) override; bool hadModuleLoaderFatalFailure() const { return ModuleLoader::HadFatalFailure; } GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override; bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override; + void setGenModuleActionWrapper(std::function + (const FrontendOptions &Opts, std::unique_ptr Action)> Wrapper) { + GenModuleActionWrapper = Wrapper; + }; + + std::function + (const FrontendOptions &Opts, std::unique_ptr Action)> + getGenModuleActionWrapper() const { return GenModuleActionWrapper; } + void addDependencyCollector(std::shared_ptr Listener) { DependencyCollectors.push_back(std::move(Listener)); } void setExternalSemaSource(IntrusiveRefCntPtr ESS); MemoryBufferCache &getPCMCache() const { return *PCMCache; } }; } // end namespace clang #endif diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index 9f4f7d316cee..da6a1616009b 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -1,65 +1,65 @@ add_subdirectory(Rewrite) set(LLVM_LINK_COMPONENTS BitReader Option ProfileData Support ) set(optional_deps intrinsics_gen) if (CLANG_BUILT_STANDALONE) set(optional_deps) endif() add_clang_library(clangFrontend ASTConsumers.cpp ASTMerge.cpp ASTUnit.cpp CacheTokens.cpp ChainedDiagnosticConsumer.cpp ChainedIncludesSource.cpp CodeGenOptions.cpp CompilerInstance.cpp CompilerInvocation.cpp CreateInvocationFromCommandLine.cpp DependencyFile.cpp DependencyGraph.cpp DiagnosticRenderer.cpp FrontendAction.cpp FrontendActions.cpp FrontendOptions.cpp HeaderIncludeGen.cpp InitHeaderSearch.cpp InitPreprocessor.cpp LangStandards.cpp LayoutOverrideSource.cpp LogDiagnosticPrinter.cpp ModuleDependencyCollector.cpp MultiplexConsumer.cpp PCHContainerOperations.cpp PrecompiledPreamble.cpp PrintPreprocessedOutput.cpp SerializedDiagnosticPrinter.cpp SerializedDiagnosticReader.cpp TestModuleFileExtension.cpp TextDiagnostic.cpp TextDiagnosticBuffer.cpp TextDiagnosticPrinter.cpp VerifyDiagnosticConsumer.cpp DEPENDS ClangDriverOptions ${optional_deps} LINK_LIBS + clangAPINotes clangAST clangBasic clangDriver clangEdit - clangIndex clangLex clangParse clangSema clangSerialization ) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index d38d9e8b15ba..7b5108157bce 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1,2136 +1,2136 @@ //===--- CompilerInstance.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInstance.h" #include "clang/APINotes/APINotesReader.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/MemoryBufferCache.h" #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" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" #include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Index/IndexingAction.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PTHManager.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #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/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" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include using namespace clang; CompilerInstance::CompilerInstance( std::shared_ptr PCHContainerOps, MemoryBufferCache *SharedPCMCache) : ModuleLoader(/* BuildingModule = */ SharedPCMCache), Invocation(new CompilerInvocation()), PCMCache(SharedPCMCache ? SharedPCMCache : new MemoryBufferCache), ThePCHContainerOperations(std::move(PCHContainerOps)) { // Don't allow this to invalidate buffers in use by others. if (SharedPCMCache) getPCMCache().finalizeCurrentBuffers(); } CompilerInstance::~CompilerInstance() { assert(OutputFiles.empty() && "Still output files in flight?"); } void CompilerInstance::setInvocation( std::shared_ptr Value) { Invocation = std::move(Value); } bool CompilerInstance::shouldBuildGlobalModuleIndex() const { return (BuildGlobalModuleIndex || (ModuleManager && ModuleManager->isGlobalIndexUnavailable() && getFrontendOpts().GenerateGlobalModuleIndex)) && !ModuleBuildFailed; } void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) { Diagnostics = Value; } void CompilerInstance::setTarget(TargetInfo *Value) { Target = Value; } void CompilerInstance::setAuxTarget(TargetInfo *Value) { AuxTarget = Value; } void CompilerInstance::setFileManager(FileManager *Value) { FileMgr = Value; if (Value) VirtualFileSystem = Value->getVirtualFileSystem(); else VirtualFileSystem.reset(); } void CompilerInstance::setSourceManager(SourceManager *Value) { SourceMgr = Value; } void CompilerInstance::setPreprocessor(std::shared_ptr Value) { PP = std::move(Value); } void CompilerInstance::setASTContext(ASTContext *Value) { Context = Value; if (Context && Consumer) getASTConsumer().Initialize(getASTContext()); } void CompilerInstance::setSema(Sema *S) { TheSema.reset(S); } void CompilerInstance::setASTConsumer(std::unique_ptr Value) { Consumer = std::move(Value); if (Context && Consumer) getASTConsumer().Initialize(getASTContext()); } void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { CompletionConsumer.reset(Value); } std::unique_ptr CompilerInstance::takeSema() { return std::move(TheSema); } IntrusiveRefCntPtr CompilerInstance::getModuleManager() const { return ModuleManager; } void CompilerInstance::setModuleManager(IntrusiveRefCntPtr Reader) { assert(PCMCache.get() == &Reader->getModuleManager().getPCMCache() && "Expected ASTReader to use the same PCM cache"); ModuleManager = std::move(Reader); } std::shared_ptr CompilerInstance::getModuleDepCollector() const { return ModuleDepCollector; } void CompilerInstance::setModuleDepCollector( std::shared_ptr Collector) { ModuleDepCollector = std::move(Collector); } static void collectHeaderMaps(const HeaderSearch &HS, std::shared_ptr MDC) { SmallVector HeaderMapFileNames; HS.getHeaderMapFileNames(HeaderMapFileNames); for (auto &Name : HeaderMapFileNames) MDC->addFile(Name); } static void collectIncludePCH(CompilerInstance &CI, std::shared_ptr MDC) { const PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); if (PPOpts.ImplicitPCHInclude.empty()) return; StringRef PCHInclude = PPOpts.ImplicitPCHInclude; FileManager &FileMgr = CI.getFileManager(); const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude); if (!PCHDir) { MDC->addFile(PCHInclude); return; } std::error_code EC; SmallString<128> DirNative; llvm::sys::path::native(PCHDir->getName(), DirNative); vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); SimpleASTReaderListener Validator(CI.getPreprocessor()); for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { // Check whether this is an AST file. ASTReader::isAcceptableASTFile is not // 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->getName(), FileMgr, CI.getPCHContainerReader(), /*FindModuleFileExtensions=*/false, Validator, /*ValidateDiagnosticOptions=*/false)) MDC->addFile(Dir->getName()); } } static void collectVFSEntries(CompilerInstance &CI, std::shared_ptr MDC) { if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) return; // Collect all VFS found. SmallVector VFSEntries; for (const std::string &VFSFile : CI.getHeaderSearchOpts().VFSOverlayFiles) { llvm::ErrorOr> Buffer = llvm::MemoryBuffer::getFile(VFSFile); if (!Buffer) return; vfs::collectVFSFromYAML(std::move(Buffer.get()), /*DiagHandler*/ nullptr, VFSFile, VFSEntries); } for (auto &E : VFSEntries) MDC->addFile(E.VPath, E.RPath); } // Diagnostics static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, const CodeGenOptions *CodeGenOpts, DiagnosticsEngine &Diags) { std::error_code EC; std::unique_ptr StreamOwner; raw_ostream *OS = &llvm::errs(); if (DiagOpts->DiagnosticLogFile != "-") { // Create the output stream. auto FileOS = llvm::make_unique( DiagOpts->DiagnosticLogFile, EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text); if (EC) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) << DiagOpts->DiagnosticLogFile << EC.message(); } else { FileOS->SetUnbuffered(); OS = FileOS.get(); StreamOwner = std::move(FileOS); } } // Chain in the diagnostic client which will log the diagnostics. auto Logger = llvm::make_unique(*OS, DiagOpts, std::move(StreamOwner)); if (CodeGenOpts) Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags); assert(Diags.ownsClient()); Diags.setClient( new ChainedDiagnosticConsumer(Diags.takeClient(), std::move(Logger))); } static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, DiagnosticsEngine &Diags, StringRef OutputFile) { auto SerializedConsumer = clang::serialized_diags::create(OutputFile, DiagOpts); if (Diags.ownsClient()) { Diags.setClient(new ChainedDiagnosticConsumer( Diags.takeClient(), std::move(SerializedConsumer))); } else { Diags.setClient(new ChainedDiagnosticConsumer( Diags.getClient(), std::move(SerializedConsumer))); } } void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client, bool ShouldOwnClient) { Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, ShouldOwnClient, &getCodeGenOpts()); } IntrusiveRefCntPtr CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, DiagnosticConsumer *Client, bool ShouldOwnClient, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr Diags(new DiagnosticsEngine(DiagID, Opts)); // Create the diagnostic client for reporting errors or for // implementing -verify. if (Client) { Diags->setClient(Client, ShouldOwnClient); } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. if (Opts->VerifyDiagnostics) Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. if (!Opts->DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); if (!Opts->DiagnosticSerializationFile.empty()) SetupSerializedDiagnostics(Opts, *Diags, Opts->DiagnosticSerializationFile); // Configure our handling of diagnostics. ProcessWarningOptions(*Diags, *Opts); return Diags; } // File Manager FileManager *CompilerInstance::createFileManager() { if (!hasVirtualFileSystem()) { if (IntrusiveRefCntPtr VFS = createVFSFromCompilerInvocation(getInvocation(), getDiagnostics())) setVirtualFileSystem(VFS); else return nullptr; } FileMgr = new FileManager(getFileSystemOpts(), VirtualFileSystem); return FileMgr.get(); } // Source Manager 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(TranslationUnitKind TUKind) { const PreprocessorOptions &PPOpts = getPreprocessorOpts(); // Create a PTH manager if we are using some form of a token cache. PTHManager *PTHMgr = nullptr; if (!PPOpts.TokenCache.empty()) PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); // Create the Preprocessor. HeaderSearch *HeaderInfo = new HeaderSearch(getHeaderSearchOptsPtr(), getSourceManager(), getDiagnostics(), getLangOpts(), &getTarget()); PP = std::make_shared( Invocation->getPreprocessorOptsPtr(), getDiagnostics(), getLangOpts(), getSourceManager(), getPCMCache(), *HeaderInfo, *this, PTHMgr, /*OwnsHeaderSearch=*/true, TUKind); PP->Initialize(getTarget(), getAuxTarget()); // Note that this is different then passing PTHMgr to Preprocessor's ctor. // That argument is used as the IdentifierInfoLookup argument to // IdentifierTable's ctor. if (PTHMgr) { PTHMgr->setPreprocessor(&*PP); PP->setPTHManager(PTHMgr); } if (PPOpts.DetailedRecord) PP->createPreprocessingRecord(); // Apply remappings to the source manager. InitializeFileRemapping(PP->getDiagnostics(), PP->getSourceManager(), PP->getFileManager(), PPOpts); // Predefine macros and configure the preprocessor. InitializePreprocessor(*PP, PPOpts, getPCHContainerReader(), getFrontendOpts()); // 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 // find the host headers in order to compile the CUDA code. const llvm::Triple *HeaderSearchTriple = &PP->getTargetInfo().getTriple(); if (PP->getTargetInfo().getTriple().getOS() == llvm::Triple::CUDA && PP->getAuxTargetInfo()) HeaderSearchTriple = &PP->getAuxTargetInfo()->getTriple(); ApplyHeaderSearchOptions(PP->getHeaderSearchInfo(), getHeaderSearchOpts(), PP->getLangOpts(), *HeaderSearchTriple); PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP); if (PP->getLangOpts().Modules && PP->getLangOpts().ImplicitModules) PP->getHeaderSearchInfo().setModuleCachePath(getSpecificModuleCachePath()); // Handle generating dependencies, if requested. const DependencyOutputOptions &DepOpts = getDependencyOutputOpts(); if (!DepOpts.OutputFile.empty()) TheDependencyFileGenerator.reset( DependencyFileGenerator::CreateAndAttachToPreprocessor(*PP, DepOpts)); if (!DepOpts.DOTOutputFile.empty()) AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile, getHeaderSearchOpts().Sysroot); // 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( DepOpts.ModuleDependencyOutputDir); } // If there is a module dep collector, register with other dep collectors // and also (a) collect header maps and (b) TODO: input vfs overlay files. if (ModuleDepCollector) { addDependencyCollector(ModuleDepCollector); collectHeaderMaps(PP->getHeaderSearchInfo(), ModuleDepCollector); collectIncludePCH(*this, ModuleDepCollector); collectVFSEntries(*this, ModuleDepCollector); } for (auto &Listener : DependencyCollectors) Listener->attachToPreprocessor(*PP); // Handle generating header include information, if requested. if (DepOpts.ShowHeaderIncludes) AttachHeaderIncludeGen(*PP, DepOpts); if (!DepOpts.HeaderIncludeOutputFile.empty()) { StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; if (OutputPath == "-") OutputPath = ""; AttachHeaderIncludeGen(*PP, DepOpts, /*ShowAllHeaders=*/true, OutputPath, /*ShowDepth=*/false); } if (DepOpts.PrintShowIncludes) { AttachHeaderIncludeGen(*PP, DepOpts, /*ShowAllHeaders=*/true, /*OutputPath=*/"", /*ShowDepth=*/true, /*MSStyle=*/true); } } std::string CompilerInstance::getSpecificModuleCachePath() { // Set up the module path, including the hash for the // module-creation options. SmallString<256> SpecificModuleCache(getHeaderSearchOpts().ModuleCachePath); if (!SpecificModuleCache.empty() && !getHeaderSearchOpts().DisableModuleHash) llvm::sys::path::append(SpecificModuleCache, getInvocation().getModuleHash(getDiagnostics())); return SpecificModuleCache.str(); } // ASTContext void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); auto *Context = new ASTContext(getLangOpts(), PP.getSourceManager(), PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo()); Context->InitBuiltinTypes(getTarget(), getAuxTarget()); setASTContext(Context); } // ExternalASTSource void CompilerInstance::createPCHExternalASTSource( StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, void *DeserializationListener, bool OwnDeserializationListener) { bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; ModuleManager = createPCHExternalASTSource( Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, TheDependencyFileGenerator.get(), DependencyCollectors, DeserializationListener, OwnDeserializationListener, Preamble, getFrontendOpts().UseGlobalModuleIndex); } IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( StringRef Path, StringRef Sysroot, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerReader &PCHContainerRdr, ArrayRef> Extensions, DependencyFileGenerator *DependencyFile, ArrayRef> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex) { HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); IntrusiveRefCntPtr Reader(new ASTReader( PP, &Context, PCHContainerRdr, Extensions, Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); // We need the external source to be set up before we read the AST, because // eagerly-deserialized declarations may use it. Context.setExternalSource(Reader.get()); Reader->setDeserializationListener( static_cast(DeserializationListener), /*TakeOwnership=*/OwnDeserializationListener); if (DependencyFile) DependencyFile->AttachToASTReader(*Reader); for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*Reader); switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); return Reader; case ASTReader::Failure: // Unrecoverable failure: don't even try to process the input file. break; case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: case ASTReader::HadErrors: // No suitable PCH file could be found. Return an error. break; } Context.setExternalSource(nullptr); return nullptr; } // Code Completion static bool EnableCodeCompletion(Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column) { // Tell the source manager to chop off the given file at a specific // line and column. const FileEntry *Entry = PP.getFileManager().getFile(Filename); if (!Entry) { PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) << Filename; return true; } // Truncate the named file at the given line/column. PP.SetCodeCompletionPoint(Entry, Line, Column); return false; } 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; } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column)) { setCodeCompletionConsumer(nullptr); return; } if (CompletionConsumer->isOutputBinary() && llvm::sys::ChangeStdoutToBinary()) { getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); setCodeCompletionConsumer(nullptr); } } void CompilerInstance::createFrontendTimer() { FrontendTimerGroup.reset( new llvm::TimerGroup("frontend", "Clang front-end time report")); FrontendTimer.reset( new llvm::Timer("frontend", "Clang front-end timer", *FrontendTimerGroup)); } CodeCompleteConsumer * CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column, const CodeCompleteOptions &Opts, raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) return nullptr; // Set up the creation routine for code-completion. return new PrintingCodeCompleteConsumer(Opts, OS); } 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); // 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); // Check for any attributes we should add to the module for (auto reader : TheSema->APINotes.getCurrentModuleReaders()) { // swift_infer_import_as_member if (reader->getModuleOptions().SwiftInferImportAsMember) { currentModule->IsSwiftInferImportAsMember = true; break; } } } // Attach the external sema source if there is any. if (ExternalSemaSrc) { TheSema->addExternalSource(ExternalSemaSrc.get()); ExternalSemaSrc->InitializeSema(*TheSema); } } // Output Files void CompilerInstance::addOutputFile(OutputFile &&OutFile) { OutputFiles.push_back(std::move(OutFile)); } void CompilerInstance::clearOutputFiles(bool EraseFiles) { for (OutputFile &OF : OutputFiles) { if (!OF.TempFilename.empty()) { if (EraseFiles) { llvm::sys::fs::remove(OF.TempFilename); } else { SmallString<128> NewOutFile(OF.Filename); // If '-working-directory' was passed, the output filename should be // relative to that. FileMgr->FixupRelativePath(NewOutFile); if (std::error_code ec = llvm::sys::fs::rename(OF.TempFilename, NewOutFile)) { getDiagnostics().Report(diag::err_unable_to_rename_temp) << OF.TempFilename << OF.Filename << ec.message(); llvm::sys::fs::remove(OF.TempFilename); } } } else if (!OF.Filename.empty() && EraseFiles) llvm::sys::fs::remove(OF.Filename); } OutputFiles.clear(); if (DeleteBuiltModules) { for (auto &Module : BuiltModules) llvm::sys::fs::remove(Module.second); BuiltModules.clear(); } NonSeekStream.reset(); } std::unique_ptr CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile, StringRef Extension) { return createOutputFile(getFrontendOpts().OutputFile, Binary, /*RemoveFileOnSignal=*/true, InFile, Extension, /*UseTemporary=*/true); } std::unique_ptr CompilerInstance::createNullOutputFile() { return llvm::make_unique(); } std::unique_ptr CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, StringRef InFile, StringRef Extension, bool UseTemporary, bool CreateMissingDirectories) { std::string OutputPathName, TempPathName; std::error_code EC; std::unique_ptr OS = createOutputFile( OutputPath, EC, Binary, RemoveFileOnSignal, InFile, Extension, UseTemporary, CreateMissingDirectories, &OutputPathName, &TempPathName); if (!OS) { getDiagnostics().Report(diag::err_fe_unable_to_open_output) << OutputPath << EC.message(); return nullptr; } // Add the output file -- but don't try to remove "-", since this means we are // using stdin. addOutputFile( OutputFile((OutputPathName != "-") ? OutputPathName : "", TempPathName)); return OS; } std::unique_ptr CompilerInstance::createOutputFile( StringRef OutputPath, std::error_code &Error, bool Binary, bool RemoveFileOnSignal, StringRef InFile, StringRef Extension, bool UseTemporary, bool CreateMissingDirectories, std::string *ResultPathName, std::string *TempPathName) { assert((!CreateMissingDirectories || UseTemporary) && "CreateMissingDirectories is only allowed when using temporary files"); std::string OutFile, TempFile; if (!OutputPath.empty()) { OutFile = OutputPath; } else if (InFile == "-") { OutFile = "-"; } else if (!Extension.empty()) { SmallString<128> Path(InFile); llvm::sys::path::replace_extension(Path, Extension); OutFile = Path.str(); } else { OutFile = "-"; } std::unique_ptr OS; std::string OSFile; if (UseTemporary) { if (OutFile == "-") UseTemporary = false; else { llvm::sys::fs::file_status Status; llvm::sys::fs::status(OutputPath, Status); if (llvm::sys::fs::exists(Status)) { // Fail early if we can't write to the final destination. if (!llvm::sys::fs::can_write(OutputPath)) { Error = make_error_code(llvm::errc::operation_not_permitted); return nullptr; } // Don't use a temporary if the output is a special file. This handles // things like '-o /dev/null' if (!llvm::sys::fs::is_regular_file(Status)) UseTemporary = false; } } } if (UseTemporary) { // Create a temporary file. // Insert -%%%%%%%% before the extension (if any), and because some tools // (noticeable, clang's own GlobalModuleIndex.cpp) glob for build // artifacts, also append .tmp. StringRef OutputExtension = llvm::sys::path::extension(OutFile); SmallString<128> TempPath = StringRef(OutFile).drop_back(OutputExtension.size()); TempPath += "-%%%%%%%%"; TempPath += OutputExtension; TempPath += ".tmp"; int fd; std::error_code EC = llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath); if (CreateMissingDirectories && EC == llvm::errc::no_such_file_or_directory) { StringRef Parent = llvm::sys::path::parent_path(OutputPath); EC = llvm::sys::fs::create_directories(Parent); if (!EC) { EC = llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath); } } if (!EC) { OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); OSFile = TempFile = TempPath.str(); } // If we failed to create the temporary, fallback to writing to the file // directly. This handles the corner case where we cannot write to the // directory, but can write to the file. } if (!OS) { OSFile = OutFile; OS.reset(new llvm::raw_fd_ostream( OSFile, Error, (Binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text))); if (Error) return nullptr; } // Make sure the out stream file gets removed if we crash. if (RemoveFileOnSignal) llvm::sys::RemoveFileOnSignal(OSFile); if (ResultPathName) *ResultPathName = OutFile; if (TempPathName) *TempPathName = TempFile; if (!Binary || OS->supportsSeeking()) return std::move(OS); auto B = llvm::make_unique(*OS); assert(!NonSeekStream); NonSeekStream = std::move(OS); return std::move(B); } // Initialization Utilities bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){ return InitializeSourceManager( Input, getDiagnostics(), getFileManager(), getSourceManager(), hasPreprocessor() ? &getPreprocessor().getHeaderSearchInfo() : nullptr, getDependencyOutputOpts(), getFrontendOpts()); } // static bool CompilerInstance::InitializeSourceManager( const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS, DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) { SrcMgr::CharacteristicKind Kind = Input.getKind().getFormat() == InputKind::ModuleMap ? Input.isSystem() ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.setMainFileID(SourceMgr.createFileID(SourceManager::Unowned, Input.getBuffer(), Kind)); assert(SourceMgr.getMainFileID().isValid() && "Couldn't establish MainFileID!"); return true; } StringRef InputFile = Input.getFile(); // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File; if (Opts.FindPchSource.empty()) { File = FileMgr.getFile(InputFile, /*OpenFile=*/true); } else { // When building a pch file in clang-cl mode, the .h file is built as if // it was included by a cc file. Since the driver doesn't know about // all include search directories, the frontend must search the input // file through HeaderSearch here, as if it had been included by the // cc file at Opts.FindPchSource. const FileEntry *FindFile = FileMgr.getFile(Opts.FindPchSource); if (!FindFile) { Diags.Report(diag::err_fe_error_reading) << Opts.FindPchSource; return false; } const DirectoryLookup *UnusedCurDir; SmallVector, 16> Includers; Includers.push_back(std::make_pair(FindFile, FindFile->getDir())); File = HS->LookupFile(InputFile, SourceLocation(), /*isAngled=*/false, /*FromDir=*/nullptr, /*CurDir=*/UnusedCurDir, Includers, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr, /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, /*SkipCache=*/true); // Also add the header to /showIncludes output. if (File) DepOpts.ShowIncludesPretendHeader = File->getName(); } if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } // The natural SourceManager infrastructure can't currently handle named // pipes, but we would at least like to accept them for the main // file. Detect them here, read them with the volatile flag so FileMgr will // pick up the correct size, and simply override their contents as we do for // STDIN. if (File->isNamedPipe()) { auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true); if (MB) { // Create a new virtual file that will have the correct size. File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0); SourceMgr.overrideFileContents(File, std::move(*MB)); } else { Diags.Report(diag::err_cannot_open_file) << InputFile << MB.getError().message(); return false; } } SourceMgr.setMainFileID( SourceMgr.createFileID(File, SourceLocation(), Kind)); } else { llvm::ErrorOr> 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 SB = std::move(SBOrErr.get()); const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.setMainFileID( SourceMgr.createFileID(File, SourceLocation(), Kind)); SourceMgr.overrideFileContents(File, std::move(SB)); } assert(SourceMgr.getMainFileID().isValid() && "Couldn't establish MainFileID!"); return true; } // High-Level Operations bool CompilerInstance::ExecuteAction(FrontendAction &Act) { assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); // FIXME: Take this as an argument, once all the APIs we used have moved to // taking it as an input instead of hard-coding llvm::errs. raw_ostream &OS = llvm::errs(); // Create the target instance. setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getInvocation().TargetOpts)); if (!hasTarget()) return false; // Create TargetInfo for the other side of CUDA and OpenMP compilation. if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) && !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared(); TO->Triple = getFrontendOpts().AuxTriple; TO->HostTriple = getTarget().getTriple().str(); setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO)); } // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. getTarget().adjust(getLangOpts()); // Adjust target options based on codegen options. getTarget().adjustTargetOptions(getCodeGenOpts(), getTargetOpts()); // rewriter project will change target built-in bool type from its default. if (getFrontendOpts().ProgramAction == frontend::RewriteObjC) getTarget().noSignedCharForObjCBool(); // 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"; if (getFrontendOpts().ShowTimers) createFrontendTimer(); if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty()) llvm::EnableStatistics(false); for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) { // Reset the ID tables if we are reusing the SourceManager and parsing // regular files. if (hasSourceManager() && !Act.isModelParsingAction()) getSourceManager().clearIDTables(); if (Act.BeginSourceFile(*this, FIF)) { Act.Execute(); Act.EndSourceFile(); } } // 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. unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings(); unsigned NumErrors = getDiagnostics().getClient()->getNumErrors(); if (NumWarnings) OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); if (NumWarnings && NumErrors) OS << " and "; if (NumErrors) OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); if (NumWarnings || NumErrors) { OS << " generated"; if (getLangOpts().CUDA) { if (!getLangOpts().CUDAIsDevice) { OS << " when compiling for host"; } else { OS << " when compiling for " << getTargetOpts().CPU; } } OS << ".\n"; } } if (getFrontendOpts().ShowStats) { if (hasFileManager()) { getFileManager().PrintStats(); OS << '\n'; } llvm::PrintStatistics(OS); } StringRef StatsFile = getFrontendOpts().StatsFile; if (!StatsFile.empty()) { std::error_code EC; auto StatS = llvm::make_unique(StatsFile, EC, llvm::sys::fs::F_Text); if (EC) { getDiagnostics().Report(diag::warn_fe_unable_to_open_stats_file) << StatsFile << EC.message(); } else { llvm::PrintStatisticsJSON(*StatS); } } return !getDiagnostics().getClient()->getNumErrors(); } /// \brief Determine the appropriate source input kind based on language /// options. static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) { if (LangOpts.OpenCL) return InputKind::OpenCL; if (LangOpts.CUDA) return InputKind::CUDA; if (LangOpts.ObjC1) return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC; return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C; } /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. static bool compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, StringRef ModuleName, FrontendInputFile Input, StringRef OriginalModuleMapFile, StringRef ModuleFileName, llvm::function_ref PreBuildStep = [](CompilerInstance &) {}, llvm::function_ref PostBuildStep = [](CompilerInstance &) {}) { // Construct a compiler invocation for creating this module. auto Invocation = std::make_shared(ImportingInstance.getInvocation()); PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); // 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(); // 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 &def) { StringRef MacroDef = def.first; return HSOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first)) > 0; }), PPOpts.Macros.end()); // Note the name of the module we're building. Invocation->getLangOpts()->CurrentModule = ModuleName; // Make sure that the failed-module structure has been allocated in // the importing instance, and propagate the pointer to the newly-created // instance. PreprocessorOptions &ImportingPPOpts = ImportingInstance.getInvocation().getPreprocessorOpts(); if (!ImportingPPOpts.FailedModules) ImportingPPOpts.FailedModules = std::make_shared(); PPOpts.FailedModules = ImportingPPOpts.FailedModules; // If there is a module map file, build the module using the module map. // Set up the inputs/outputs so that we build the module from its umbrella // header. FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); FrontendOpts.OutputFile = ModuleFileName.str(); FrontendOpts.DisableFree = false; FrontendOpts.GenerateGlobalModuleIndex = false; FrontendOpts.BuildingImplicitModule = true; FrontendOpts.OriginalModuleMap = OriginalModuleMapFile; // Force implicitly-built modules to hash the content of the module file. HSOpts.ModulesHashContent = true; FrontendOpts.Inputs = {Input}; // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; assert(ImportingInstance.getInvocation().getModuleHash( ImportingInstance.getDiagnostics()) == Invocation->getModuleHash(ImportingInstance.getDiagnostics()) && "Module hash mismatch!"); // Construct a compiler instance that will be used to actually create the // module. Since we're sharing a PCMCache, // CompilerInstance::CompilerInstance is responsible for finalizing the // buffers to prevent use-after-frees. CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(), &ImportingInstance.getPreprocessor().getPCMCache()); auto &Inv = *Invocation; Instance.setInvocation(std::move(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.setFileManager(&ImportingInstance.getFileManager()); Instance.createSourceManager(Instance.getFileManager()); SourceManager &SourceMgr = Instance.getSourceManager(); SourceMgr.setModuleBuildStack( ImportingInstance.getSourceManager().getModuleBuildStack()); SourceMgr.pushModuleBuildStack(ModuleName, FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + // Pass along the GenModuleActionWrapper callback + auto wrapGenModuleAction = ImportingInstance.getGenModuleActionWrapper(); + Instance.setGenModuleActionWrapper(wrapGenModuleAction); + // If we're collecting module dependencies, we need to share a collector // between all of the module CompilerInstances. Other than that, we don't // want to produce any dependency output from the module build. Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector()); Inv.getDependencyOutputOpts() = DependencyOutputOptions(); ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << ModuleName << ModuleFileName; PreBuildStep(Instance); // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; CRC.RunSafelyOnThread( [&]() { // FIXME: I have no idea what the best way to do this is, but it's // probably not this. Interfaces changed upstream. std::unique_ptr Action( new GenerateModuleFromModuleMapAction); - - if (!FrontendOpts.IndexStorePath.empty()) { -#if defined(__APPLE__) - Action = index::createIndexDataRecordingAction(FrontendOpts, - std::move(Action)); -#endif + if (wrapGenModuleAction) { + Action = wrapGenModuleAction(FrontendOpts, std::move(Action)); } Instance.ExecuteAction(*Action); }, ThreadStackSize); PostBuildStep(Instance); ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build_done) << ModuleName; // 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 // doesn't make sense for all clients, so clean this up manually. Instance.clearOutputFiles(/*EraseFiles=*/true); return !Instance.getDiagnostics().hasErrorOccurred(); } /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. static bool compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, Module *Module, StringRef ModuleFileName) { InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), InputKind::ModuleMap); // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); bool Result; if (const FileEntry *ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Use the module map where this module resides. Result = compileModuleImpl( ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem), ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); } else { // FIXME: We only need to fake up an input file here as a way of // transporting the module's directory to the module map parser. We should // be able to do that more directly, and parse from a memory buffer without // inventing this file. SmallString<128> FakeModuleMapFile(Module->Directory->getName()); llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); std::string InferredModuleMapContent; llvm::raw_string_ostream OS(InferredModuleMapContent); Module->print(OS); OS.flush(); Result = compileModuleImpl( ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem), ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName, [&](CompilerInstance &Instance) { std::unique_ptr ModuleMapBuffer = llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); ModuleMapFile = Instance.getFileManager().getVirtualFile( FakeModuleMapFile, InferredModuleMapContent.size(), 0); Instance.getSourceManager().overrideFileContents( ModuleMapFile, std::move(ModuleMapBuffer)); }); } // We've rebuilt a module. If we're allowed to generate or update the global // module index, record that fact in the importing compiler instance. if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { ImportingInstance.setBuildGlobalModuleIndex(true); } return Result; } static bool compileAndLoadModule(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); }; // 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: // PCMCache takes care of correctness and locks are only necessary for // performance. Fallback to building the module in case of any lock // related errors. Diags.Report(ModuleNameLoc, diag::remark_module_lock_failure) << Module->Name << Locked.getErrorMessage(); // Clear out any potential leftover. Locked.unsafeRemoveLockFile(); // FALLTHROUGH 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. 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 PCMCache 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 invokations can make progress. Locked.unsafeRemoveLockFile(); continue; } break; } // Try to read the module file, now that we've compiled it. ASTReader::ASTReadResult ReadResult = ImportingInstance.getModuleManager()->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... 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; } } /// \brief 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, Module *Mod, SourceLocation ImportLoc) { IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro); SourceManager &SourceMgr = PP.getSourceManager(); // If this identifier has never had a macro definition, then it could // not have changed. if (!Id->hadMacroDefinition()) return; auto *LatestLocalMD = PP.getLocalMacroDirectiveHistory(Id); // Find the macro definition from the command line. MacroInfo *CmdLineDefinition = nullptr; for (auto *MD = LatestLocalMD; MD; MD = MD->getPrevious()) { // We only care about the predefines buffer. FileID FID = SourceMgr.getFileID(MD->getLocation()); if (FID.isInvalid() || FID != PP.getPredefinesFileID()) continue; if (auto *DMD = dyn_cast(MD)) CmdLineDefinition = DMD->getMacroInfo(); break; } auto *CurrentDefinition = PP.getMacroInfo(Id); if (CurrentDefinition == CmdLineDefinition) { // Macro matches. Nothing to do. } else if (!CurrentDefinition) { // This macro was defined on the command line, then #undef'd later. // Complain. PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) << true << ConfigMacro << Mod->getFullModuleName(); auto LatestDef = LatestLocalMD->getDefinition(); assert(LatestDef.isUndefined() && "predefined macro went away with no #undef?"); PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here) << true; return; } else if (!CmdLineDefinition) { // There was no definition for this macro in the predefines buffer, // but there was a local definition. Complain. PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) << false << ConfigMacro << Mod->getFullModuleName(); PP.Diag(CurrentDefinition->getDefinitionLoc(), diag::note_module_def_undef_here) << false; } else if (!CurrentDefinition->isIdenticalTo(*CmdLineDefinition, PP, /*Syntactically=*/true)) { // The macro definitions differ. PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) << false << ConfigMacro << Mod->getFullModuleName(); PP.Diag(CurrentDefinition->getDefinitionLoc(), diag::note_module_def_undef_here) << false; } } /// \brief Write a new timestamp file with the given path. static void writeTimestampFile(StringRef TimestampFile) { std::error_code EC; llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::F_None); } /// \brief Prune the module cache of modules that haven't been accessed in /// a long time. static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { struct stat StatBuf; llvm::SmallString<128> TimestampFile; TimestampFile = HSOpts.ModuleCachePath; assert(!TimestampFile.empty()); llvm::sys::path::append(TimestampFile, "modules.timestamp"); // Try to stat() the timestamp file. if (::stat(TimestampFile.c_str(), &StatBuf)) { // If the timestamp file wasn't there, create one now. if (errno == ENOENT) { writeTimestampFile(TimestampFile); } return; } // 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(nullptr); if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval)) return; // Write a new timestamp file so that nobody else attempts to prune. // There is a benign race condition here, if two Clang instances happen to // notice at the same time that the timestamp is out-of-date. writeTimestampFile(TimestampFile); // Walk the entire module cache, looking for unused module files and module // indices. std::error_code EC; SmallString<128> ModuleCachePathNative; llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative); for (llvm::sys::fs::directory_iterator Dir(ModuleCachePathNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { // If we don't have a directory, there's nothing to look into. if (!llvm::sys::fs::is_directory(Dir->path())) continue; // Walk all of the files within this directory. 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. 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)) 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)) { continue; } // Remove the file. 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 (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 implicitly building modules but not currently recursively // building a module, check whether we need to prune the module cache. if (getSourceManager().getModuleBuildStack().empty() && !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() && getHeaderSearchOpts().ModuleCachePruneInterval > 0 && getHeaderSearchOpts().ModuleCachePruneAfter > 0) { pruneModuleCache(getHeaderSearchOpts()); } HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); std::string Sysroot = HSOpts.Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); std::unique_ptr ReadTimer; if (FrontendTimerGroup) ReadTimer = llvm::make_unique("reading_modules", "Reading modules", *FrontendTimerGroup); ModuleManager = new ASTReader( getPreprocessor(), &getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, /*AllowASTWithCompilerErrors=*/false, /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); getASTContext().setASTMutationListener( getASTConsumer().GetASTMutationListener()); } getASTContext().setExternalSource(ModuleManager); if (hasSema()) ModuleManager->InitializeSema(getSema()); if (hasASTConsumer()) ModuleManager->StartTranslationUnit(&getASTConsumer()); if (TheDependencyFileGenerator) TheDependencyFileGenerator->AttachToASTReader(*ModuleManager); for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*ModuleManager); } } bool CompilerInstance::loadModuleFile(StringRef FileName) { 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 LoadedModules; ReadModuleNames(CompilerInstance &CI) : CI(CI) {} void ReadModuleName(StringRef ModuleName) override { LoadedModules.push_back( CI.getPreprocessor().getIdentifierInfo(ModuleName)); } void registerAll() { for (auto *II : LoadedModules) { CI.KnownModules[II] = CI.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() .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 Stack; Stack.push_back(M); while (!Stack.empty()) { Module *Current = Stack.pop_back_val(); if (Current->IsMissingRequirement) 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 (!ModuleManager) createModuleManager(); auto Listener = llvm::make_unique(*this); auto &ListenerRef = *Listener; ASTReader::ListenerScope ReadModuleNamesListener(*ModuleManager, std::move(Listener)); // Try to load the module file. switch (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule, SourceLocation(), ASTReader::ARR_ConfigurationMismatch)) { 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. ListenerRef.registerAll(); return true; case ASTReader::ConfigurationMismatch: // Ignore unusable module files. getDiagnostics().Report(SourceLocation(), diag::warn_module_config_mismatch) << FileName; // All modules provided by any files we tried and failed to load are now // unavailable; includes of those modules should now be handled textually. ListenerRef.markAllUnavailable(); return true; default: return false; } } ModuleLoadResult CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) { // Determine what file we're searching from. // FIXME: Should we be deciding whether this is a submodule (here and // below) based on -fmodules-ts or should we pass a flag and make the // caller decide? std::string ModuleName; if (getLangOpts().ModulesTS) { // FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a // better place/way to do this. for (auto &Piece : Path) { if (!ModuleName.empty()) ModuleName += "."; ModuleName += Piece.first->getName(); } } else ModuleName = Path[0].first->getName(); SourceLocation ModuleNameLoc = Path[0].second; // If we've already handled this import, just return the cached result. // This one-element cache is important to eliminate redundant diagnostics // when both the preprocessor and parser see the same import declaration. if (ImportLoc.isValid() && LastModuleImportLoc == ImportLoc) { // Make the named module visible. if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule) ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility, ImportLoc); return LastModuleImportResult; } clang::Module *Module = nullptr; // If we don't already have information on this module, load the module now. llvm::DenseMap::iterator Known = KnownModules.find(Path[0].first); if (Known != KnownModules.end()) { // Retrieve the cached top-level module. Module = Known->second; } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); /// 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; // ModuleBuildFailed = true; // return ModuleLoadResult(); //} 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); HeaderSearchOptions &HSOpts = PP->getHeaderSearchInfo().getHeaderSearchOpts(); std::string ModuleFileName; enum ModuleSource { ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma } Source = ModuleNotFound; // Check to see if the module has been built as part of this compilation // via a module build pragma. auto BuiltModuleIt = BuiltModules.find(ModuleName); if (BuiltModuleIt != BuiltModules.end()) { ModuleFileName = BuiltModuleIt->second; Source = ModuleBuildPragma; } // Try to load the module from the prebuilt module path. if (Source == ModuleNotFound && (!HSOpts.PrebuiltModuleFiles.empty() || !HSOpts.PrebuiltModulePaths.empty())) { ModuleFileName = PP->getHeaderSearchInfo().getPrebuiltModuleFileName(ModuleName); if (!ModuleFileName.empty()) Source = PrebuiltModulePath; } // Try to load the module from the module cache. if (Source == ModuleNotFound && Module) { ModuleFileName = PP->getHeaderSearchInfo().getCachedModuleFileName(Module); Source = ModuleCache; } if (Source == ModuleNotFound) { // We can't find a module, error out here. getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); ModuleBuildFailed = true; return ModuleLoadResult(); } if (ModuleFileName.empty()) { if (Module && Module->HasIncompatibleModuleFile) { // We tried and failed to load a module file for this module. Fall // back to textual inclusion for its headers. return ModuleLoadResult::ConfigMismatch; } getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) << ModuleName; ModuleBuildFailed = true; return ModuleLoadResult(); } // If we don't already have an ASTReader, create one now. if (!ModuleManager) createModuleManager(); llvm::Timer Timer; if (FrontendTimerGroup) Timer.init("loading." + ModuleFileName, "Loading " + ModuleFileName, *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); // Try to load the module file. If we are not trying to load from the // module cache, we don't know how to rebuild modules. unsigned ARRFlags = Source == ModuleCache ? ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing : ASTReader::ARR_ConfigurationMismatch; switch (ModuleManager->ReadAST(ModuleFileName, Source == PrebuiltModulePath ? serialization::MK_PrebuiltModule : Source == ModuleBuildPragma ? serialization::MK_ExplicitModule : serialization::MK_ImplicitModule, ImportLoc, ARRFlags)) { case ASTReader::Success: { if (Source != ModuleCache && !Module) { Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); if (!Module || !Module->getASTFile() || FileMgr->getFile(ModuleFileName) != Module->getASTFile()) { // Error out if Module does not refer to the file in the prebuilt // module path. getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt) << ModuleName; ModuleBuildFailed = true; KnownModules[Path[0].first] = nullptr; return ModuleLoadResult(); } } break; } case ASTReader::OutOfDate: case ASTReader::Missing: { if (Source != ModuleCache) { // We don't know the desired configuration for this module and don't // necessarily even have a module map. Since ReadAST already produces // diagnostics for these two cases, we simply error out here. ModuleBuildFailed = true; KnownModules[Path[0].first] = nullptr; return ModuleLoadResult(); } // The module file is missing or out-of-date. Build it. 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(); for (; Pos != PosEnd; ++Pos) { if (Pos->first == ModuleName) break; } if (Pos != PosEnd) { SmallString<256> CyclePath; for (; Pos != PosEnd; ++Pos) { CyclePath += Pos->first; CyclePath += " -> "; } CyclePath += ModuleName; getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) << ModuleName << CyclePath; return ModuleLoadResult(); } // Check whether we have already attempted to build this module (but // failed). if (getPreprocessorOpts().FailedModules && getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); ModuleBuildFailed = true; return ModuleLoadResult(); } // Try to compile and then load the module. if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module, ModuleFileName)) { assert(getDiagnostics().hasErrorOccurred() && "undiagnosed error in compileAndLoadModule"); if (getPreprocessorOpts().FailedModules) getPreprocessorOpts().FailedModules->addFailed(ModuleName); KnownModules[Path[0].first] = nullptr; ModuleBuildFailed = true; return ModuleLoadResult(); } // Okay, we've rebuilt and now loaded the module. break; } case ASTReader::ConfigurationMismatch: if (Source == PrebuiltModulePath) // FIXME: We shouldn't be setting HadFatalFailure below if we only // produce a warning here! getDiagnostics().Report(SourceLocation(), diag::warn_module_config_mismatch) << ModuleFileName; // Fall through to error out. LLVM_FALLTHROUGH; case ASTReader::VersionMismatch: case ASTReader::HadErrors: ModuleLoader::HadFatalFailure = true; // FIXME: The ASTReader will already have complained, but can we shoehorn // that diagnostic information into a more useful form? 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] = nullptr; ModuleBuildFailed = true; return ModuleLoadResult(); } // Cache the result of this top-level module lookup for later. Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; } // If we never found the module, fail. if (!Module) return ModuleLoadResult(); // Verify that the rest of the module path actually corresponds to // a submodule. if (!getLangOpts().ModulesTS && 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 (!Sub) { // Attempt to perform typo correction to find a module name that works. SmallVector Best; unsigned BestEditDistance = (std::numeric_limits::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 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) << FixItHint::CreateReplacement(SourceRange(Path[I].second), 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) << Path[I].first << Module->getFullModuleName() << 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 // we are parsing. if (ModuleName != getLangOpts().CurrentModule) { if (!Module->IsFromModuleFile) { // We have an umbrella header or directory that doesn't actually include // all of the headers within the directory it covers. Complain about // this missing submodule and recover by forgetting that we ever saw // this submodule. // FIXME: Should we detect this at module load time? It seems fairly // expensive (and rare). getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule) << Module->getFullModuleName() << SourceRange(Path.front().second, Path.back().second); return ModuleLoadResult::MissingExpected; } // Check whether this module is available. if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(), getDiagnostics(), Module)) { getDiagnostics().Report(ImportLoc, diag::note_module_import_here) << SourceRange(Path.front().second, Path.back().second); LastModuleImportLoc = ImportLoc; LastModuleImportResult = ModuleLoadResult(); return ModuleLoadResult(); } ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc); } // Check for any configuration macros that have changed. clang::Module *TopModule = Module->getTopLevelModule(); for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) { checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I], Module, ImportLoc); } LastModuleImportLoc = ImportLoc; LastModuleImportResult = ModuleLoadResult(Module); return LastModuleImportResult; } void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, StringRef Source) { // Avoid creating filenames with special characters. SmallString<128> CleanModuleName(ModuleName); for (auto &C : CleanModuleName) if (!isAlphanumeric(C)) C = '_'; // FIXME: Using a randomized filename here means that our intermediate .pcm // output is nondeterministic (as .pcm files refer to each other by name). // Can this affect the output in any way? SmallString<128> ModuleFileName; if (std::error_code EC = llvm::sys::fs::createTemporaryFile( CleanModuleName, "pcm", ModuleFileName)) { getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output) << ModuleFileName << EC.message(); return; } std::string ModuleMapFileName = (CleanModuleName + ".map").str(); FrontendInputFile Input( ModuleMapFileName, InputKind(getLanguageFromOptions(*Invocation->getLangOpts()), InputKind::ModuleMap, /*Preprocessed*/true)); std::string NullTerminatedSource(Source.str()); auto PreBuildStep = [&](CompilerInstance &Other) { // Create a virtual file containing our desired source. // FIXME: We shouldn't need to do this. const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile( ModuleMapFileName, NullTerminatedSource.size(), 0); Other.getSourceManager().overrideFileContents( ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str())); Other.BuiltModules = std::move(BuiltModules); Other.DeleteBuiltModules = false; }; auto PostBuildStep = [this](CompilerInstance &Other) { BuiltModules = std::move(Other.BuiltModules); }; // Build the module, inheriting any modules that we've built locally. if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(), ModuleFileName, PreBuildStep, PostBuildStep)) { BuiltModules[ModuleName] = ModuleFileName.str(); llvm::sys::RemoveFileOnSignal(ModuleFileName); } } void CompilerInstance::makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) { if (!ModuleManager) createModuleManager(); if (!ModuleManager) return; ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc); } GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( SourceLocation TriggerLoc) { if (getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty()) return nullptr; 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(), getPCHContainerReader(), 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, 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(), getPCHContainerReader(), 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; } void CompilerInstance::resetAndLeakSema() { BuryPointer(takeSema()); } void CompilerInstance::setExternalSemaSource( IntrusiveRefCntPtr ESS) { ExternalSemaSrc = std::move(ESS); } diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt index 7e11be0ce4c5..4a713e5902b2 100644 --- a/clang/lib/FrontendTool/CMakeLists.txt +++ b/clang/lib/FrontendTool/CMakeLists.txt @@ -1,34 +1,35 @@ set(LLVM_LINK_COMPONENTS Option Support ) set(link_libs clangBasic clangCodeGen clangDriver clangFrontend + clangIndex clangRewriteFrontend ) if(CLANG_ENABLE_ARCMT) list(APPEND link_libs clangARCMigrate ) endif() if(CLANG_ENABLE_STATIC_ANALYZER) list(APPEND link_libs clangStaticAnalyzerFrontend ) endif() add_clang_library(clangFrontendTool ExecuteCompilerInvocation.cpp DEPENDS ClangDriverOptions LINK_LIBS ${link_libs} ) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index e217bf60b377..5715e8e2af94 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -1,263 +1,262 @@ //===--- ExecuteCompilerInvocation.cpp ------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file holds ExecuteCompilerInvocation(). It is split into its own file to // minimize the impact of pulling in essentially everything else in Clang. // //===----------------------------------------------------------------------===// #include "clang/FrontendTool/Utils.h" #include "clang/ARCMigrate/ARCMTActions.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/Config/config.h" #include "clang/Driver/Options.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/Utils.h" #include "clang/Index/IndexingAction.h" #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace llvm::opt; static std::unique_ptr CreateFrontendBaseAction(CompilerInstance &CI) { using namespace clang::frontend; StringRef Action("unknown"); (void)Action; switch (CI.getFrontendOpts().ProgramAction) { case ASTDeclList: return llvm::make_unique(); case ASTDump: return llvm::make_unique(); case ASTPrint: return llvm::make_unique(); case ASTView: return llvm::make_unique(); case DumpRawTokens: return llvm::make_unique(); case DumpTokens: return llvm::make_unique(); case EmitAssembly: return llvm::make_unique(); case EmitBC: return llvm::make_unique(); case EmitHTML: return llvm::make_unique(); case EmitLLVM: return llvm::make_unique(); case EmitLLVMOnly: return llvm::make_unique(); case EmitCodeGenOnly: return llvm::make_unique(); case EmitObj: return llvm::make_unique(); case FixIt: return llvm::make_unique(); case GenerateModule: return llvm::make_unique(); case GenerateModuleInterface: return llvm::make_unique(); case GeneratePCH: return llvm::make_unique(); case GeneratePTH: return llvm::make_unique(); case InitOnly: return llvm::make_unique(); case ParseSyntaxOnly: return llvm::make_unique(); case ModuleFileInfo: return llvm::make_unique(); case VerifyPCH: return llvm::make_unique(); case PluginAction: { for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); it != ie; ++it) { if (it->getName() == CI.getFrontendOpts().ActionName) { std::unique_ptr P(it->instantiate()); if ((P->getActionType() != PluginASTAction::ReplaceAction && P->getActionType() != PluginASTAction::Cmdline) || !P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs[it->getName()])) return nullptr; return std::move(P); } } CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) << CI.getFrontendOpts().ActionName; return nullptr; } case PrintDeclContext: return llvm::make_unique(); case PrintPreamble: return llvm::make_unique(); case PrintPreprocessedInput: { if (CI.getPreprocessorOutputOpts().RewriteIncludes || CI.getPreprocessorOutputOpts().RewriteImports) return llvm::make_unique(); return llvm::make_unique(); } case RewriteMacros: return llvm::make_unique(); case RewriteTest: return llvm::make_unique(); #ifdef CLANG_ENABLE_OBJC_REWRITER case RewriteObjC: return llvm::make_unique(); #else case RewriteObjC: Action = "RewriteObjC"; break; #endif #ifdef CLANG_ENABLE_ARCMT case MigrateSource: return llvm::make_unique(); #else case MigrateSource: Action = "MigrateSource"; break; #endif #ifdef CLANG_ENABLE_STATIC_ANALYZER case RunAnalysis: return llvm::make_unique(); #else case RunAnalysis: Action = "RunAnalysis"; break; #endif case RunPreprocessorOnly: return llvm::make_unique(); } #if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \ || !defined(CLANG_ENABLE_OBJC_REWRITER) CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action; return 0; #else llvm_unreachable("Invalid program action!"); #endif } static std::unique_ptr CreateFrontendAction(CompilerInstance &CI) { // Create the underlying action. std::unique_ptr Act = CreateFrontendBaseAction(CI); if (!Act) return nullptr; const FrontendOptions &FEOpts = CI.getFrontendOpts(); if (FEOpts.FixAndRecompile) { Act = llvm::make_unique(std::move(Act)); } #ifdef CLANG_ENABLE_ARCMT if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource && CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) { // Potentially wrap the base FE action in an ARC Migrate Tool action. switch (FEOpts.ARCMTAction) { case FrontendOptions::ARCMT_None: break; case FrontendOptions::ARCMT_Check: Act = llvm::make_unique(std::move(Act)); break; case FrontendOptions::ARCMT_Modify: Act = llvm::make_unique(std::move(Act)); break; case FrontendOptions::ARCMT_Migrate: Act = llvm::make_unique(std::move(Act), FEOpts.MTMigrateDir, FEOpts.ARCMTMigrateReportOut, FEOpts.ARCMTMigrateEmitARCErrors); break; } if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) { Act = llvm::make_unique(std::move(Act), FEOpts.MTMigrateDir, FEOpts.ObjCMTAction); } } #endif if (!FEOpts.IndexStorePath.empty()) { -#if defined(__APPLE__) Act = index::createIndexDataRecordingAction(FEOpts, std::move(Act)); -#endif + CI.setGenModuleActionWrapper(&index::createIndexDataRecordingAction); } // If there are any AST files to merge, create a frontend action // adaptor to perform the merge. if (!FEOpts.ASTMergeFiles.empty()) Act = llvm::make_unique(std::move(Act), FEOpts.ASTMergeFiles); return Act; } bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { std::unique_ptr Opts = driver::createDriverOptTable(); Opts->PrintHelp(llvm::outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org", /*Include=*/driver::options::CC1Option, /*Exclude=*/0, /*ShowAllAliases=*/false); return true; } // Honor -version. // // FIXME: Use a better -version message? if (Clang->getFrontendOpts().ShowVersion) { llvm::cl::PrintVersionMessage(); return true; } // Load any requested plugins. for (unsigned i = 0, e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { const std::string &Path = Clang->getFrontendOpts().Plugins[i]; std::string Error; if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) << Path << Error; } // Check if any of the loaded plugins replaces the main AST action for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); it != ie; ++it) { std::unique_ptr P(it->instantiate()); if (P->getActionType() == PluginASTAction::ReplaceAction) { Clang->getFrontendOpts().ProgramAction = clang::frontend::PluginAction; Clang->getFrontendOpts().ActionName = it->getName(); break; } } // Honor -mllvm. // // FIXME: Remove this, one day. // This should happen AFTER plugins have been loaded! if (!Clang->getFrontendOpts().LLVMArgs.empty()) { unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); auto Args = llvm::make_unique(NumArgs + 2); Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); } #ifdef CLANG_ENABLE_STATIC_ANALYZER // Honor -analyzer-checker-help. // This should happen AFTER plugins have been loaded! if (Clang->getAnalyzerOpts()->ShowCheckerHelp) { ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins); return true; } if (Clang->getAnalyzerOpts()->ShowEnabledCheckerList) { ento::printEnabledCheckerList(llvm::outs(), Clang->getFrontendOpts().Plugins, *Clang->getAnalyzerOpts()); } #endif // If there were errors in processing arguments, don't do anything else. if (Clang->getDiagnostics().hasErrorOccurred()) return false; // Create and execute the frontend action. std::unique_ptr Act(CreateFrontendAction(*Clang)); if (!Act) return false; bool Success = Clang->ExecuteAction(*Act); if (Clang->getFrontendOpts().DisableFree) BuryPointer(std::move(Act)); return Success; } diff --git a/clang/lib/Index/CMakeLists.txt b/clang/lib/Index/CMakeLists.txt index b5dea4cd05c5..bb17d15b5526 100644 --- a/clang/lib/Index/CMakeLists.txt +++ b/clang/lib/Index/CMakeLists.txt @@ -1,38 +1,40 @@ set(LLVM_LINK_COMPONENTS + BitReader Core Support ) add_clang_library(clangIndex ClangIndexRecordWriter.cpp CodegenNameGenerator.cpp CommentToXML.cpp FileIndexRecord.cpp IndexBody.cpp IndexDataStore.cpp IndexDataStoreUtils.cpp IndexDecl.cpp IndexingAction.cpp IndexingContext.cpp IndexRecordHasher.cpp IndexRecordReader.cpp IndexRecordWriter.cpp IndexSymbol.cpp IndexTypeSourceInfo.cpp IndexUnitReader.cpp IndexUnitWriter.cpp USRGeneration.cpp ADDITIONAL_HEADERS IndexingContext.h SimpleFormatContext.h LINK_LIBS clangAST clangBasic clangFormat clangFrontend + clangLex clangRewrite clangSerialization clangToolingCore )