https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/65412:
>From 5f8e316a774dbd18cbdf98d507bc6910de3d37d4 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 31 Aug 2023 11:39:32 -0700 Subject: [PATCH] [clang] Introduce copy-on-write `CompilerInvocation` --- clang/include/clang/Basic/CodeGenOptions.h | 1 + clang/include/clang/Basic/DiagnosticOptions.h | 1 + clang/include/clang/Basic/LangOptions.h | 1 + .../clang/Frontend/CompilerInvocation.h | 317 ++++++++++++------ clang/lib/Frontend/CompilerInvocation.cpp | 208 +++++++----- 5 files changed, 346 insertions(+), 182 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 14fc94fe27f995..c6d7db32f2d266 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -32,6 +32,7 @@ namespace clang { /// that this large collection of bitfields is a trivial class type. class CodeGenOptionsBase { friend class CompilerInvocation; + friend struct CompilerInvocationBase; public: #define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits; diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h index 0f3120859ecef6..9fb84415e22ead 100644 --- a/clang/include/clang/Basic/DiagnosticOptions.h +++ b/clang/include/clang/Basic/DiagnosticOptions.h @@ -72,6 +72,7 @@ class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{ clang::DiagnosticsEngine *, bool); friend class CompilerInvocation; + friend struct CompilerInvocationBase; public: enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIF }; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 2adf4751444726..aa649e675d9024 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -34,6 +34,7 @@ namespace clang { /// this large collection of bitfields is a trivial class type. class LangOptionsBase { friend class CompilerInvocation; + friend struct CompilerInvocationBase; public: // Define simple language options (with no accessors). diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 5dc55bb7abdbab..81f3107b4b4df4 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -20,8 +20,8 @@ #include "clang/Frontend/MigratorOptions.h" #include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include <memory> #include <string> @@ -66,16 +66,18 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, DiagnosticsEngine *Diags = nullptr, bool DefaultDiagColor = true); +namespace CompilerInvocationDetail { /// The base class of CompilerInvocation with reference semantics. /// /// This class stores option objects behind reference-counted pointers. This is /// useful for clients that want to keep some option object around even after /// CompilerInvocation gets destroyed, without making a copy. /// -/// This is a separate class so that we can implement the copy constructor and -/// assignment here and leave them defaulted in the rest of CompilerInvocation. -class CompilerInvocationRefBase { -public: +/// This is a separate base class so that the client-facing sub-classes can +/// simply declare the desired copy semantics without managing the internals +/// themselves (for the most parts). +class RefBase { +protected: /// Options controlling the language variant. std::shared_ptr<LangOptions> LangOpts; @@ -94,47 +96,37 @@ class CompilerInvocationRefBase { /// Options controlling the static analyzer. AnalyzerOptionsRef AnalyzerOpts; - CompilerInvocationRefBase(); - CompilerInvocationRefBase(const CompilerInvocationRefBase &X); - CompilerInvocationRefBase(CompilerInvocationRefBase &&X); - CompilerInvocationRefBase &operator=(CompilerInvocationRefBase X); - CompilerInvocationRefBase &operator=(CompilerInvocationRefBase &&X); - ~CompilerInvocationRefBase(); + struct ShallowCopy {}; + struct DeepCopy {}; - LangOptions &getLangOpts() { return *LangOpts; } - const LangOptions &getLangOpts() const { return *LangOpts; } + RefBase(); - TargetOptions &getTargetOpts() { return *TargetOpts.get(); } - const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); } + RefBase(const RefBase &X, DeepCopy); + RefBase(const RefBase &X, ShallowCopy); + RefBase(const RefBase &) = delete; - DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; } + RefBase &assign(const RefBase &X, DeepCopy); + RefBase &assign(const RefBase &X, ShallowCopy); + RefBase &operator=(const RefBase &) = delete; - HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; } + RefBase(RefBase &&); + RefBase &operator=(RefBase &&); - const HeaderSearchOptions &getHeaderSearchOpts() const { - return *HeaderSearchOpts; - } + ~RefBase(); - std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const { - return HeaderSearchOpts; - } - - std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() { - return PreprocessorOpts; - } - - PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; } - - const PreprocessorOptions &getPreprocessorOpts() const { - return *PreprocessorOpts; - } - - AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; } +public: + // clang-format off + const LangOptions &getLangOpts() const { return *LangOpts; } + const TargetOptions &getTargetOpts() const { return *TargetOpts; } + const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; } + const HeaderSearchOptions &getHeaderSearchOpts() const { return *HeaderSearchOpts; } + const PreprocessorOptions &getPreprocessorOpts() const { return *PreprocessorOpts; } const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; } + // clang-format on }; /// The base class of CompilerInvocation with value semantics. -class CompilerInvocationValueBase { +class ValBase { protected: MigratorOptions MigratorOpts; @@ -154,36 +146,87 @@ class CompilerInvocationValueBase { PreprocessorOutputOptions PreprocessorOutputOpts; public: - MigratorOptions &getMigratorOpts() { return MigratorOpts; } + // clang-format off const MigratorOptions &getMigratorOpts() const { return MigratorOpts; } - - CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } + const DependencyOutputOptions &getDependencyOutputOpts() const { return DependencyOutputOpts; } + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } + const FrontendOptions &getFrontendOpts() const { return FrontendOpts; } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { return PreprocessorOutputOpts; } + // clang-format on +}; +} // namespace CompilerInvocationDetail - DependencyOutputOptions &getDependencyOutputOpts() { - return DependencyOutputOpts; - } +struct CompilerInvocationBase : CompilerInvocationDetail::RefBase, + CompilerInvocationDetail::ValBase { + CompilerInvocationBase() = default; - const DependencyOutputOptions &getDependencyOutputOpts() const { - return DependencyOutputOpts; - } + CompilerInvocationBase(const CompilerInvocationBase &X, DeepCopy) + : RefBase(X, DeepCopy{}), ValBase(X) {} - FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + CompilerInvocationBase(const CompilerInvocationBase &X, ShallowCopy) + : RefBase(X, ShallowCopy{}), ValBase(X) {} - const FileSystemOptions &getFileSystemOpts() const { - return FileSystemOpts; + CompilerInvocationBase &assign(const CompilerInvocationBase &X, DeepCopy) { + RefBase::assign(X, DeepCopy{}); + ValBase::operator=(X); + return *this; } - FrontendOptions &getFrontendOpts() { return FrontendOpts; } - const FrontendOptions &getFrontendOpts() const { return FrontendOpts; } - - PreprocessorOutputOptions &getPreprocessorOutputOpts() { - return PreprocessorOutputOpts; + CompilerInvocationBase &assign(const CompilerInvocationBase &X, ShallowCopy) { + RefBase::assign(X, ShallowCopy{}); + ValBase::operator=(X); + return *this; } - const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { - return PreprocessorOutputOpts; + using StringAllocator = llvm::function_ref<const char *(const Twine &)>; + /// Generate cc1-compatible command line arguments from this instance. + /// + /// \param [out] Args - The generated arguments. Note that the caller is + /// responsible for inserting the path to the clang executable and "-cc1" if + /// desired. + /// \param SA - A function that given a Twine can allocate storage for a given + /// command line argument and return a pointer to the newly allocated string. + /// The returned pointer is what gets appended to Args. + void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args, + StringAllocator SA) const { + generateCC1CommandLine([&](const Twine &Arg) { + // No need to allocate static string literals. + Args.push_back(Arg.isSingleStringLiteral() + ? Arg.getSingleStringRef().data() + : SA(Arg)); + }); } + + using ArgumentConsumer = llvm::function_ref<void(const Twine &)>; + /// Generate cc1-compatible command line arguments from this instance. + /// + /// \param Consumer - Callback that gets invoked for every single generated + /// command line argument. + void generateCC1CommandLine(ArgumentConsumer Consumer) const; + + /// Generate cc1-compatible command line arguments from this instance, + /// wrapping the result as a std::vector<std::string>. + /// + /// This is a (less-efficient) wrapper over generateCC1CommandLine(). + std::vector<std::string> getCC1CommandLine() const; + + /// Generate command line options from DiagnosticOptions. + static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts, + ArgumentConsumer Consumer, + bool DefaultDiagColor); + + /// Generate command line options from LangOptions. + static void GenerateLangArgs(const LangOptions &Opts, + ArgumentConsumer Consumer, const llvm::Triple &T, + InputKind IK); + + // Generate command line options from CodeGenOptions. + static void GenerateCodeGenArgs(const CodeGenOptions &Opts, + ArgumentConsumer Consumer, + const llvm::Triple &T, + const std::string &OutputFile, + const LangOptions *LangOpts); }; /// Helper class for holding the data necessary to invoke the compiler. @@ -191,9 +234,70 @@ class CompilerInvocationValueBase { /// This class is designed to represent an abstract "invocation" of the /// compiler, including data such as the include paths, the code generation /// options, the warning flags, and so on. -class CompilerInvocation : public CompilerInvocationRefBase, - public CompilerInvocationValueBase { +class CompilerInvocation : public CompilerInvocationBase { public: + CompilerInvocation() = default; + + CompilerInvocation(const CompilerInvocation &X) + : CompilerInvocationBase(X, DeepCopy{}) {} + + CompilerInvocation &operator=(const CompilerInvocation &X) { + CompilerInvocationBase::assign(X, DeepCopy{}); + return *this; + } + + // Mutable RefBase accessors. + + LangOptions &getLangOpts() { return *LangOpts; } + TargetOptions &getTargetOpts() { return *TargetOpts; } + DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; } + HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; } + PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; } + AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; } + + // Const RefBase accessors. + + using RefBase::getLangOpts; + using RefBase::getTargetOpts; + using RefBase::getDiagnosticOpts; + using RefBase::getHeaderSearchOpts; + using RefBase::getPreprocessorOpts; + using RefBase::getAnalyzerOpts; + + // Mutable ValBase accessors. + + // clang-format off + MigratorOptions &getMigratorOpts() { return MigratorOpts; } + CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; } + DependencyOutputOptions &getDependencyOutputOpts() { return DependencyOutputOpts; } + FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + FrontendOptions &getFrontendOpts() { return FrontendOpts; } + PreprocessorOutputOptions &getPreprocessorOutputOpts() { return PreprocessorOutputOpts; } + // clang-format on + + // Const ValBase accessors. + + using ValBase::getMigratorOpts; + using ValBase::getCodeGenOpts; + using ValBase::getDependencyOutputOpts; + using ValBase::getFileSystemOpts; + using ValBase::getFrontendOpts; + using ValBase::getPreprocessorOutputOpts; + + /// RefBase innards + + std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const { + return HeaderSearchOpts; + } + + std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() const { + return PreprocessorOpts; + } + + using CompilerInvocationBase::DiagnosticOpts; + using CompilerInvocationBase::TargetOpts; + using CompilerInvocationBase::LangOpts; + /// Create a compiler invocation from a list of input options. /// \returns true on success. /// @@ -224,38 +328,6 @@ class CompilerInvocation : public CompilerInvocationRefBase, /// identifying the conditions under which the module was built. std::string getModuleHash() const; - using StringAllocator = llvm::function_ref<const char *(const Twine &)>; - /// Generate cc1-compatible command line arguments from this instance. - /// - /// \param [out] Args - The generated arguments. Note that the caller is - /// responsible for inserting the path to the clang executable and "-cc1" if - /// desired. - /// \param SA - A function that given a Twine can allocate storage for a given - /// command line argument and return a pointer to the newly allocated string. - /// The returned pointer is what gets appended to Args. - void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args, - StringAllocator SA) const { - generateCC1CommandLine([&](const Twine &Arg) { - // No need to allocate static string literals. - Args.push_back(Arg.isSingleStringLiteral() - ? Arg.getSingleStringRef().data() - : SA(Arg)); - }); - } - - using ArgumentConsumer = llvm::function_ref<void(const Twine &)>; - /// Generate cc1-compatible command line arguments from this instance. - /// - /// \param Consumer - Callback that gets invoked for every single generated - /// command line argument. - void generateCC1CommandLine(ArgumentConsumer Consumer) const; - - /// Generate cc1-compatible command line arguments from this instance, - /// wrapping the result as a std::vector<std::string>. - /// - /// This is a (less-efficient) wrapper over generateCC1CommandLine(). - std::vector<std::string> getCC1CommandLine() const; - /// Check that \p Args can be parsed and re-serialized without change, /// emiting diagnostics for any differences. /// @@ -280,35 +352,70 @@ class CompilerInvocation : public CompilerInvocationRefBase, ArrayRef<const char *> CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0); - /// Generate command line options from DiagnosticOptions. - static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts, - ArgumentConsumer Consumer, - bool DefaultDiagColor); - /// Parse command line options that map to LangOptions. static bool ParseLangArgs(LangOptions &Opts, llvm::opt::ArgList &Args, InputKind IK, const llvm::Triple &T, std::vector<std::string> &Includes, DiagnosticsEngine &Diags); - /// Generate command line options from LangOptions. - static void GenerateLangArgs(const LangOptions &Opts, - ArgumentConsumer Consumer, const llvm::Triple &T, - InputKind IK); - /// Parse command line options that map to CodeGenOptions. static bool ParseCodeGenArgs(CodeGenOptions &Opts, llvm::opt::ArgList &Args, InputKind IK, DiagnosticsEngine &Diags, const llvm::Triple &T, const std::string &OutputFile, const LangOptions &LangOptsRef); +}; - // Generate command line options from CodeGenOptions. - static void GenerateCodeGenArgs(const CodeGenOptions &Opts, - ArgumentConsumer Consumer, - const llvm::Triple &T, - const std::string &OutputFile, - const LangOptions *LangOpts); +/// Same as CompilerInvocation, but copies are on-demand and per-opts-object. +struct CowCompilerInvocation : CompilerInvocationBase { + CowCompilerInvocation(const CompilerInvocation &X) + : CompilerInvocationBase(X, DeepCopy{}) {} + + CowCompilerInvocation(const CowCompilerInvocation &X) + : CompilerInvocationBase(X, ShallowCopy{}) {} + + CowCompilerInvocation &operator=(const CowCompilerInvocation &X) { + CompilerInvocationBase::assign(X, ShallowCopy{}); + return *this; + } + + // Mutable RefBase accessors. + + LangOptions &getMutLangOpts(); + TargetOptions &getMutTargetOpts(); + DiagnosticOptions &getMutDiagnosticOpts(); + HeaderSearchOptions &getMutHeaderSearchOpts(); + PreprocessorOptions &getMutPreprocessorOpts(); + AnalyzerOptions &getMutAnalyzerOpts(); + + // Const RefBase accessors. + + using RefBase::getLangOpts; + using RefBase::getTargetOpts; + using RefBase::getDiagnosticOpts; + using RefBase::getHeaderSearchOpts; + using RefBase::getPreprocessorOpts; + using RefBase::getAnalyzerOpts; + + // Mutable ValBase accessors. + + // clang-format off + MigratorOptions &getMutMigratorOpts() { return MigratorOpts; } + CodeGenOptions &getMutCodeGenOpts() { return CodeGenOpts; } + DependencyOutputOptions &getMutDependencyOutputOpts() { return DependencyOutputOpts; } + FileSystemOptions &getMutFileSystemOpts() { return FileSystemOpts; } + FrontendOptions &getMutFrontendOpts() { return FrontendOpts; } + PreprocessorOutputOptions &getMutPreprocessorOutputOpts() { return PreprocessorOutputOpts; } + // clang-format on + + // Const ValBase accessors. + + using ValBase::getMigratorOpts; + using ValBase::getCodeGenOpts; + using ValBase::getDependencyOutputOpts; + using ValBase::getFileSystemOpts; + using ValBase::getFrontendOpts; + using ValBase::getPreprocessorOutputOpts; }; IntrusiveRefCntPtr<llvm::vfs::FileSystem> diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 11ffb3d6630d1f..3fc354d6cc621d 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -123,49 +123,101 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) { } //===----------------------------------------------------------------------===// -// Initialization. +// Storage details. //===----------------------------------------------------------------------===// -CompilerInvocationRefBase::CompilerInvocationRefBase() - : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), - DiagnosticOpts(new DiagnosticOptions()), - HeaderSearchOpts(new HeaderSearchOptions()), - PreprocessorOpts(new PreprocessorOptions()), - AnalyzerOpts(new AnalyzerOptions()) {} - -CompilerInvocationRefBase::CompilerInvocationRefBase( - const CompilerInvocationRefBase &X) - : LangOpts(new LangOptions(X.getLangOpts())), - TargetOpts(new TargetOptions(X.getTargetOpts())), - DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())), - HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())), - PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())), - AnalyzerOpts(new AnalyzerOptions(X.getAnalyzerOpts())) {} - -CompilerInvocationRefBase::CompilerInvocationRefBase( - CompilerInvocationRefBase &&X) = default; - -CompilerInvocationRefBase & -CompilerInvocationRefBase::operator=(CompilerInvocationRefBase X) { - LangOpts.swap(X.LangOpts); - TargetOpts.swap(X.TargetOpts); - DiagnosticOpts.swap(X.DiagnosticOpts); - HeaderSearchOpts.swap(X.HeaderSearchOpts); - PreprocessorOpts.swap(X.PreprocessorOpts); - AnalyzerOpts.swap(X.AnalyzerOpts); +namespace clang::CompilerInvocationDetail { +namespace { +template <class T> std::shared_ptr<T> make_shared(const T &X) { + return std::make_shared<T>(X); +} + +template <class T> llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(const T &X) { + return llvm::makeIntrusiveRefCnt<T>(X); +} +} // namespace + +RefBase::RefBase() + : LangOpts(std::make_shared<LangOptions>()), + TargetOpts(std::make_shared<TargetOptions>()), + DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()), + HeaderSearchOpts(std::make_shared<HeaderSearchOptions>()), + PreprocessorOpts(std::make_shared<PreprocessorOptions>()), + AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()) {} + +RefBase::RefBase(const RefBase &X, DeepCopy) + : LangOpts(make_shared(*X.LangOpts)), + TargetOpts(make_shared(*X.TargetOpts)), + DiagnosticOpts(makeIntrusiveRefCnt(*X.DiagnosticOpts)), + HeaderSearchOpts(make_shared(*X.HeaderSearchOpts)), + PreprocessorOpts(make_shared(*X.PreprocessorOpts)), + AnalyzerOpts(makeIntrusiveRefCnt(*X.AnalyzerOpts)) {} + +RefBase::RefBase(const RefBase &X, ShallowCopy) + : LangOpts(X.LangOpts), // + TargetOpts(X.TargetOpts), // + DiagnosticOpts(X.DiagnosticOpts), // + HeaderSearchOpts(X.HeaderSearchOpts), // + PreprocessorOpts(X.PreprocessorOpts), // + AnalyzerOpts(X.AnalyzerOpts) {} + +RefBase &RefBase::assign(const RefBase &X, DeepCopy) { + LangOpts = make_shared(*X.LangOpts); + TargetOpts = make_shared(*X.TargetOpts); + DiagnosticOpts = makeIntrusiveRefCnt(*X.DiagnosticOpts); + HeaderSearchOpts = make_shared(*X.HeaderSearchOpts); + PreprocessorOpts = make_shared(*X.PreprocessorOpts); + AnalyzerOpts = makeIntrusiveRefCnt(*X.AnalyzerOpts); return *this; } -CompilerInvocationRefBase & -CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default; +RefBase &RefBase::assign(const RefBase &X, ShallowCopy) { + LangOpts = X.LangOpts; + TargetOpts = X.TargetOpts; + DiagnosticOpts = X.DiagnosticOpts; + HeaderSearchOpts = X.HeaderSearchOpts; + PreprocessorOpts = X.PreprocessorOpts; + AnalyzerOpts = X.AnalyzerOpts; + return *this; +} + +RefBase::RefBase(RefBase &&) = default; +RefBase &RefBase::operator=(RefBase &&) = default; + +RefBase::~RefBase() = default; +} // namespace clang::CompilerInvocationDetail + +namespace { +template <typename T> +T &ensure_owned(std::shared_ptr<T> &Storage) { + if (Storage.use_count() > 1) + Storage = std::make_shared<T>(*Storage); + return *Storage; +} + +template <typename T> +T &ensure_owned(llvm::IntrusiveRefCntPtr<T> &Storage) { + if (Storage.useCount() > 1) + Storage = llvm::makeIntrusiveRefCnt<T>(*Storage); + return *Storage; +} +} // namespace -CompilerInvocationRefBase::~CompilerInvocationRefBase() = default; +// clang-format off +LangOptions &CowCompilerInvocation::getMutLangOpts() { return ensure_owned(LangOpts); } +TargetOptions &CowCompilerInvocation::getMutTargetOpts() { return ensure_owned(TargetOpts); } +DiagnosticOptions &CowCompilerInvocation::getMutDiagnosticOpts() { return ensure_owned(DiagnosticOpts); } +HeaderSearchOptions &CowCompilerInvocation::getMutHeaderSearchOpts() { return ensure_owned(HeaderSearchOpts); } +PreprocessorOptions &CowCompilerInvocation::getMutPreprocessorOpts() { return ensure_owned(PreprocessorOpts); } +AnalyzerOptions &CowCompilerInvocation::getMutAnalyzerOpts() { return ensure_owned(AnalyzerOpts); } +// clang-format on //===----------------------------------------------------------------------===// // Normalizers //===----------------------------------------------------------------------===// -using ArgumentConsumer = CompilerInvocation::ArgumentConsumer; +using ArgumentConsumer = CompilerInvocationBase::ArgumentConsumer; +using StringAllocator = CompilerInvocationBase::StringAllocator; #define SIMPLE_ENUM_VALUE_TABLE #include "clang/Driver/Options.inc" @@ -633,8 +685,7 @@ using ParseFn = // Generate command line arguments from CompilerInvocation. using GenerateFn = llvm::function_ref<void( - CompilerInvocation &, SmallVectorImpl<const char *> &, - CompilerInvocation::StringAllocator)>; + CompilerInvocation &, SmallVectorImpl<const char *> &, StringAllocator)>; /// May perform round-trip of command line arguments. By default, the round-trip /// is enabled in assert builds. This can be overwritten at run-time via the @@ -838,7 +889,7 @@ static void getAllNoBuiltinFuncValues(ArgList &Args, Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd); } -static void GenerateAnalyzerArgs(AnalyzerOptions &Opts, +static void GenerateAnalyzerArgs(const AnalyzerOptions &Opts, ArgumentConsumer Consumer) { const AnalyzerOptions *AnalyzerOpts = &Opts; @@ -1346,11 +1397,11 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, Opts.setProfileUse(CodeGenOptions::ProfileClangInstr); } -void CompilerInvocation::GenerateCodeGenArgs(const CodeGenOptions &Opts, - ArgumentConsumer Consumer, - const llvm::Triple &T, - const std::string &OutputFile, - const LangOptions *LangOpts) { +void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, + ArgumentConsumer Consumer, + const llvm::Triple &T, + const std::string &OutputFile, + const LangOptions *LangOpts) { const CodeGenOptions &CodeGenOpts = Opts; if (Opts.OptimizationLevel == 0) @@ -2254,9 +2305,9 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, const ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } -void CompilerInvocation::GenerateDiagnosticArgs(const DiagnosticOptions &Opts, - ArgumentConsumer Consumer, - bool DefaultDiagColor) { +void CompilerInvocationBase::GenerateDiagnosticArgs( + const DiagnosticOptions &Opts, ArgumentConsumer Consumer, + bool DefaultDiagColor) { const DiagnosticOptions *DiagnosticOpts = &Opts; #define DIAG_OPTION_WITH_MARSHALLING(...) \ GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__) @@ -2917,7 +2968,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } -static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts, +static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, ArgumentConsumer Consumer) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; #define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \ @@ -3247,9 +3298,10 @@ static StringRef GetInputKindName(InputKind IK) { llvm_unreachable("unknown input language"); } -void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, - ArgumentConsumer Consumer, - const llvm::Triple &T, InputKind IK) { +void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts, + ArgumentConsumer Consumer, + const llvm::Triple &T, + InputKind IK) { if (IK.getFormat() == InputKind::Precompiled || IK.getLanguage() == Language::LLVM_IR) { if (Opts.ObjCAutoRefCount) @@ -4103,12 +4155,12 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { llvm_unreachable("invalid frontend action"); } -static void GeneratePreprocessorArgs(PreprocessorOptions &Opts, +static void GeneratePreprocessorArgs(const PreprocessorOptions &Opts, ArgumentConsumer Consumer, const LangOptions &LangOpts, const FrontendOptions &FrontendOpts, const CodeGenOptions &CodeGenOpts) { - PreprocessorOptions *PreprocessorOpts = &Opts; + const PreprocessorOptions *PreprocessorOpts = &Opts; #define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \ GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__) @@ -4507,22 +4559,23 @@ std::string CompilerInvocation::getModuleHash() const { HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); // Extend the signature with the language options -#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name); +#define LANGOPT(Name, Bits, Default, Description) \ + HBuilder.add(getLangOpts().Name); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - HBuilder.add(static_cast<unsigned>(LangOpts->get##Name())); + HBuilder.add(static_cast<unsigned>(getLangOpts().get##Name())); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - HBuilder.addRange(LangOpts->ModuleFeatures); + HBuilder.addRange(getLangOpts().ModuleFeatures); - HBuilder.add(LangOpts->ObjCRuntime); - HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames); + HBuilder.add(getLangOpts().ObjCRuntime); + HBuilder.addRange(getLangOpts().CommentOpts.BlockCommandNames); // Extend the signature with the target options. - HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU, - TargetOpts->ABI); - HBuilder.addRange(TargetOpts->FeaturesAsWritten); + HBuilder.add(getTargetOpts().Triple, getTargetOpts().CPU, + getTargetOpts().TuneCPU, getTargetOpts().ABI); + HBuilder.addRange(getTargetOpts().FeaturesAsWritten); // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); @@ -4577,7 +4630,7 @@ std::string CompilerInvocation::getModuleHash() const { // Extend the signature with the enabled sanitizers, if at least one is // enabled. Sanitizers which cannot affect AST generation aren't hashed. - SanitizerSet SanHash = LangOpts->Sanitize; + SanitizerSet SanHash = getLangOpts().Sanitize; SanHash.clear(getPPTransparentSanitizers()); if (!SanHash.empty()) HBuilder.add(SanHash.Mask); @@ -4588,28 +4641,29 @@ std::string CompilerInvocation::getModuleHash() const { return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false); } -void CompilerInvocation::generateCC1CommandLine( +void CompilerInvocationBase::generateCC1CommandLine( ArgumentConsumer Consumer) const { - llvm::Triple T(TargetOpts->Triple); - - GenerateFileSystemArgs(FileSystemOpts, Consumer); - GenerateMigratorArgs(MigratorOpts, Consumer); - GenerateAnalyzerArgs(*AnalyzerOpts, Consumer); - GenerateDiagnosticArgs(*DiagnosticOpts, Consumer, false); - GenerateFrontendArgs(FrontendOpts, Consumer, LangOpts->IsHeaderFile); - GenerateTargetArgs(*TargetOpts, Consumer); - GenerateHeaderSearchArgs(*HeaderSearchOpts, Consumer); - GenerateLangArgs(*LangOpts, Consumer, T, FrontendOpts.DashX); - GenerateCodeGenArgs(CodeGenOpts, Consumer, T, FrontendOpts.OutputFile, - &*LangOpts); - GeneratePreprocessorArgs(*PreprocessorOpts, Consumer, *LangOpts, FrontendOpts, - CodeGenOpts); - GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Consumer, - FrontendOpts.ProgramAction); - GenerateDependencyOutputArgs(DependencyOutputOpts, Consumer); + llvm::Triple T(getTargetOpts().Triple); + + GenerateFileSystemArgs(getFileSystemOpts(), Consumer); + GenerateMigratorArgs(getMigratorOpts(), Consumer); + GenerateAnalyzerArgs(getAnalyzerOpts(), Consumer); + GenerateDiagnosticArgs(getDiagnosticOpts(), Consumer, false); + GenerateFrontendArgs(getFrontendOpts(), Consumer, + getLangOpts().IsHeaderFile); + GenerateTargetArgs(getTargetOpts(), Consumer); + GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer); + GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX); + GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T, + getFrontendOpts().OutputFile, &getLangOpts()); + GeneratePreprocessorArgs(getPreprocessorOpts(), Consumer, getLangOpts(), + getFrontendOpts(), getCodeGenOpts()); + GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer, + getFrontendOpts().ProgramAction); + GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer); } -std::vector<std::string> CompilerInvocation::getCC1CommandLine() const { +std::vector<std::string> CompilerInvocationBase::getCC1CommandLine() const { std::vector<std::string> Args{"-cc1"}; generateCC1CommandLine( [&Args](const Twine &Arg) { Args.push_back(Arg.str()); }); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits