diff options
Diffstat (limited to 'include/flang/Frontend/CompilerInstance.h')
-rw-r--r-- | include/flang/Frontend/CompilerInstance.h | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/include/flang/Frontend/CompilerInstance.h b/include/flang/Frontend/CompilerInstance.h new file mode 100644 index 0000000000..948e8b336e --- /dev/null +++ b/include/flang/Frontend/CompilerInstance.h @@ -0,0 +1,528 @@ +//===-- 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_FLANG_FRONTEND_COMPILERINSTANCE_H_ +#define LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H_ + +#include "flang/Basic/Diagnostic.h" +#include "flang/Frontend/CompilerInvocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" +#include <cassert> +#include <list> +#include <string> +#include <utility> + +namespace llvm { +class raw_fd_ostream; +class Timer; +} + +namespace flang { +class ASTContext; +class ASTConsumer; +class ASTReader; +class CodeCompleteConsumer; +class DiagnosticsEngine; +class DiagnosticClient; +class ExternalASTSource; +class FileEntry; +class FrontendAction; +class Module; +class Preprocessor; +class Sema; +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 { + /// The options used in this compiler instance. + llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation; + + /// The diagnostics engine instance. + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + + /// The target being compiled for. + llvm::IntrusiveRefCntPtr<TargetInfo> Target; + + /// The source manager. + llvm::IntrusiveRefCntPtr<llvm::SourceMgr> SourceMgr; + + /// The preprocessor. + llvm::IntrusiveRefCntPtr<Preprocessor> PP; + + /// The AST context. + llvm::IntrusiveRefCntPtr<ASTContext> Context; + + /// The AST consumer. + std::unique_ptr<ASTConsumer> Consumer; + + /// The code completion consumer. + std::unique_ptr<CodeCompleteConsumer> CompletionConsumer; + + /// \brief The semantic analysis object. + std::unique_ptr<Sema> TheSema; + + /// \brief The frontend timer + std::unique_ptr<llvm::Timer> FrontendTimer; + + /// \brief Non-owning reference to the ASTReader, if one exists. + ASTReader *ModuleManager; + + /// \brief The set of top-level modules that has already been loaded, + /// along with the module map + llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules; + + /// \brief The location of the module-import keyword for the last module + /// import. + SourceLocation LastModuleImportLoc; + + /// \brief Whether we should (re)build the global module index once we + /// have finished with this translation unit. + bool BuildGlobalModuleIndex; + + /// \brief One or more modules failed to build. + bool ModuleBuildFailed; + + /// \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; + raw_ostream *OS; + + OutputFile(const std::string &filename, const std::string &tempFilename, + raw_ostream *os) + : Filename(filename), TempFilename(tempFilename), OS(os) { } + }; + + /// The list of active output files. + std::list<OutputFile> OutputFiles; + + CompilerInstance(const CompilerInstance &) LLVM_DELETED_FUNCTION; + void operator=(const CompilerInstance &) LLVM_DELETED_FUNCTION; +public: + CompilerInstance(); + ~CompilerInstance(); + + /// @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 != 0; } + + CompilerInvocation &getInvocation() { + assert(Invocation && "Compiler instance has no invocation!"); + return *Invocation; + } + + /// setInvocation - Replace the current invocation. + void setInvocation(CompilerInvocation *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 + /// { + + CodeGenOptions &getCodeGenOpts() { + return Invocation->getCodeGenOpts(); + } + const CodeGenOptions &getCodeGenOpts() const { + return Invocation->getCodeGenOpts(); + } + + FrontendOptions &getFrontendOpts() { + return Invocation->getFrontendOpts(); + } + const FrontendOptions &getFrontendOpts() const { + return Invocation->getFrontendOpts(); + } + + LangOptions &getLangOpts() { + return *Invocation->getLangOpts(); + } + const LangOptions &getLangOpts() const { + return *Invocation->getLangOpts(); + } + + TargetOptions &getTargetOpts() { + return Invocation->getTargetOpts(); + } + const TargetOptions &getTargetOpts() const { + return Invocation->getTargetOpts(); + } + + /// } + /// @name Diagnostics Engine + /// { + + bool hasDiagnostics() const { return Diagnostics != 0; } + + /// 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); + + DiagnosticClient &getDiagnosticConsumer() const { + assert(Diagnostics && Diagnostics->getClient() && + "Compiler instance has no diagnostic client!"); + return *Diagnostics->getClient(); + } + + /// } + /// @name Target Info + /// { + + bool hasTarget() const { return Target != 0; } + + TargetInfo &getTarget() const { + assert(Target && "Compiler instance has no target!"); + return *Target; + } + + /// Replace the current diagnostics engine. + void setTarget(TargetInfo *Value); + + /// } + /// @name Source Manager + /// { + + bool hasSourceManager() const { return SourceMgr != 0; } + + /// Return the current source manager. + llvm::SourceMgr &getSourceManager() const { + assert(SourceMgr && "Compiler instance has no source manager!"); + return *SourceMgr; + } + + void resetAndLeakSourceManager() { + SourceMgr.resetWithoutRelease(); + } + + /// setSourceManager - Replace the current source manager. + void setSourceManager(llvm::SourceMgr *Value); + + /// } + /// @name Preprocessor + /// { + + bool hasPreprocessor() const { return PP != 0; } + + /// Return the current preprocessor. + Preprocessor &getPreprocessor() const { + assert(PP && "Compiler instance has no preprocessor!"); + return *PP; + } + + void resetAndLeakPreprocessor() { + PP.resetWithoutRelease(); + } + + /// Replace the current preprocessor. + void setPreprocessor(Preprocessor *Value); + + /// } + /// @name ASTContext + /// { + + bool hasASTContext() const { return Context != 0; } + + ASTContext &getASTContext() const { + assert(Context && "Compiler instance has no AST context!"); + return *Context; + } + + void resetAndLeakASTContext() { + 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 Consumer.get() != nullptr; } + + 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. + ASTConsumer *takeASTConsumer() { return Consumer.release(); } + + /// setASTConsumer - Replace the current AST consumer; the compiler instance + /// takes ownership of \p Value. + void setASTConsumer(ASTConsumer *Value); + + /// } + /// @name Semantic analysis + /// { + bool hasSema() const { return TheSema.get() != nullptr; } + + Sema &getSema() const { + assert(TheSema && "Compiler instance has no Sema object!"); + return *TheSema; + } + + Sema *takeSema() { return TheSema.release(); } + + /// } + /// @name Module Management + /// { + + ASTReader *getModuleManager() const { return ModuleManager; } + void setModuleManager(ASTReader *Reader) { ModuleManager = Reader; } + + /// } + /// @name Frontend timer + /// { + + bool hasFrontendTimer() const { return FrontendTimer.get() != nullptr; } + + 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(const OutputFile &OutFile); + + /// clearOutputFiles - Clear the output file list, destroying the contained + /// output streams. + /// + /// \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(DiagnosticClient *Client = 0, + 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 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> + createDiagnostics(DiagnosticOptions *Opts, + DiagnosticClient *Client = 0, + bool ShouldOwnClient = true, + const CodeGenOptions *CodeGenOpts = 0); + + /// Create the source manager and replace any existing one with it. + void createSourceManager(); + + /// Create the preprocessor, using the invocation, file, and source managers, + /// and replace any existing one with it. + void createPreprocessor(); + + /// Create the AST context. + void createASTContext(); + + /// \brief Create the Sema object to be used for parsing. + void createSema(); + + /// 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. + llvm::raw_fd_ostream * + 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. + llvm::raw_fd_ostream * + 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 message. + /// \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. + static llvm::raw_fd_ostream * + createOutputFile(StringRef OutputPath, std::string &Error, + bool Binary, bool RemoveFileOnSignal, + StringRef BaseInput, + StringRef Extension, + bool UseTemporary, + bool CreateMissingDirectories, + std::string *ResultPathName, + std::string *TempPathName); + + /// } + /// @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, + llvm::SourceMgr &SrcMgr, + const FrontendOptions &Opts); + + /// } + +}; + +} // end namespace flang + +#endif |