[clang] [clang][deps] Optimize command line generation (PR #65412)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 5 14:34:38 PDT 2023


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

>From 968fc04bc9bdcc33bb3f9401073343d2f69369f3 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 1 Sep 2023 15:07:23 -0700
Subject: [PATCH 1/6] [llvm][adt] Implement `IntrusiveRefCntPtr::unique()`

---
 llvm/include/llvm/ADT/IntrusiveRefCntPtr.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
index e41eb0639ce30e..5a7f93f4a99363 100644
--- a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
+++ b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
@@ -93,6 +93,8 @@ template <class Derived> class RefCountedBase {
 #endif
 
 public:
+  bool Unique() const { return RefCount == 1; }
+
   void Retain() const { ++RefCount; }
 
   void Release() const {
@@ -124,6 +126,8 @@ template <class Derived> class ThreadSafeRefCountedBase {
 #endif
 
 public:
+  bool Unique() const { return RefCount.load() == 1; }
+
   void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
 
   void Release() const {
@@ -155,6 +159,7 @@ template <class Derived> class ThreadSafeRefCountedBase {
 /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
 /// functions on Foo itself, because Foo would be an incomplete type.
 template <typename T> struct IntrusiveRefCntPtrInfo {
+  static bool unique(T *obj) { return obj->Unique(); }
   static void retain(T *obj) { obj->Retain(); }
   static void release(T *obj) { obj->Release(); }
 };
@@ -213,6 +218,8 @@ template <typename T> class IntrusiveRefCntPtr {
 
   void resetWithoutRelease() { Obj = nullptr; }
 
+  bool unique() { return Obj && IntrusiveRefCntPtrInfo<T>::unique(Obj); }
+
 private:
   void retain() {
     if (Obj)

>From 514ae513549245eadc4046f301f7d6186a6ff81e Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 31 Aug 2023 11:39:32 -0700
Subject: [PATCH 2/6] [clang][ci] 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       | 326 ++++++++++++------
 clang/lib/Frontend/CompilerInvocation.cpp     | 208 ++++++-----
 5 files changed, 355 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..a7c349cd919189 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,6 +66,7 @@ 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
@@ -74,8 +75,8 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
 ///
 /// 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:
+class RefBase {
+protected:
   /// Options controlling the language variant.
   std::shared_ptr<LangOptions> LangOpts;
 
@@ -94,47 +95,36 @@ 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; }
+  // 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;
 
@@ -151,39 +141,89 @@ class CompilerInvocationValueBase {
   FrontendOptions FrontendOpts;
 
   /// Options controlling preprocessed output.
-  PreprocessorOutputOptions PreprocessorOutputOpts;
+  PreprocessorOutputOptions PPOutputOpts;
 
-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 PPOutputOpts; }
+  // 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 +231,76 @@ 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.
+
+  // clang-format off
+  LangOptions &getLangOpts() { return *LangOpts; }
+  TargetOptions &getTargetOpts() { return *TargetOpts; }
+  DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
+  HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
+  PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
+  AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
+  // clang-format on
+
+  // Const RefBase accessors.
+
+  // clang-format off
+  using RefBase::getLangOpts;
+  using RefBase::getTargetOpts;
+  using RefBase::getDiagnosticOpts;
+  using RefBase::getHeaderSearchOpts;
+  using RefBase::getPreprocessorOpts;
+  using RefBase::getAnalyzerOpts;
+  // clang-format on
+
+  // 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 PPOutputOpts; }
+  // clang-format on
+
+  // Const ValBase accessors.
+
+  // clang-format off
+  using ValBase::getMigratorOpts;
+  using ValBase::getCodeGenOpts;
+  using ValBase::getDependencyOutputOpts;
+  using ValBase::getFileSystemOpts;
+  using ValBase::getFrontendOpts;
+  using ValBase::getPreprocessorOutputOpts;
+  // clang-format on
+
+  /// 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 +331,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 +355,76 @@ 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.
+
+  // clang-format off
+  LangOptions &getMutLangOpts();
+  TargetOptions &getMutTargetOpts();
+  DiagnosticOptions &getMutDiagnosticOpts();
+  HeaderSearchOptions &getMutHeaderSearchOpts();
+  PreprocessorOptions &getMutPreprocessorOpts();
+  AnalyzerOptions &getMutAnalyzerOpts();
+  // clang-format on
+
+  // Const RefBase accessors.
+
+  // clang-format off
+  const LangOptions &getConstLangOpts() const { return *LangOpts; }
+  const TargetOptions &getConstTargetOpts() const { return *TargetOpts; }
+  const DiagnosticOptions &getConstDiagnosticOpts() const { return *DiagnosticOpts; }
+  const HeaderSearchOptions &getConstHeaderSearchOpts() const { return *HeaderSearchOpts; }
+  const PreprocessorOptions &getConstPreprocessorOpts() const { return *PreprocessorOpts; }
+  const AnalyzerOptions &getConstAnalyzerOpts() const { return *AnalyzerOpts; }
+  // clang-format on
+
+  // 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 PPOutputOpts; }
+  // clang-format on
+
+  // Const ValBase accessors.
+
+  // clang-format off
+  const MigratorOptions &getConstMigratorOpts() const { return MigratorOpts; }
+  const CodeGenOptions &getConstCodeGenOpts() const { return CodeGenOpts; }
+  const DependencyOutputOptions &getConstDependencyOutputOpts() const { return DependencyOutputOpts; }
+  const FileSystemOptions &getConstFileSystemOpts() const { return FileSystemOpts; }
+  const FrontendOptions &getConstFrontendOpts() const { return FrontendOpts; }
+  const PreprocessorOutputOptions &getConstPreprocessorOutputOpts() const { return PPOutputOpts; }
+  // clang-format on
 };
 
 IntrusiveRefCntPtr<llvm::vfs::FileSystem>
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 11ffb3d6630d1f..41972c7b05f896 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.unique())
+    Storage = std::make_shared<T>(*Storage);
+  return *Storage;
+}
+
+template <typename T>
+T &ensure_owned(llvm::IntrusiveRefCntPtr<T> &Storage) {
+  if (!Storage.unique())
+    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()); });

>From 9ab72be5e1287465245b0d8dc656a0340065b3d3 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 24 Aug 2023 17:33:38 -0700
Subject: [PATCH 3/6] [clang][deps] Store common, partially-formed invocation

---
 .../DependencyScanning/ModuleDepCollector.h   |  17 ++-
 .../DependencyScanning/ModuleDepCollector.cpp | 119 ++++++++++--------
 2 files changed, 81 insertions(+), 55 deletions(-)

diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 914d55eadefe85..1f76314101c20a 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -241,8 +241,10 @@ class ModuleDepCollector final : public DependencyCollector {
   llvm::SetVector<const Module *> DirectModularDeps;
   /// Options that control the dependency output generation.
   std::unique_ptr<DependencyOutputOptions> Opts;
-  /// The original Clang invocation passed to dependency scanner.
-  CompilerInvocation OriginalInvocation;
+  /// Original Clang invocation passed to the dependency scanner that has been
+  /// partially massaged into one that can perform explicit build of a module.
+  /// This still needs to be finalized for each discovered modular dependency.
+  CowCompilerInvocation CommonInvocation;
   /// Whether to optimize the modules' command-line arguments.
   bool OptimizeArgs;
   /// Whether to set up command-lines to load PCM files eagerly.
@@ -265,9 +267,9 @@ class ModuleDepCollector final : public DependencyCollector {
   /// Constructs a CompilerInvocation that can be used to build the given
   /// module, excluding paths to discovered modular dependencies that are yet to
   /// be built.
-  CompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
+  CowCompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
       const ModuleDeps &Deps,
-      llvm::function_ref<void(CompilerInvocation &)> Optimize) const;
+      llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const;
 
   /// Collect module map files for given modules.
   llvm::DenseSet<const FileEntry *>
@@ -279,13 +281,16 @@ class ModuleDepCollector final : public DependencyCollector {
   /// Add module files (pcm) to the invocation, if needed.
   void addModuleFiles(CompilerInvocation &CI,
                       ArrayRef<ModuleID> ClangModuleDeps) const;
+  void addModuleFiles(CowCompilerInvocation &CI,
+                      ArrayRef<ModuleID> ClangModuleDeps) const;
 
   /// Add paths that require looking up outputs to the given dependencies.
-  void addOutputPaths(CompilerInvocation &CI, ModuleDeps &Deps);
+  void addOutputPaths(CowCompilerInvocation &CI, ModuleDeps &Deps);
 
   /// Compute the context hash for \p Deps, and create the mapping
   /// \c ModuleDepsByID[Deps.ID] = &Deps.
-  void associateWithContextHash(const CompilerInvocation &CI, ModuleDeps &Deps);
+  void associateWithContextHash(const CompilerInvocationBase &CI,
+                                ModuleDeps &Deps);
 };
 
 } // end namespace dependencies
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index e13f7c74e9b92e..09289313cb1ebe 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -54,38 +54,33 @@ static std::vector<std::string> splitString(std::string S, char Separator) {
   return Result;
 }
 
-void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI,
+void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
                                         ModuleDeps &Deps) {
-  CI.getFrontendOpts().OutputFile =
+  CI.getMutFrontendOpts().OutputFile =
       Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
-  if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
-    CI.getDiagnosticOpts().DiagnosticSerializationFile =
+  if (!CI.getConstDiagnosticOpts().DiagnosticSerializationFile.empty())
+    CI.getMutDiagnosticOpts().DiagnosticSerializationFile =
         Controller.lookupModuleOutput(
             Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
-  if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
-    CI.getDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput(
+  if (!CI.getConstDependencyOutputOpts().OutputFile.empty()) {
+    CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput(
         Deps.ID, ModuleOutputKind::DependencyFile);
-    CI.getDependencyOutputOpts().Targets =
+    CI.getMutDependencyOutputOpts().Targets =
         splitString(Controller.lookupModuleOutput(
                         Deps.ID, ModuleOutputKind::DependencyTargets),
                     '\0');
-    if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
-        CI.getDependencyOutputOpts().Targets.empty()) {
+    if (!CI.getMutDependencyOutputOpts().OutputFile.empty() &&
+        CI.getMutDependencyOutputOpts().Targets.empty()) {
       // Fallback to -o as dependency target, as in the driver.
       SmallString<128> Target;
-      quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
-      CI.getDependencyOutputOpts().Targets.push_back(std::string(Target));
+      quoteMakeTarget(CI.getConstFrontendOpts().OutputFile, Target);
+      CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
     }
   }
 }
 
-CompilerInvocation
-ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
-    const ModuleDeps &Deps,
-    llvm::function_ref<void(CompilerInvocation &)> Optimize) const {
-  // Make a deep copy of the original Clang invocation.
-  CompilerInvocation CI(OriginalInvocation);
-
+static CowCompilerInvocation
+makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
   CI.resetNonModularOptions();
   CI.clearImplicitModuleBuildOptions();
 
@@ -117,14 +112,37 @@ ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
   CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None;
   CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None;
   CI.getFrontendOpts().MTMigrateDir.clear();
-  CI.getLangOpts().ModuleName = Deps.ID.ModuleName;
-  CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
+
+  // Remove any macro definitions that are explicitly ignored.
+  if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
+    llvm::erase_if(
+        CI.getPreprocessorOpts().Macros,
+        [&CI](const std::pair<std::string, bool> &Def) {
+          StringRef MacroDef = Def.first;
+          return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
+              llvm::CachedHashString(MacroDef.split('=').first));
+        });
+    // Remove the now unused option.
+    CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
+  }
+
+  return CI;
+}
+
+CowCompilerInvocation
+ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
+    const ModuleDeps &Deps,
+    llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
+  CowCompilerInvocation CI = CommonInvocation;
+
+  CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName;
+  CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem;
 
   // Inputs
-  InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
+  InputKind ModuleMapInputKind(CI.getConstFrontendOpts().DashX.getLanguage(),
                                InputKind::Format::ModuleMap);
-  CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
-                                           ModuleMapInputKind);
+  CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
+                                              ModuleMapInputKind);
 
   auto CurrentModuleMapEntry =
       ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
