[clang] [clang] Introduce copy-on-write `CompilerInvocation` (PR #65412)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 7 08:45:40 PDT 2023


================
@@ -154,46 +146,158 @@ 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.
 ///
 /// 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
----------------
jansvoboda11 wrote:

This is supposed to span the next 5 declarations. I should probably switch to using Doxygen's grouping mechanism for this (`@{` and `@}`).

https://github.com/llvm/llvm-project/pull/65412


More information about the cfe-commits mailing list