@@ -150,35 +168,23 @@ ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
         !DepModuleMapFiles.contains(*ModuleMapEntry))
       continue;
 
-    CI.getFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
+    CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
   }
 
   // Report the prebuilt modules this module uses.
   for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
-    CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
+    CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
 
   // Add module file inputs from dependencies.
   addModuleFiles(CI, Deps.ClangModuleDeps);
 
-  // Remove any macro definitions that are explicitly ignored.
-  if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
-    llvm::erase_if(
-        CI.getPreprocessorOpts().Macros,
-        [&CI](const std::pair<std::string, bool> &Def) {
-          StringRef MacroDef = Def.first;
-          return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
-              llvm::CachedHashString(MacroDef.split('=').first));
-        });
-    // Remove the now unused option.
-    CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
-  }
-
   // Apply -Wsystem-headers-in-module for the current module.
-  if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
-                         Deps.ID.ModuleName))
-    CI.getDiagnosticOpts().Warnings.push_back("system-headers");
+  if (llvm::is_contained(
+          CI.getConstDiagnosticOpts().SystemHeaderWarningsModules,
+          Deps.ID.ModuleName))
+    CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
   // Remove the now unused option(s).
-  CI.getDiagnosticOpts().SystemHeaderWarningsModules.clear();
+  CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear();
 
   Optimize(CI);
 
@@ -224,6 +230,19 @@ void ModuleDepCollector::addModuleFiles(
   }
 }
 
+void ModuleDepCollector::addModuleFiles(
+    CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
+  for (const ModuleID &MID : ClangModuleDeps) {
+    std::string PCMPath =
+        Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
+    if (EagerLoadModules)
+      CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
+    else
+      CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert(
+          {MID.ModuleName, std::move(PCMPath)});
+  }
+}
+
 static bool needsModules(FrontendInputFile FIF) {
   switch (FIF.getKind().getLanguage()) {
   case Language::Unknown:
@@ -264,7 +283,7 @@ void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
 }
 
 static std::string getModuleContextHash(const ModuleDeps &MD,
-                                        const CompilerInvocation &CI,
+                                        const CompilerInvocationBase &CI,
                                         bool EagerLoadModules) {
   llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
                     llvm::support::endianness::native>
@@ -304,8 +323,8 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
   return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
 }
 
-void ModuleDepCollector::associateWithContextHash(const CompilerInvocation &CI,
-                                                  ModuleDeps &Deps) {
+void ModuleDepCollector::associateWithContextHash(
+    const CompilerInvocationBase &CI, ModuleDeps &Deps) {
   Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules);
   bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
   (void)Inserted;
@@ -498,10 +517,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
         MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
       });
 
-  CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
-      MD, [&](CompilerInvocation &BuildInvocation) {
+  CowCompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
+      MD, [&](CowCompilerInvocation &BuildInvocation) {
         if (MDC.OptimizeArgs)
-          optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(),
+          optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(),
                                    *MDC.ScanInstance.getASTReader(), *MF);
       });
 
@@ -601,7 +620,9 @@ ModuleDepCollector::ModuleDepCollector(
     DependencyActionController &Controller, CompilerInvocation OriginalCI,
     bool OptimizeArgs, bool EagerLoadModules, bool IsStdModuleP1689Format)
     : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
-      Opts(std::move(Opts)), OriginalInvocation(std::move(OriginalCI)),
+      Opts(std::move(Opts)),
+      CommonInvocation(
+          makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
       OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
       IsStdModuleP1689Format(IsStdModuleP1689Format) {}
 

>From b74f4dec1cef70a032ce5ce211addac1de5e949d Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 1 Sep 2023 13:01:24 -0700
Subject: [PATCH 4/6] [clang][deps] Generate command-lines lazily

---
 .../DependencyScanningTool.h                  |  2 +-
 .../DependencyScanning/ModuleDepCollector.h   | 21 +++++++++----
 .../DependencyScanning/ModuleDepCollector.cpp | 29 ++++++++---------
 clang/tools/clang-scan-deps/ClangScanDeps.cpp | 31 +++++++++++++------
 4 files changed, 52 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index cb9476d1550df3..b2cfa621e183c8 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -168,7 +168,7 @@ class FullDependencyConsumer : public DependencyConsumer {
   }
 
   void handleModuleDependency(ModuleDeps MD) override {
-    ClangModuleDeps[MD.ID] = std::move(MD);
+    ClangModuleDeps.insert({MD.ID, std::move(MD)});
   }
 
   void handleDirectModuleDependency(ModuleID ID) override {
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 1f76314101c20a..b7189939caf714 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -104,7 +104,16 @@ enum class ModuleOutputKind {
   DiagnosticSerializationFile,
 };
 
-struct ModuleDeps {
+class ModuleDeps {
+  std::variant<std::shared_ptr<CowCompilerInvocation>, std::vector<std::string>>
+      BuildInvocationOrArguments;
+
+  explicit ModuleDeps(std::shared_ptr<CowCompilerInvocation> CI)
+      : BuildInvocationOrArguments(std::move(CI)) {}
+
+  friend class ModuleDepCollectorPP;
+
+public:
   /// The identifier of the module.
   ModuleID ID;
 
@@ -136,9 +145,9 @@ struct ModuleDeps {
   /// determined that the differences are benign for this compilation.
   std::vector<ModuleID> ClangModuleDeps;
 
-  /// Compiler invocation that can be used to build this module. Does not
-  /// include argv[0].
-  std::vector<std::string> BuildArguments;
+  /// Get (or compute) the compiler invocation that can be used to build this
+  /// module. Does not include argv[0].
+  const std::vector<std::string> &getBuildArguments();
 };
 
 class ModuleDepCollector;
@@ -267,8 +276,8 @@ class ModuleDepCollector final : public DependencyCollector {
   /// Constructs a CompilerInvocation that can be used to build the given
   /// module, excluding paths to discovered modular dependencies that are yet to
   /// be built.
-  CowCompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
-      const ModuleDeps &Deps,
+  void makeInvocationForModuleBuildWithoutOutputs(
+      CowCompilerInvocation &CI, const ModuleDeps &Deps,
       llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const;
 
   /// Collect module map files for given modules.
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 09289313cb1ebe..ef10ad18b6314b 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -21,6 +21,13 @@ using namespace clang;
 using namespace tooling;
 using namespace dependencies;
 
+const std::vector<std::string> &ModuleDeps::getBuildArguments() {
+  if (auto *CI = std::get_if<std::shared_ptr<CowCompilerInvocation>>(
+          &BuildInvocationOrArguments))
+    BuildInvocationOrArguments = (*CI)->getCC1CommandLine();
+  return std::get<std::vector<std::string>>(BuildInvocationOrArguments);
+}
+
 static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
                                      ASTReader &Reader,
                                      const serialization::ModuleFile &MF) {
@@ -129,12 +136,9 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
   return CI;
 }
 
-CowCompilerInvocation
-ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
-    const ModuleDeps &Deps,
+void ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
+    CowCompilerInvocation &CI, const ModuleDeps &Deps,
     llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
-  CowCompilerInvocation CI = CommonInvocation;
-
   CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName;
   CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem;
 
@@ -187,8 +191,6 @@ ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
   CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear();
 
   Optimize(CI);
-
-  return CI;
 }
 
 llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
@@ -466,7 +468,8 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
   if (!ModI.second)
     return ModI.first->second->ID;
 
-  ModI.first->second = std::make_unique<ModuleDeps>();
+  auto CI = std::make_shared<CowCompilerInvocation>(MDC.CommonInvocation);
+  ModI.first->second.reset(new ModuleDeps(CI));
   ModuleDeps &MD = *ModI.first->second;
 
   MD.ID.ModuleName = M->getFullModuleName();
@@ -517,19 +520,17 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
         MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
       });
 
-  CowCompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
-      MD, [&](CowCompilerInvocation &BuildInvocation) {
+  MDC.makeInvocationForModuleBuildWithoutOutputs(
+      *CI, MD, [&](CowCompilerInvocation &BuildInvocation) {
         if (MDC.OptimizeArgs)
           optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(),
                                    *MDC.ScanInstance.getASTReader(), *MF);
       });
 
-  MDC.associateWithContextHash(CI, MD);
+  MDC.associateWithContextHash(*CI, MD);
 
   // Finish the compiler invocation. Requires dependencies and the context hash.
-  MDC.addOutputPaths(CI, MD);
-
-  MD.BuildArguments = CI.getCC1CommandLine();
+  MDC.addOutputPaths(*CI, MD);
 
   return MD.ID;
 }
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index dab3de42b7fa1a..7491d6c284fe12 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -351,14 +351,23 @@ class FullDeps {
   }
 
   void mergeDeps(ModuleDepsGraph Graph, size_t InputIndex) {
-    std::unique_lock<std::mutex> ul(Lock);
-    for (const ModuleDeps &MD : Graph) {
-      auto I = Modules.find({MD.ID, 0});
-      if (I != Modules.end()) {
-        I->first.InputIndex = std::min(I->first.InputIndex, InputIndex);
-        continue;
+    std::vector<ModuleDeps *> NewMDs;
+    {
+      std::unique_lock<std::mutex> ul(Lock);
+      for (const ModuleDeps &MD : Graph) {
+        auto I = Modules.find({MD.ID, 0});
+        if (I != Modules.end()) {
+          I->first.InputIndex = std::min(I->first.InputIndex, InputIndex);
+          continue;
+        }
+        auto Res = Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
+        NewMDs.push_back(&Res->second);
       }
-      Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
+      // First call to \c getBuildArguments is somewhat expensive. Let's call it
+      // on the current thread (instead of the main one), and outside the
+      // critical section.
+      for (ModuleDeps *MD : NewMDs)
+        MD->getBuildArguments();
     }
   }
 
@@ -382,7 +391,7 @@ class FullDeps {
                                             /*ShouldOwnClient=*/false);
 
     for (auto &&M : Modules)
-      if (roundTripCommand(M.second.BuildArguments, *Diags))
+      if (roundTripCommand(M.second.getBuildArguments(), *Diags))
         return true;
 
     for (auto &&I : Inputs)
@@ -404,14 +413,16 @@ class FullDeps {
 
     Array OutModules;
     for (auto &&ModID : ModuleIDs) {
-      auto &MD = Modules[ModID];
+      auto It = Modules.find(ModID);
+      assert(It != Modules.end());
+      auto &MD = It->second;
       Object O{
           {"name", MD.ID.ModuleName},
           {"context-hash", MD.ID.ContextHash},
           {"file-deps", toJSONSorted(MD.FileDeps)},
           {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
           {"clang-modulemap-file", MD.ClangModuleMapFile},
-          {"command-line", MD.BuildArguments},
+          {"command-line", MD.getBuildArguments()},
       };
       OutModules.push_back(std::move(O));
     }

>From b83741bd2032ab05bdf040a5c9d3ed9c1bd1c8c8 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 1 Sep 2023 14:45:48 -0700
Subject: [PATCH 5/6] [clang][cli][deps] Make CodeGenOpts copy-on-write

---
 .../include/clang/Frontend/CompilerInvocation.h  | 16 ++++++++--------
 clang/lib/Frontend/CompilerInvocation.cpp        |  6 ++++++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index a7c349cd919189..3d5a7fdf99cb6e 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -92,6 +92,9 @@ class RefBase {
   /// Options controlling the preprocessor (aside from \#include handling).
   std::shared_ptr<PreprocessorOptions> PreprocessorOpts;
 
+  /// Options controlling IRgen and the backend.
+  std::shared_ptr<CodeGenOptions> CodeGenOpts;
+
   /// Options controlling the static analyzer.
   AnalyzerOptionsRef AnalyzerOpts;
 
@@ -119,6 +122,7 @@ class RefBase {
   const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
   const HeaderSearchOptions &getHeaderSearchOpts() const { return *HeaderSearchOpts; }
   const PreprocessorOptions &getPreprocessorOpts() const { return *PreprocessorOpts; }
+  const CodeGenOptions &getCodeGenOpts() const { return *CodeGenOpts; }
   const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
   // clang-format on
 };
@@ -128,9 +132,6 @@ class ValBase {
 protected:
   MigratorOptions MigratorOpts;
 
-  /// Options controlling IRgen and the backend.
-  CodeGenOptions CodeGenOpts;
-
   /// Options controlling dependency output.
   DependencyOutputOptions DependencyOutputOpts;
 
@@ -145,7 +146,6 @@ class ValBase {
 
   // clang-format off
   const MigratorOptions &getMigratorOpts() const { return MigratorOpts; }
-  const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
   const DependencyOutputOptions &getDependencyOutputOpts() const { return DependencyOutputOpts; }
   const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
   const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }
@@ -251,6 +251,7 @@ class CompilerInvocation : public CompilerInvocationBase {
   DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
   HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
   PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
+  CodeGenOptions &getCodeGenOpts() { return *CodeGenOpts; }
   AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
   // clang-format on
 
@@ -262,6 +263,7 @@ class CompilerInvocation : public CompilerInvocationBase {
   using RefBase::getDiagnosticOpts;
   using RefBase::getHeaderSearchOpts;
   using RefBase::getPreprocessorOpts;
+  using RefBase::getCodeGenOpts;
   using RefBase::getAnalyzerOpts;
   // clang-format on
 
@@ -269,7 +271,6 @@ class CompilerInvocation : public CompilerInvocationBase {
 
   // clang-format off
   MigratorOptions &getMigratorOpts() { return MigratorOpts; }
-  CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
   DependencyOutputOptions &getDependencyOutputOpts() { return DependencyOutputOpts; }
   FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
   FrontendOptions &getFrontendOpts() { return FrontendOpts; }
@@ -280,7 +281,6 @@ class CompilerInvocation : public CompilerInvocationBase {
 
   // clang-format off
   using ValBase::getMigratorOpts;
-  using ValBase::getCodeGenOpts;
   using ValBase::getDependencyOutputOpts;
   using ValBase::getFileSystemOpts;
   using ValBase::getFrontendOpts;
@@ -390,6 +390,7 @@ struct CowCompilerInvocation : CompilerInvocationBase {
   DiagnosticOptions &getMutDiagnosticOpts();
   HeaderSearchOptions &getMutHeaderSearchOpts();
   PreprocessorOptions &getMutPreprocessorOpts();
+  CodeGenOptions &getMutCodeGenOpts();
   AnalyzerOptions &getMutAnalyzerOpts();
   // clang-format on
 
@@ -401,6 +402,7 @@ struct CowCompilerInvocation : CompilerInvocationBase {
   const DiagnosticOptions &getConstDiagnosticOpts() const { return *DiagnosticOpts; }
   const HeaderSearchOptions &getConstHeaderSearchOpts() const { return *HeaderSearchOpts; }
   const PreprocessorOptions &getConstPreprocessorOpts() const { return *PreprocessorOpts; }
+  const CodeGenOptions &getConstCodeGenOpts() const { return *CodeGenOpts; }
   const AnalyzerOptions &getConstAnalyzerOpts() const { return *AnalyzerOpts; }
   // clang-format on
 
@@ -408,7 +410,6 @@ struct CowCompilerInvocation : CompilerInvocationBase {
 
   // clang-format off
   MigratorOptions &getMutMigratorOpts() { return MigratorOpts; }
-  CodeGenOptions &getMutCodeGenOpts() { return CodeGenOpts; }
   DependencyOutputOptions &getMutDependencyOutputOpts() { return DependencyOutputOpts; }
   FileSystemOptions &getMutFileSystemOpts() { return FileSystemOpts; }
   FrontendOptions &getMutFrontendOpts() { return FrontendOpts; }
@@ -419,7 +420,6 @@ struct CowCompilerInvocation : CompilerInvocationBase {
 
   // clang-format off
   const MigratorOptions &getConstMigratorOpts() const { return MigratorOpts; }
-  const CodeGenOptions &getConstCodeGenOpts() const { return CodeGenOpts; }
   const DependencyOutputOptions &getConstDependencyOutputOpts() const { return DependencyOutputOpts; }
   const FileSystemOptions &getConstFileSystemOpts() const { return FileSystemOpts; }
   const FrontendOptions &getConstFrontendOpts() const { return FrontendOpts; }
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 41972c7b05f896..ba586fcac6bd29 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -143,6 +143,7 @@ RefBase::RefBase()
       DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
       HeaderSearchOpts(std::make_shared<HeaderSearchOptions>()),
       PreprocessorOpts(std::make_shared<PreprocessorOptions>()),
+      CodeGenOpts(std::make_shared<CodeGenOptions>()),
       AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()) {}
 
 RefBase::RefBase(const RefBase &X, DeepCopy)
@@ -151,6 +152,7 @@ RefBase::RefBase(const RefBase &X, DeepCopy)
       DiagnosticOpts(makeIntrusiveRefCnt(*X.DiagnosticOpts)),
       HeaderSearchOpts(make_shared(*X.HeaderSearchOpts)),
       PreprocessorOpts(make_shared(*X.PreprocessorOpts)),
+      CodeGenOpts(make_shared(*X.CodeGenOpts)),
       AnalyzerOpts(makeIntrusiveRefCnt(*X.AnalyzerOpts)) {}
 
 RefBase::RefBase(const RefBase &X, ShallowCopy)
@@ -159,6 +161,7 @@ RefBase::RefBase(const RefBase &X, ShallowCopy)
       DiagnosticOpts(X.DiagnosticOpts),     //
       HeaderSearchOpts(X.HeaderSearchOpts), //
       PreprocessorOpts(X.PreprocessorOpts), //
+      CodeGenOpts(X.CodeGenOpts),           //
       AnalyzerOpts(X.AnalyzerOpts) {}
 
 RefBase &RefBase::assign(const RefBase &X, DeepCopy) {
@@ -168,6 +171,7 @@ RefBase &RefBase::assign(const RefBase &X, DeepCopy) {
   HeaderSearchOpts = make_shared(*X.HeaderSearchOpts);
   PreprocessorOpts = make_shared(*X.PreprocessorOpts);
   AnalyzerOpts = makeIntrusiveRefCnt(*X.AnalyzerOpts);
+  CodeGenOpts = make_shared(*X.CodeGenOpts);
   return *this;
 }
 
@@ -177,6 +181,7 @@ RefBase &RefBase::assign(const RefBase &X, ShallowCopy) {
   DiagnosticOpts = X.DiagnosticOpts;
   HeaderSearchOpts = X.HeaderSearchOpts;
   PreprocessorOpts = X.PreprocessorOpts;
+  CodeGenOpts = X.CodeGenOpts;
   AnalyzerOpts = X.AnalyzerOpts;
   return *this;
 }
@@ -209,6 +214,7 @@ TargetOptions &CowCompilerInvocation::getMutTargetOpts() { return ensure_owned(T
 DiagnosticOptions &CowCompilerInvocation::getMutDiagnosticOpts() { return ensure_owned(DiagnosticOpts); }
 HeaderSearchOptions &CowCompilerInvocation::getMutHeaderSearchOpts() { return ensure_owned(HeaderSearchOpts); }
 PreprocessorOptions &CowCompilerInvocation::getMutPreprocessorOpts() { return ensure_owned(PreprocessorOpts); }
+CodeGenOptions &CowCompilerInvocation::getMutCodeGenOpts() { return ensure_owned(CodeGenOpts); }
 AnalyzerOptions &CowCompilerInvocation::getMutAnalyzerOpts() { return ensure_owned(AnalyzerOpts); }
 // clang-format on
 

>From 8bd2e9887d11fd3ea77444acf622521e860c875f Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 1 Sep 2023 13:01:24 -0700
Subject: [PATCH 6/6] [clang][deps] Generate command-lines lazily

---
 .../clang/Tooling/DependencyScanning/ModuleDepCollector.h       | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index b7189939caf714..5ed76de665d2c9 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -20,9 +20,11 @@
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/raw_ostream.h"
+#include <memory>
 #include <optional>
 #include <string>
 #include <unordered_map>
+#include <variant>
 
 namespace clang {
 namespace tooling {



More information about the cfe-commits mailing list