[clang] 8345265 - [clang] Abstract away string allocation in command line generation

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 3 20:35:21 PDT 2023


Author: Jan Svoboda
Date: 2023-08-03T20:35:00-07:00
New Revision: 83452650490eb1021939129682b01fcdff34c691

URL: https://github.com/llvm/llvm-project/commit/83452650490eb1021939129682b01fcdff34c691
DIFF: https://github.com/llvm/llvm-project/commit/83452650490eb1021939129682b01fcdff34c691.diff

LOG: [clang] Abstract away string allocation in command line generation

This patch abstracts away the string allocation and vector push-back from command line generation. Instead, **all** generated arguments are passed into `ArgumentConsumer`, which may choose to do the string allocation and vector push-back, or something else entirely.

Reviewed By: benlangmuir

Differential Revision: https://reviews.llvm.org/D157046

Added: 
    

Modified: 
    clang/include/clang/Frontend/CompilerInvocation.h
    clang/lib/Frontend/CompilerInvocation.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 1dbd1eda62b3f2..4142499f2dd703 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -223,7 +223,7 @@ 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 llvm::Twine &)>;
+  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
@@ -233,7 +233,21 @@ class CompilerInvocation : public CompilerInvocationRefBase,
   /// 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;
+                              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>.
@@ -267,8 +281,8 @@ class CompilerInvocation : public CompilerInvocationRefBase,
 
   /// Generate command line options from DiagnosticOptions.
   static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
-                                     SmallVectorImpl<const char *> &Args,
-                                     StringAllocator SA, bool DefaultDiagColor);
+                                     ArgumentConsumer Consumer,
+                                     bool DefaultDiagColor);
 
   /// Parse command line options that map to LangOptions.
   static bool ParseLangArgs(LangOptions &Opts, llvm::opt::ArgList &Args,
@@ -278,8 +292,7 @@ class CompilerInvocation : public CompilerInvocationRefBase,
 
   /// Generate command line options from LangOptions.
   static void GenerateLangArgs(const LangOptions &Opts,
-                               SmallVectorImpl<const char *> &Args,
-                               StringAllocator SA, const llvm::Triple &T,
+                               ArgumentConsumer Consumer, const llvm::Triple &T,
                                InputKind IK);
 
   /// Parse command line options that map to CodeGenOptions.
@@ -291,8 +304,8 @@ class CompilerInvocation : public CompilerInvocationRefBase,
 
   // Generate command line options from CodeGenOptions.
   static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
-                                  SmallVectorImpl<const char *> &Args,
-                                  StringAllocator SA, const llvm::Triple &T,
+                                  ArgumentConsumer Consumer,
+                                  const llvm::Triple &T,
                                   const std::string &OutputFile,
                                   const LangOptions *LangOpts);
 };

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 1e990f4663d44f..2e2f1de36482fa 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -165,6 +165,8 @@ CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
 // Normalizers
 //===----------------------------------------------------------------------===//
 
+using ArgumentConsumer = CompilerInvocation::ArgumentConsumer;
+
 #define SIMPLE_ENUM_VALUE_TABLE
 #include "clang/Driver/Options.inc"
 #undef SIMPLE_ENUM_VALUE_TABLE
@@ -191,13 +193,10 @@ static std::optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt,
 /// denormalizeSimpleFlags never looks at it. Avoid bloating compile-time with
 /// unnecessary template instantiations and just ignore it with a variadic
 /// argument.
-static void denormalizeSimpleFlag(SmallVectorImpl<const char *> &Args,
-                                  const Twine &Spelling,
-                                  CompilerInvocation::StringAllocator,
-                                  Option::OptionClass, unsigned, /*T*/...) {
-  // Spelling is already allocated or a static string, no need to call SA.
-  assert(*Spelling.getSingleStringRef().end() == '\0');
-  Args.push_back(Spelling.getSingleStringRef().data());
+static void denormalizeSimpleFlag(ArgumentConsumer Consumer,
+                                  const Twine &Spelling, Option::OptionClass,
+                                  unsigned, /*T*/...) {
+  Consumer(Spelling);
 }
 
 template <typename T> static constexpr bool is_uint64_t_convertible() {
@@ -234,34 +233,27 @@ static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue,
 }
 
 static auto makeBooleanOptionDenormalizer(bool Value) {
-  return [Value](SmallVectorImpl<const char *> &Args, const Twine &Spelling,
-                 CompilerInvocation::StringAllocator, Option::OptionClass,
-                 unsigned, bool KeyPath) {
-    if (KeyPath == Value) {
-      // Spelling is already allocated or a static string, no need to call SA.
-      assert(*Spelling.getSingleStringRef().end() == '\0');
-      Args.push_back(Spelling.getSingleStringRef().data());
-    }
+  return [Value](ArgumentConsumer Consumer, const Twine &Spelling,
+                 Option::OptionClass, unsigned, bool KeyPath) {
+    if (KeyPath == Value)
+      Consumer(Spelling);
   };
 }
 
-static void denormalizeStringImpl(SmallVectorImpl<const char *> &Args,
+static void denormalizeStringImpl(ArgumentConsumer Consumer,
                                   const Twine &Spelling,
-                                  CompilerInvocation::StringAllocator SA,
                                   Option::OptionClass OptClass, unsigned,
                                   const Twine &Value) {
   switch (OptClass) {
   case Option::SeparateClass:
   case Option::JoinedOrSeparateClass:
   case Option::JoinedAndSeparateClass:
-    // Spelling is already allocated or a static string, no need to call SA.
-    assert(*Spelling.getSingleStringRef().end() == '\0');
-    Args.push_back(Spelling.getSingleStringRef().data());
-    Args.push_back(SA(Value));
+    Consumer(Spelling);
+    Consumer(Value);
     break;
   case Option::JoinedClass:
   case Option::CommaJoinedClass:
-    Args.push_back(SA(Twine(Spelling) + Value));
+    Consumer(Spelling + Value);
     break;
   default:
     llvm_unreachable("Cannot denormalize an option with option class "
@@ -270,11 +262,10 @@ static void denormalizeStringImpl(SmallVectorImpl<const char *> &Args,
 }
 
 template <typename T>
-static void
-denormalizeString(SmallVectorImpl<const char *> &Args, const Twine &Spelling,
-                  CompilerInvocation::StringAllocator SA,
-                  Option::OptionClass OptClass, unsigned TableIndex, T Value) {
-  denormalizeStringImpl(Args, Spelling, SA, OptClass, TableIndex, Twine(Value));
+static void denormalizeString(ArgumentConsumer Consumer, const Twine &Spelling,
+                              Option::OptionClass OptClass, unsigned TableIndex,
+                              T Value) {
+  denormalizeStringImpl(Consumer, Spelling, OptClass, TableIndex, Twine(Value));
 }
 
 static std::optional<SimpleEnumValue>
@@ -315,15 +306,14 @@ static std::optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
   return std::nullopt;
 }
 
-static void denormalizeSimpleEnumImpl(SmallVectorImpl<const char *> &Args,
+static void denormalizeSimpleEnumImpl(ArgumentConsumer Consumer,
                                       const Twine &Spelling,
-                                      CompilerInvocation::StringAllocator SA,
                                       Option::OptionClass OptClass,
                                       unsigned TableIndex, unsigned Value) {
   assert(TableIndex < SimpleEnumValueTablesSize);
   const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
   if (auto MaybeEnumVal = findValueTableByValue(Table, Value)) {
-    denormalizeString(Args, Spelling, SA, OptClass, TableIndex,
+    denormalizeString(Consumer, Spelling, OptClass, TableIndex,
                       MaybeEnumVal->Name);
   } else {
     llvm_unreachable("The simple enum value was not correctly defined in "
@@ -332,12 +322,11 @@ static void denormalizeSimpleEnumImpl(SmallVectorImpl<const char *> &Args,
 }
 
 template <typename T>
-static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
+static void denormalizeSimpleEnum(ArgumentConsumer Consumer,
                                   const Twine &Spelling,
-                                  CompilerInvocation::StringAllocator SA,
                                   Option::OptionClass OptClass,
                                   unsigned TableIndex, T Value) {
-  return denormalizeSimpleEnumImpl(Args, Spelling, SA, OptClass, TableIndex,
+  return denormalizeSimpleEnumImpl(Consumer, Spelling, OptClass, TableIndex,
                                    static_cast<unsigned>(Value));
 }
 
@@ -373,9 +362,8 @@ normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args,
   return Args.getAllArgValues(Opt);
 }
 
-static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
+static void denormalizeStringVector(ArgumentConsumer Consumer,
                                     const Twine &Spelling,
-                                    CompilerInvocation::StringAllocator SA,
                                     Option::OptionClass OptClass,
                                     unsigned TableIndex,
                                     const std::vector<std::string> &Values) {
@@ -389,7 +377,7 @@ static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
         CommaJoinedValue.append(Value);
       }
     }
-    denormalizeString(Args, Spelling, SA, Option::OptionClass::JoinedClass,
+    denormalizeString(Consumer, Spelling, Option::OptionClass::JoinedClass,
                       TableIndex, CommaJoinedValue);
     break;
   }
@@ -397,7 +385,7 @@ static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
   case Option::SeparateClass:
   case Option::JoinedOrSeparateClass:
     for (const std::string &Value : Values)
-      denormalizeString(Args, Spelling, SA, OptClass, TableIndex, Value);
+      denormalizeString(Consumer, Spelling, OptClass, TableIndex, Value);
     break;
   default:
     llvm_unreachable("Cannot denormalize an option with option class "
@@ -451,18 +439,18 @@ static T extractMaskValue(T KeyPath) {
 // Capture the extracted value as a lambda argument to avoid potential issues
 // with lifetime extension of the reference.
 #define GENERATE_OPTION_WITH_MARSHALLING(                                      \
-    ARGS, STRING_ALLOCATOR, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS,         \
-    ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, VALUES, SPELLING,              \
-    SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK,          \
-    IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX)   \
+    CONSUMER, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,     \
+    PARAM, HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT,     \
+    KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER,          \
+    DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX)                              \
   if ((FLAGS)&options::CC1Option) {                                            \
     [&](const auto &Extracted) {                                               \
       if (ALWAYS_EMIT ||                                                       \
           (Extracted !=                                                        \
            static_cast<decltype(KEYPATH)>((IMPLIED_CHECK) ? (IMPLIED_VALUE)    \
                                                           : (DEFAULT_VALUE)))) \
-        DENORMALIZER(ARGS, SPELLING, STRING_ALLOCATOR, Option::KIND##Class,    \
-                     TABLE_INDEX, Extracted);                                  \
+        DENORMALIZER(CONSUMER, SPELLING, Option::KIND##Class, TABLE_INDEX,     \
+                     Extracted);                                               \
     }(EXTRACTOR(KEYPATH));                                                     \
   }
 
@@ -624,21 +612,19 @@ static unsigned getOptimizationLevelSize(ArgList &Args) {
   return 0;
 }
 
-static void GenerateArg(SmallVectorImpl<const char *> &Args,
-                        llvm::opt::OptSpecifier OptSpecifier,
-                        CompilerInvocation::StringAllocator SA) {
+static void GenerateArg(ArgumentConsumer Consumer,
+                        llvm::opt::OptSpecifier OptSpecifier) {
   Option Opt = getDriverOptTable().getOption(OptSpecifier);
-  denormalizeSimpleFlag(Args, SA(Opt.getPrefix() + Opt.getName()), SA,
+  denormalizeSimpleFlag(Consumer, Opt.getPrefix() + Opt.getName(),
                         Option::OptionClass::FlagClass, 0);
 }
 
-static void GenerateArg(SmallVectorImpl<const char *> &Args,
+static void GenerateArg(ArgumentConsumer Consumer,
                         llvm::opt::OptSpecifier OptSpecifier,
-                        const Twine &Value,
-                        CompilerInvocation::StringAllocator SA) {
+                        const Twine &Value) {
   Option Opt = getDriverOptTable().getOption(OptSpecifier);
-  denormalizeString(Args, SA(Opt.getPrefix() + Opt.getName()), SA,
-                    Opt.getKind(), 0, Value);
+  denormalizeString(Consumer, Opt.getPrefix() + Opt.getName(), Opt.getKind(), 0,
+                    Value);
 }
 
 // Parse command line arguments into CompilerInvocation.
@@ -854,12 +840,11 @@ static void getAllNoBuiltinFuncValues(ArgList &Args,
 }
 
 static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
-                                 SmallVectorImpl<const char *> &Args,
-                                 CompilerInvocation::StringAllocator SA) {
+                                 ArgumentConsumer Consumer) {
   const AnalyzerOptions *AnalyzerOpts = &Opts;
 
 #define ANALYZER_OPTION_WITH_MARSHALLING(...)                                  \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef ANALYZER_OPTION_WITH_MARSHALLING
 
@@ -867,7 +852,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
     switch (Opts.AnalysisConstraintsOpt) {
 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)                     \
   case NAME##Model:                                                            \
-    GenerateArg(Args, OPT_analyzer_constraints, CMDFLAG, SA);                  \
+    GenerateArg(Consumer, OPT_analyzer_constraints, CMDFLAG);                  \
     break;
 #include "clang/StaticAnalyzer/Core/Analyses.def"
     default:
@@ -879,7 +864,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
     switch (Opts.AnalysisDiagOpt) {
 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN)                     \
   case PD_##NAME:                                                              \
-    GenerateArg(Args, OPT_analyzer_output, CMDFLAG, SA);                       \
+    GenerateArg(Consumer, OPT_analyzer_output, CMDFLAG);                       \
     break;
 #include "clang/StaticAnalyzer/Core/Analyses.def"
     default:
@@ -891,7 +876,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
     switch (Opts.AnalysisPurgeOpt) {
 #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC)                                    \
   case NAME:                                                                   \
-    GenerateArg(Args, OPT_analyzer_purge, CMDFLAG, SA);                        \
+    GenerateArg(Consumer, OPT_analyzer_purge, CMDFLAG);                        \
     break;
 #include "clang/StaticAnalyzer/Core/Analyses.def"
     default:
@@ -903,7 +888,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
     switch (Opts.InliningMode) {
 #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC)                            \
   case NAME:                                                                   \
-    GenerateArg(Args, OPT_analyzer_inlining_mode, CMDFLAG, SA);                \
+    GenerateArg(Consumer, OPT_analyzer_inlining_mode, CMDFLAG);                \
     break;
 #include "clang/StaticAnalyzer/Core/Analyses.def"
     default:
@@ -914,7 +899,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
   for (const auto &CP : Opts.CheckersAndPackages) {
     OptSpecifier Opt =
         CP.second ? OPT_analyzer_checker : OPT_analyzer_disable_checker;
-    GenerateArg(Args, Opt, CP.first, SA);
+    GenerateArg(Consumer, Opt, CP.first);
   }
 
   AnalyzerOptions ConfigOpts;
@@ -933,7 +918,7 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
     if (Entry != ConfigOpts.Config.end() && Entry->getValue() == Value)
       continue;
 
-    GenerateArg(Args, OPT_analyzer_config, Key + "=" + Value, SA);
+    GenerateArg(Consumer, OPT_analyzer_config, Key + "=" + Value);
   }
 
   // Nothing to generate for FullCompilerInvocation.
@@ -1199,16 +1184,15 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
 
 /// Generate a remark argument. This is an inverse of `ParseOptimizationRemark`.
 static void
-GenerateOptimizationRemark(SmallVectorImpl<const char *> &Args,
-                           CompilerInvocation::StringAllocator SA,
-                           OptSpecifier OptEQ, StringRef Name,
+GenerateOptimizationRemark(ArgumentConsumer Consumer, OptSpecifier OptEQ,
+                           StringRef Name,
                            const CodeGenOptions::OptRemark &Remark) {
   if (Remark.hasValidPattern()) {
-    GenerateArg(Args, OptEQ, Remark.Pattern, SA);
+    GenerateArg(Consumer, OptEQ, Remark.Pattern);
   } else if (Remark.Kind == CodeGenOptions::RK_Enabled) {
-    GenerateArg(Args, OPT_R_Joined, Name, SA);
+    GenerateArg(Consumer, OPT_R_Joined, Name);
   } else if (Remark.Kind == CodeGenOptions::RK_Disabled) {
-    GenerateArg(Args, OPT_R_Joined, StringRef("no-") + Name, SA);
+    GenerateArg(Consumer, OPT_R_Joined, StringRef("no-") + Name);
   }
 }
 
@@ -1363,35 +1347,36 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
     Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
 }
 
-void CompilerInvocation::GenerateCodeGenArgs(
-    const CodeGenOptions &Opts, SmallVectorImpl<const char *> &Args,
-    StringAllocator SA, const llvm::Triple &T, const std::string &OutputFile,
-    const LangOptions *LangOpts) {
+void CompilerInvocation::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)
-    GenerateArg(Args, OPT_O0, SA);
+    GenerateArg(Consumer, OPT_O0);
   else
-    GenerateArg(Args, OPT_O, Twine(Opts.OptimizationLevel), SA);
+    GenerateArg(Consumer, OPT_O, Twine(Opts.OptimizationLevel));
 
 #define CODEGEN_OPTION_WITH_MARSHALLING(...)                                   \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef CODEGEN_OPTION_WITH_MARSHALLING
 
   if (Opts.OptimizationLevel > 0) {
     if (Opts.Inlining == CodeGenOptions::NormalInlining)
-      GenerateArg(Args, OPT_finline_functions, SA);
+      GenerateArg(Consumer, OPT_finline_functions);
     else if (Opts.Inlining == CodeGenOptions::OnlyHintInlining)
-      GenerateArg(Args, OPT_finline_hint_functions, SA);
+      GenerateArg(Consumer, OPT_finline_hint_functions);
     else if (Opts.Inlining == CodeGenOptions::OnlyAlwaysInlining)
-      GenerateArg(Args, OPT_fno_inline, SA);
+      GenerateArg(Consumer, OPT_fno_inline);
   }
 
   if (Opts.DirectAccessExternalData && LangOpts->PICLevel != 0)
-    GenerateArg(Args, OPT_fdirect_access_external_data, SA);
+    GenerateArg(Consumer, OPT_fdirect_access_external_data);
   else if (!Opts.DirectAccessExternalData && LangOpts->PICLevel == 0)
-    GenerateArg(Args, OPT_fno_direct_access_external_data, SA);
+    GenerateArg(Consumer, OPT_fno_direct_access_external_data);
 
   std::optional<StringRef> DebugInfoVal;
   switch (Opts.DebugInfo) {
@@ -1421,23 +1406,23 @@ void CompilerInvocation::GenerateCodeGenArgs(
     break;
   }
   if (DebugInfoVal)
-    GenerateArg(Args, OPT_debug_info_kind_EQ, *DebugInfoVal, SA);
+    GenerateArg(Consumer, OPT_debug_info_kind_EQ, *DebugInfoVal);
 
   for (const auto &Prefix : Opts.DebugPrefixMap)
-    GenerateArg(Args, OPT_fdebug_prefix_map_EQ,
-                Prefix.first + "=" + Prefix.second, SA);
+    GenerateArg(Consumer, OPT_fdebug_prefix_map_EQ,
+                Prefix.first + "=" + Prefix.second);
 
   for (const auto &Prefix : Opts.CoveragePrefixMap)
-    GenerateArg(Args, OPT_fcoverage_prefix_map_EQ,
-                Prefix.first + "=" + Prefix.second, SA);
+    GenerateArg(Consumer, OPT_fcoverage_prefix_map_EQ,
+                Prefix.first + "=" + Prefix.second);
 
   if (Opts.NewStructPathTBAA)
-    GenerateArg(Args, OPT_new_struct_path_tbaa, SA);
+    GenerateArg(Consumer, OPT_new_struct_path_tbaa);
 
   if (Opts.OptimizeSize == 1)
-    GenerateArg(Args, OPT_O, "s", SA);
+    GenerateArg(Consumer, OPT_O, "s");
   else if (Opts.OptimizeSize == 2)
-    GenerateArg(Args, OPT_O, "z", SA);
+    GenerateArg(Consumer, OPT_O, "z");
 
   // SimplifyLibCalls is set only in the absence of -fno-builtin and
   // -ffreestanding. We'll consider that when generating them.
@@ -1445,65 +1430,65 @@ void CompilerInvocation::GenerateCodeGenArgs(
   // NoBuiltinFuncs are generated by LangOptions.
 
   if (Opts.UnrollLoops && Opts.OptimizationLevel <= 1)
-    GenerateArg(Args, OPT_funroll_loops, SA);
+    GenerateArg(Consumer, OPT_funroll_loops);
   else if (!Opts.UnrollLoops && Opts.OptimizationLevel > 1)
-    GenerateArg(Args, OPT_fno_unroll_loops, SA);
+    GenerateArg(Consumer, OPT_fno_unroll_loops);
 
   if (!Opts.BinutilsVersion.empty())
-    GenerateArg(Args, OPT_fbinutils_version_EQ, Opts.BinutilsVersion, SA);
+    GenerateArg(Consumer, OPT_fbinutils_version_EQ, Opts.BinutilsVersion);
 
   if (Opts.DebugNameTable ==
       static_cast<unsigned>(llvm::DICompileUnit::DebugNameTableKind::GNU))
-    GenerateArg(Args, OPT_ggnu_pubnames, SA);
+    GenerateArg(Consumer, OPT_ggnu_pubnames);
   else if (Opts.DebugNameTable ==
            static_cast<unsigned>(
                llvm::DICompileUnit::DebugNameTableKind::Default))
-    GenerateArg(Args, OPT_gpubnames, SA);
+    GenerateArg(Consumer, OPT_gpubnames);
 
   auto TNK = Opts.getDebugSimpleTemplateNames();
   if (TNK != llvm::codegenoptions::DebugTemplateNamesKind::Full) {
     if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Simple)
-      GenerateArg(Args, OPT_gsimple_template_names_EQ, "simple", SA);
+      GenerateArg(Consumer, OPT_gsimple_template_names_EQ, "simple");
     else if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Mangled)
-      GenerateArg(Args, OPT_gsimple_template_names_EQ, "mangled", SA);
+      GenerateArg(Consumer, OPT_gsimple_template_names_EQ, "mangled");
   }
   // ProfileInstrumentUsePath is marshalled automatically, no need to generate
   // it or PGOUseInstrumentor.
 
   if (Opts.TimePasses) {
     if (Opts.TimePassesPerRun)
-      GenerateArg(Args, OPT_ftime_report_EQ, "per-pass-run", SA);
+      GenerateArg(Consumer, OPT_ftime_report_EQ, "per-pass-run");
     else
-      GenerateArg(Args, OPT_ftime_report, SA);
+      GenerateArg(Consumer, OPT_ftime_report);
   }
 
   if (Opts.PrepareForLTO && !Opts.PrepareForThinLTO)
-    GenerateArg(Args, OPT_flto_EQ, "full", SA);
+    GenerateArg(Consumer, OPT_flto_EQ, "full");
 
   if (Opts.PrepareForThinLTO)
-    GenerateArg(Args, OPT_flto_EQ, "thin", SA);
+    GenerateArg(Consumer, OPT_flto_EQ, "thin");
 
   if (!Opts.ThinLTOIndexFile.empty())
-    GenerateArg(Args, OPT_fthinlto_index_EQ, Opts.ThinLTOIndexFile, SA);
+    GenerateArg(Consumer, OPT_fthinlto_index_EQ, Opts.ThinLTOIndexFile);
 
   if (Opts.SaveTempsFilePrefix == OutputFile)
-    GenerateArg(Args, OPT_save_temps_EQ, "obj", SA);
+    GenerateArg(Consumer, OPT_save_temps_EQ, "obj");
 
   StringRef MemProfileBasename("memprof.profraw");
   if (!Opts.MemoryProfileOutput.empty()) {
     if (Opts.MemoryProfileOutput == MemProfileBasename) {
-      GenerateArg(Args, OPT_fmemory_profile, SA);
+      GenerateArg(Consumer, OPT_fmemory_profile);
     } else {
       size_t ArgLength =
           Opts.MemoryProfileOutput.size() - MemProfileBasename.size();
-      GenerateArg(Args, OPT_fmemory_profile_EQ,
-                  Opts.MemoryProfileOutput.substr(0, ArgLength), SA);
+      GenerateArg(Consumer, OPT_fmemory_profile_EQ,
+                  Opts.MemoryProfileOutput.substr(0, ArgLength));
     }
   }
 
   if (memcmp(Opts.CoverageVersion, "408*", 4) != 0)
-    GenerateArg(Args, OPT_coverage_version_EQ,
-                StringRef(Opts.CoverageVersion, 4), SA);
+    GenerateArg(Consumer, OPT_coverage_version_EQ,
+                StringRef(Opts.CoverageVersion, 4));
 
   // TODO: Check if we need to generate arguments stored in CmdArgs. (Namely
   //  '-fembed_bitcode', which does not map to any CompilerInvocation field and
@@ -1513,95 +1498,94 @@ void CompilerInvocation::GenerateCodeGenArgs(
     std::string InstrBundle =
         serializeXRayInstrumentationBundle(Opts.XRayInstrumentationBundle);
     if (!InstrBundle.empty())
-      GenerateArg(Args, OPT_fxray_instrumentation_bundle, InstrBundle, SA);
+      GenerateArg(Consumer, OPT_fxray_instrumentation_bundle, InstrBundle);
   }
 
   if (Opts.CFProtectionReturn && Opts.CFProtectionBranch)
-    GenerateArg(Args, OPT_fcf_protection_EQ, "full", SA);
+    GenerateArg(Consumer, OPT_fcf_protection_EQ, "full");
   else if (Opts.CFProtectionReturn)
-    GenerateArg(Args, OPT_fcf_protection_EQ, "return", SA);
+    GenerateArg(Consumer, OPT_fcf_protection_EQ, "return");
   else if (Opts.CFProtectionBranch)
-    GenerateArg(Args, OPT_fcf_protection_EQ, "branch", SA);
+    GenerateArg(Consumer, OPT_fcf_protection_EQ, "branch");
 
   if (Opts.FunctionReturnThunks)
-    GenerateArg(Args, OPT_mfunction_return_EQ, "thunk-extern", SA);
+    GenerateArg(Consumer, OPT_mfunction_return_EQ, "thunk-extern");
 
   for (const auto &F : Opts.LinkBitcodeFiles) {
     bool Builtint = F.LinkFlags == llvm::Linker::Flags::LinkOnlyNeeded &&
                     F.PropagateAttrs && F.Internalize;
-    GenerateArg(Args,
+    GenerateArg(Consumer,
                 Builtint ? OPT_mlink_builtin_bitcode : OPT_mlink_bitcode_file,
-                F.Filename, SA);
+                F.Filename);
   }
 
   if (Opts.EmulatedTLS)
-    GenerateArg(Args, OPT_femulated_tls, SA);
+    GenerateArg(Consumer, OPT_femulated_tls);
 
   if (Opts.FPDenormalMode != llvm::DenormalMode::getIEEE())
-    GenerateArg(Args, OPT_fdenormal_fp_math_EQ, Opts.FPDenormalMode.str(), SA);
+    GenerateArg(Consumer, OPT_fdenormal_fp_math_EQ, Opts.FPDenormalMode.str());
 
   if ((Opts.FPDenormalMode != Opts.FP32DenormalMode) ||
       (Opts.FP32DenormalMode != llvm::DenormalMode::getIEEE()))
-    GenerateArg(Args, OPT_fdenormal_fp_math_f32_EQ, Opts.FP32DenormalMode.str(),
-                SA);
+    GenerateArg(Consumer, OPT_fdenormal_fp_math_f32_EQ,
+                Opts.FP32DenormalMode.str());
 
   if (Opts.StructReturnConvention == CodeGenOptions::SRCK_OnStack) {
     OptSpecifier Opt =
         T.isPPC32() ? OPT_maix_struct_return : OPT_fpcc_struct_return;
-    GenerateArg(Args, Opt, SA);
+    GenerateArg(Consumer, Opt);
   } else if (Opts.StructReturnConvention == CodeGenOptions::SRCK_InRegs) {
     OptSpecifier Opt =
         T.isPPC32() ? OPT_msvr4_struct_return : OPT_freg_struct_return;
-    GenerateArg(Args, Opt, SA);
+    GenerateArg(Consumer, Opt);
   }
 
   if (Opts.EnableAIXExtendedAltivecABI)
-    GenerateArg(Args, OPT_mabi_EQ_vec_extabi, SA);
+    GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi);
 
   if (Opts.XCOFFReadOnlyPointers)
-    GenerateArg(Args, OPT_mxcoff_roptr, SA);
+    GenerateArg(Consumer, OPT_mxcoff_roptr);
 
   if (!Opts.OptRecordPasses.empty())
-    GenerateArg(Args, OPT_opt_record_passes, Opts.OptRecordPasses, SA);
+    GenerateArg(Consumer, OPT_opt_record_passes, Opts.OptRecordPasses);
 
   if (!Opts.OptRecordFormat.empty())
-    GenerateArg(Args, OPT_opt_record_format, Opts.OptRecordFormat, SA);
+    GenerateArg(Consumer, OPT_opt_record_format, Opts.OptRecordFormat);
 
-  GenerateOptimizationRemark(Args, SA, OPT_Rpass_EQ, "pass",
+  GenerateOptimizationRemark(Consumer, OPT_Rpass_EQ, "pass",
                              Opts.OptimizationRemark);
 
-  GenerateOptimizationRemark(Args, SA, OPT_Rpass_missed_EQ, "pass-missed",
+  GenerateOptimizationRemark(Consumer, OPT_Rpass_missed_EQ, "pass-missed",
                              Opts.OptimizationRemarkMissed);
 
-  GenerateOptimizationRemark(Args, SA, OPT_Rpass_analysis_EQ, "pass-analysis",
+  GenerateOptimizationRemark(Consumer, OPT_Rpass_analysis_EQ, "pass-analysis",
                              Opts.OptimizationRemarkAnalysis);
 
-  GenerateArg(Args, OPT_fdiagnostics_hotness_threshold_EQ,
+  GenerateArg(Consumer, OPT_fdiagnostics_hotness_threshold_EQ,
               Opts.DiagnosticsHotnessThreshold
                   ? Twine(*Opts.DiagnosticsHotnessThreshold)
-                  : "auto",
-              SA);
+                  : "auto");
 
-  GenerateArg(Args, OPT_fdiagnostics_misexpect_tolerance_EQ,
-              Twine(*Opts.DiagnosticsMisExpectTolerance), SA);
+  GenerateArg(Consumer, OPT_fdiagnostics_misexpect_tolerance_EQ,
+              Twine(*Opts.DiagnosticsMisExpectTolerance));
 
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeRecover))
-    GenerateArg(Args, OPT_fsanitize_recover_EQ, Sanitizer, SA);
+    GenerateArg(Consumer, OPT_fsanitize_recover_EQ, Sanitizer);
 
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
-    GenerateArg(Args, OPT_fsanitize_trap_EQ, Sanitizer, SA);
+    GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer);
 
   if (!Opts.EmitVersionIdentMetadata)
-    GenerateArg(Args, OPT_Qn, SA);
+    GenerateArg(Consumer, OPT_Qn);
 
   switch (Opts.FiniteLoops) {
   case CodeGenOptions::FiniteLoopsKind::Language:
     break;
   case CodeGenOptions::FiniteLoopsKind::Always:
-    GenerateArg(Args, OPT_ffinite_loops, SA);
+    GenerateArg(Consumer, OPT_ffinite_loops);
     break;
   case CodeGenOptions::FiniteLoopsKind::Never:
-    GenerateArg(Args, OPT_fno_finite_loops, SA);
+    GenerateArg(Consumer, OPT_fno_finite_loops);
     break;
   }
 }
@@ -2074,18 +2058,16 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
-static void
-GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
-                             SmallVectorImpl<const char *> &Args,
-                             CompilerInvocation::StringAllocator SA) {
+static void GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
+                                         ArgumentConsumer Consumer) {
   const DependencyOutputOptions &DependencyOutputOpts = Opts;
 #define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING(...)                         \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING
 
   if (Opts.ShowIncludesDest != ShowIncludesDestination::None)
-    GenerateArg(Args, OPT_show_includes, SA);
+    GenerateArg(Consumer, OPT_show_includes);
 
   for (const auto &Dep : Opts.ExtraDeps) {
     switch (Dep.second) {
@@ -2101,7 +2083,7 @@ GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
       // marshalling infrastructure.
       continue;
     case EDK_DepFileEntry:
-      GenerateArg(Args, OPT_fdepfile_entry, Dep.first, SA);
+      GenerateArg(Consumer, OPT_fdepfile_entry, Dep.first);
       break;
     }
   }
@@ -2227,12 +2209,11 @@ static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes,
 }
 
 static void GenerateFileSystemArgs(const FileSystemOptions &Opts,
-                                   SmallVectorImpl<const char *> &Args,
-                                   CompilerInvocation::StringAllocator SA) {
+                                   ArgumentConsumer Consumer) {
   const FileSystemOptions &FileSystemOpts = Opts;
 
 #define FILE_SYSTEM_OPTION_WITH_MARSHALLING(...)                               \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef FILE_SYSTEM_OPTION_WITH_MARSHALLING
 }
@@ -2252,11 +2233,10 @@ static bool ParseFileSystemArgs(FileSystemOptions &Opts, const ArgList &Args,
 }
 
 static void GenerateMigratorArgs(const MigratorOptions &Opts,
-                                 SmallVectorImpl<const char *> &Args,
-                                 CompilerInvocation::StringAllocator SA) {
+                                 ArgumentConsumer Consumer) {
   const MigratorOptions &MigratorOpts = Opts;
 #define MIGRATOR_OPTION_WITH_MARSHALLING(...)                                  \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef MIGRATOR_OPTION_WITH_MARSHALLING
 }
@@ -2275,51 +2255,51 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, const ArgList &Args,
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
-void CompilerInvocation::GenerateDiagnosticArgs(
-    const DiagnosticOptions &Opts, SmallVectorImpl<const char *> &Args,
-    StringAllocator SA, bool DefaultDiagColor) {
+void CompilerInvocation::GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
+                                                ArgumentConsumer Consumer,
+                                                bool DefaultDiagColor) {
   const DiagnosticOptions *DiagnosticOpts = &Opts;
 #define DIAG_OPTION_WITH_MARSHALLING(...)                                      \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef DIAG_OPTION_WITH_MARSHALLING
 
   if (!Opts.DiagnosticSerializationFile.empty())
-    GenerateArg(Args, OPT_diagnostic_serialized_file,
-                Opts.DiagnosticSerializationFile, SA);
+    GenerateArg(Consumer, OPT_diagnostic_serialized_file,
+                Opts.DiagnosticSerializationFile);
 
   if (Opts.ShowColors)
-    GenerateArg(Args, OPT_fcolor_diagnostics, SA);
+    GenerateArg(Consumer, OPT_fcolor_diagnostics);
 
   if (Opts.VerifyDiagnostics &&
       llvm::is_contained(Opts.VerifyPrefixes, "expected"))
-    GenerateArg(Args, OPT_verify, SA);
+    GenerateArg(Consumer, OPT_verify);
 
   for (const auto &Prefix : Opts.VerifyPrefixes)
     if (Prefix != "expected")
-      GenerateArg(Args, OPT_verify_EQ, Prefix, SA);
+      GenerateArg(Consumer, OPT_verify_EQ, Prefix);
 
   DiagnosticLevelMask VIU = Opts.getVerifyIgnoreUnexpected();
   if (VIU == DiagnosticLevelMask::None) {
     // This is the default, don't generate anything.
   } else if (VIU == DiagnosticLevelMask::All) {
-    GenerateArg(Args, OPT_verify_ignore_unexpected, SA);
+    GenerateArg(Consumer, OPT_verify_ignore_unexpected);
   } else {
     if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Note) != 0)
-      GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "note", SA);
+      GenerateArg(Consumer, OPT_verify_ignore_unexpected_EQ, "note");
     if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Remark) != 0)
-      GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "remark", SA);
+      GenerateArg(Consumer, OPT_verify_ignore_unexpected_EQ, "remark");
     if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Warning) != 0)
-      GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "warning", SA);
+      GenerateArg(Consumer, OPT_verify_ignore_unexpected_EQ, "warning");
     if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Error) != 0)
-      GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "error", SA);
+      GenerateArg(Consumer, OPT_verify_ignore_unexpected_EQ, "error");
   }
 
   for (const auto &Warning : Opts.Warnings) {
     // This option is automatically generated from UndefPrefixes.
     if (Warning == "undef-prefix")
       continue;
-    Args.push_back(SA(StringRef("-W") + Warning));
+    Consumer(StringRef("-W") + Warning);
   }
 
   for (const auto &Remark : Opts.Remarks) {
@@ -2331,7 +2311,7 @@ void CompilerInvocation::GenerateDiagnosticArgs(
     if (llvm::is_contained(IgnoredRemarks, Remark))
       continue;
 
-    Args.push_back(SA(StringRef("-R") + Remark));
+    Consumer(StringRef("-R") + Remark);
   }
 }
 
@@ -2517,12 +2497,10 @@ getProgramActionOpt(frontend::ActionKind ProgramAction) {
 }
 
 static void GenerateFrontendArgs(const FrontendOptions &Opts,
-                                 SmallVectorImpl<const char *> &Args,
-                                 CompilerInvocation::StringAllocator SA,
-                                 bool IsHeader) {
+                                 ArgumentConsumer Consumer, bool IsHeader) {
   const FrontendOptions &FrontendOpts = Opts;
 #define FRONTEND_OPTION_WITH_MARSHALLING(...)                                  \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef FRONTEND_OPTION_WITH_MARSHALLING
 
@@ -2531,7 +2509,7 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
 
   // Generating a simple flag covers most frontend actions.
   std::function<void()> GenerateProgramAction = [&]() {
-    GenerateArg(Args, *ProgramActionOpt, SA);
+    GenerateArg(Consumer, *ProgramActionOpt);
   };
 
   if (!ProgramActionOpt) {
@@ -2539,7 +2517,7 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
     assert(Opts.ProgramAction == frontend::PluginAction &&
            "Frontend action without option.");
     GenerateProgramAction = [&]() {
-      GenerateArg(Args, OPT_plugin, Opts.ActionName, SA);
+      GenerateArg(Consumer, OPT_plugin, Opts.ActionName);
     };
   }
 
@@ -2560,21 +2538,21 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
         }
 
         if (Opts.ASTDumpAll)
-          GenerateArg(Args, OPT_ast_dump_all_EQ, Format, SA);
+          GenerateArg(Consumer, OPT_ast_dump_all_EQ, Format);
         if (Opts.ASTDumpDecls)
-          GenerateArg(Args, OPT_ast_dump_EQ, Format, SA);
+          GenerateArg(Consumer, OPT_ast_dump_EQ, Format);
       } else {
         if (Opts.ASTDumpAll)
-          GenerateArg(Args, OPT_ast_dump_all, SA);
+          GenerateArg(Consumer, OPT_ast_dump_all);
         if (Opts.ASTDumpDecls)
-          GenerateArg(Args, OPT_ast_dump, SA);
+          GenerateArg(Consumer, OPT_ast_dump);
       }
     };
   }
 
   if (Opts.ProgramAction == frontend::FixIt && !Opts.FixItSuffix.empty()) {
     GenerateProgramAction = [&]() {
-      GenerateArg(Args, OPT_fixit_EQ, Opts.FixItSuffix, SA);
+      GenerateArg(Consumer, OPT_fixit_EQ, Opts.FixItSuffix);
     };
   }
 
@@ -2582,34 +2560,34 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
 
   for (const auto &PluginArgs : Opts.PluginArgs) {
     Option Opt = getDriverOptTable().getOption(OPT_plugin_arg);
-    const char *Spelling =
-        SA(Opt.getPrefix() + Opt.getName() + PluginArgs.first);
     for (const auto &PluginArg : PluginArgs.second)
-      denormalizeString(Args, Spelling, SA, Opt.getKind(), 0, PluginArg);
+      denormalizeString(Consumer,
+                        Opt.getPrefix() + Opt.getName() + PluginArgs.first,
+                        Opt.getKind(), 0, PluginArg);
   }
 
   for (const auto &Ext : Opts.ModuleFileExtensions)
     if (auto *TestExt = dyn_cast_or_null<TestModuleFileExtension>(Ext.get()))
-      GenerateArg(Args, OPT_ftest_module_file_extension_EQ, TestExt->str(), SA);
+      GenerateArg(Consumer, OPT_ftest_module_file_extension_EQ, TestExt->str());
 
   if (!Opts.CodeCompletionAt.FileName.empty())
-    GenerateArg(Args, OPT_code_completion_at, Opts.CodeCompletionAt.ToString(),
-                SA);
+    GenerateArg(Consumer, OPT_code_completion_at,
+                Opts.CodeCompletionAt.ToString());
 
   for (const auto &Plugin : Opts.Plugins)
-    GenerateArg(Args, OPT_load, Plugin, SA);
+    GenerateArg(Consumer, OPT_load, Plugin);
 
   // ASTDumpDecls and ASTDumpAll already handled with ProgramAction.
 
   for (const auto &ModuleFile : Opts.ModuleFiles)
-    GenerateArg(Args, OPT_fmodule_file, ModuleFile, SA);
+    GenerateArg(Consumer, OPT_fmodule_file, ModuleFile);
 
   if (Opts.AuxTargetCPU)
-    GenerateArg(Args, OPT_aux_target_cpu, *Opts.AuxTargetCPU, SA);
+    GenerateArg(Consumer, OPT_aux_target_cpu, *Opts.AuxTargetCPU);
 
   if (Opts.AuxTargetFeatures)
     for (const auto &Feature : *Opts.AuxTargetFeatures)
-      GenerateArg(Args, OPT_aux_target_feature, Feature, SA);
+      GenerateArg(Consumer, OPT_aux_target_feature, Feature);
 
   {
     StringRef Preprocessed = Opts.DashX.isPreprocessed() ? "-cpp-output" : "";
@@ -2676,13 +2654,13 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
       break;
     }
 
-    GenerateArg(Args, OPT_x,
-                Lang + HeaderUnit + Header + ModuleMap + Preprocessed, SA);
+    GenerateArg(Consumer, OPT_x,
+                Lang + HeaderUnit + Header + ModuleMap + Preprocessed);
   }
 
   // OPT_INPUT has a unique class, generate it directly.
   for (const auto &Input : Opts.Inputs)
-    Args.push_back(SA(Input.getFile()));
+    Consumer(Input.getFile());
 }
 
 static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
@@ -2941,28 +2919,27 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
 }
 
 static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
-                                     SmallVectorImpl<const char *> &Args,
-                                     CompilerInvocation::StringAllocator SA) {
+                                     ArgumentConsumer Consumer) {
   const HeaderSearchOptions *HeaderSearchOpts = &Opts;
 #define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...)                             \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef HEADER_SEARCH_OPTION_WITH_MARSHALLING
 
   if (Opts.UseLibcxx)
-    GenerateArg(Args, OPT_stdlib_EQ, "libc++", SA);
+    GenerateArg(Consumer, OPT_stdlib_EQ, "libc++");
 
   if (!Opts.ModuleCachePath.empty())
-    GenerateArg(Args, OPT_fmodules_cache_path, Opts.ModuleCachePath, SA);
+    GenerateArg(Consumer, OPT_fmodules_cache_path, Opts.ModuleCachePath);
 
   for (const auto &File : Opts.PrebuiltModuleFiles)
-    GenerateArg(Args, OPT_fmodule_file, File.first + "=" + File.second, SA);
+    GenerateArg(Consumer, OPT_fmodule_file, File.first + "=" + File.second);
 
   for (const auto &Path : Opts.PrebuiltModulePaths)
-    GenerateArg(Args, OPT_fprebuilt_module_path, Path, SA);
+    GenerateArg(Consumer, OPT_fprebuilt_module_path, Path);
 
   for (const auto &Macro : Opts.ModulesIgnoreMacros)
-    GenerateArg(Args, OPT_fmodules_ignore_macro, Macro.val(), SA);
+    GenerateArg(Consumer, OPT_fmodules_ignore_macro, Macro.val());
 
   auto Matches = [](const HeaderSearchOptions::Entry &Entry,
                     llvm::ArrayRef<frontend::IncludeDirGroup> Groups,
@@ -2993,8 +2970,8 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
     }();
 
     if (It->Group == frontend::IndexHeaderMap)
-      GenerateArg(Args, OPT_index_header_map, SA);
-    GenerateArg(Args, Opt, It->Path, SA);
+      GenerateArg(Consumer, OPT_index_header_map);
+    GenerateArg(Consumer, Opt, It->Path);
   };
 
   // Note: some paths that came from "[-iprefix=xx] -iwithprefixbefore=yy" may
@@ -3006,34 +2983,34 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
        ++It) {
     OptSpecifier Opt =
         It->Group == frontend::After ? OPT_iwithprefix : OPT_iwithprefixbefore;
-    GenerateArg(Args, Opt, It->Path, SA);
+    GenerateArg(Consumer, Opt, It->Path);
   }
 
   // Note: Some paths that came from "-idirafter=xxyy" may have already been
   // generated as "-iwithprefix=xxyy". If that's the case, their position on
   // command line was such that this has no semantic impact on include paths.
   for (; It < End && Matches(*It, {frontend::After}, false, true); ++It)
-    GenerateArg(Args, OPT_idirafter, It->Path, SA);
+    GenerateArg(Consumer, OPT_idirafter, It->Path);
   for (; It < End && Matches(*It, {frontend::Quoted}, false, true); ++It)
-    GenerateArg(Args, OPT_iquote, It->Path, SA);
+    GenerateArg(Consumer, OPT_iquote, It->Path);
   for (; It < End && Matches(*It, {frontend::System}, false, std::nullopt);
        ++It)
-    GenerateArg(Args, It->IgnoreSysRoot ? OPT_isystem : OPT_iwithsysroot,
-                It->Path, SA);
+    GenerateArg(Consumer, It->IgnoreSysRoot ? OPT_isystem : OPT_iwithsysroot,
+                It->Path);
   for (; It < End && Matches(*It, {frontend::System}, true, true); ++It)
-    GenerateArg(Args, OPT_iframework, It->Path, SA);
+    GenerateArg(Consumer, OPT_iframework, It->Path);
   for (; It < End && Matches(*It, {frontend::System}, true, false); ++It)
-    GenerateArg(Args, OPT_iframeworkwithsysroot, It->Path, SA);
+    GenerateArg(Consumer, OPT_iframeworkwithsysroot, It->Path);
 
   // Add the paths for the various language specific isystem flags.
   for (; It < End && Matches(*It, {frontend::CSystem}, false, true); ++It)
-    GenerateArg(Args, OPT_c_isystem, It->Path, SA);
+    GenerateArg(Consumer, OPT_c_isystem, It->Path);
   for (; It < End && Matches(*It, {frontend::CXXSystem}, false, true); ++It)
-    GenerateArg(Args, OPT_cxx_isystem, It->Path, SA);
+    GenerateArg(Consumer, OPT_cxx_isystem, It->Path);
   for (; It < End && Matches(*It, {frontend::ObjCSystem}, false, true); ++It)
-    GenerateArg(Args, OPT_objc_isystem, It->Path, SA);
+    GenerateArg(Consumer, OPT_objc_isystem, It->Path);
   for (; It < End && Matches(*It, {frontend::ObjCXXSystem}, false, true); ++It)
-    GenerateArg(Args, OPT_objcxx_isystem, It->Path, SA);
+    GenerateArg(Consumer, OPT_objcxx_isystem, It->Path);
 
   // Add the internal paths from a driver that detects standard include paths.
   // Note: Some paths that came from "-internal-isystem" arguments may have
@@ -3045,7 +3022,7 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
     OptSpecifier Opt = It->Group == frontend::System
                            ? OPT_internal_isystem
                            : OPT_internal_externc_isystem;
-    GenerateArg(Args, Opt, It->Path, SA);
+    GenerateArg(Consumer, Opt, It->Path);
   }
 
   assert(It == End && "Unhandled HeaderSearchOption::Entry.");
@@ -3054,11 +3031,11 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
   for (const auto &P : Opts.SystemHeaderPrefixes) {
     OptSpecifier Opt = P.IsSystemHeader ? OPT_system_header_prefix
                                         : OPT_no_system_header_prefix;
-    GenerateArg(Args, Opt, P.Prefix, SA);
+    GenerateArg(Consumer, Opt, P.Prefix);
   }
 
   for (const std::string &F : Opts.VFSOverlayFiles)
-    GenerateArg(Args, OPT_ivfsoverlay, F, SA);
+    GenerateArg(Consumer, OPT_ivfsoverlay, F);
 }
 
 static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
@@ -3272,19 +3249,18 @@ static StringRef GetInputKindName(InputKind IK) {
 }
 
 void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
-                                          SmallVectorImpl<const char *> &Args,
-                                          StringAllocator SA,
+                                          ArgumentConsumer Consumer,
                                           const llvm::Triple &T, InputKind IK) {
   if (IK.getFormat() == InputKind::Precompiled ||
       IK.getLanguage() == Language::LLVM_IR) {
     if (Opts.ObjCAutoRefCount)
-      GenerateArg(Args, OPT_fobjc_arc, SA);
+      GenerateArg(Consumer, OPT_fobjc_arc);
     if (Opts.PICLevel != 0)
-      GenerateArg(Args, OPT_pic_level, Twine(Opts.PICLevel), SA);
+      GenerateArg(Consumer, OPT_pic_level, Twine(Opts.PICLevel));
     if (Opts.PIE)
-      GenerateArg(Args, OPT_pic_is_pie, SA);
+      GenerateArg(Consumer, OPT_pic_is_pie);
     for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
-      GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
+      GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
 
     return;
   }
@@ -3306,145 +3282,145 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
   }
 
   auto LangStandard = LangStandard::getLangStandardForKind(Opts.LangStd);
-  GenerateArg(Args, StdOpt, LangStandard.getName(), SA);
+  GenerateArg(Consumer, StdOpt, LangStandard.getName());
 
   if (Opts.IncludeDefaultHeader)
-    GenerateArg(Args, OPT_finclude_default_header, SA);
+    GenerateArg(Consumer, OPT_finclude_default_header);
   if (Opts.DeclareOpenCLBuiltins)
-    GenerateArg(Args, OPT_fdeclare_opencl_builtins, SA);
+    GenerateArg(Consumer, OPT_fdeclare_opencl_builtins);
 
   const LangOptions *LangOpts = &Opts;
 
 #define LANG_OPTION_WITH_MARSHALLING(...)                                      \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef LANG_OPTION_WITH_MARSHALLING
 
   // The '-fcf-protection=' option is generated by CodeGenOpts generator.
 
   if (Opts.ObjC) {
-    GenerateArg(Args, OPT_fobjc_runtime_EQ, Opts.ObjCRuntime.getAsString(), SA);
+    GenerateArg(Consumer, OPT_fobjc_runtime_EQ, Opts.ObjCRuntime.getAsString());
 
     if (Opts.GC == LangOptions::GCOnly)
-      GenerateArg(Args, OPT_fobjc_gc_only, SA);
+      GenerateArg(Consumer, OPT_fobjc_gc_only);
     else if (Opts.GC == LangOptions::HybridGC)
-      GenerateArg(Args, OPT_fobjc_gc, SA);
+      GenerateArg(Consumer, OPT_fobjc_gc);
     else if (Opts.ObjCAutoRefCount == 1)
-      GenerateArg(Args, OPT_fobjc_arc, SA);
+      GenerateArg(Consumer, OPT_fobjc_arc);
 
     if (Opts.ObjCWeakRuntime)
-      GenerateArg(Args, OPT_fobjc_runtime_has_weak, SA);
+      GenerateArg(Consumer, OPT_fobjc_runtime_has_weak);
 
     if (Opts.ObjCWeak)
-      GenerateArg(Args, OPT_fobjc_weak, SA);
+      GenerateArg(Consumer, OPT_fobjc_weak);
 
     if (Opts.ObjCSubscriptingLegacyRuntime)
-      GenerateArg(Args, OPT_fobjc_subscripting_legacy_runtime, SA);
+      GenerateArg(Consumer, OPT_fobjc_subscripting_legacy_runtime);
   }
 
   if (Opts.GNUCVersion != 0) {
     unsigned Major = Opts.GNUCVersion / 100 / 100;
     unsigned Minor = (Opts.GNUCVersion / 100) % 100;
     unsigned Patch = Opts.GNUCVersion % 100;
-    GenerateArg(Args, OPT_fgnuc_version_EQ,
-                Twine(Major) + "." + Twine(Minor) + "." + Twine(Patch), SA);
+    GenerateArg(Consumer, OPT_fgnuc_version_EQ,
+                Twine(Major) + "." + Twine(Minor) + "." + Twine(Patch));
   }
 
   if (Opts.IgnoreXCOFFVisibility)
-    GenerateArg(Args, OPT_mignore_xcoff_visibility, SA);
+    GenerateArg(Consumer, OPT_mignore_xcoff_visibility);
 
   if (Opts.SignedOverflowBehavior == LangOptions::SOB_Trapping) {
-    GenerateArg(Args, OPT_ftrapv, SA);
-    GenerateArg(Args, OPT_ftrapv_handler, Opts.OverflowHandler, SA);
+    GenerateArg(Consumer, OPT_ftrapv);
+    GenerateArg(Consumer, OPT_ftrapv_handler, Opts.OverflowHandler);
   } else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
-    GenerateArg(Args, OPT_fwrapv, SA);
+    GenerateArg(Consumer, OPT_fwrapv);
   }
 
   if (Opts.MSCompatibilityVersion != 0) {
     unsigned Major = Opts.MSCompatibilityVersion / 10000000;
     unsigned Minor = (Opts.MSCompatibilityVersion / 100000) % 100;
     unsigned Subminor = Opts.MSCompatibilityVersion % 100000;
-    GenerateArg(Args, OPT_fms_compatibility_version,
-                Twine(Major) + "." + Twine(Minor) + "." + Twine(Subminor), SA);
+    GenerateArg(Consumer, OPT_fms_compatibility_version,
+                Twine(Major) + "." + Twine(Minor) + "." + Twine(Subminor));
   }
 
   if ((!Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus17) || T.isOSzOS()) {
     if (!Opts.Trigraphs)
-      GenerateArg(Args, OPT_fno_trigraphs, SA);
+      GenerateArg(Consumer, OPT_fno_trigraphs);
   } else {
     if (Opts.Trigraphs)
-      GenerateArg(Args, OPT_ftrigraphs, SA);
+      GenerateArg(Consumer, OPT_ftrigraphs);
   }
 
   if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
-    GenerateArg(Args, OPT_fblocks, SA);
+    GenerateArg(Consumer, OPT_fblocks);
 
   if (Opts.ConvergentFunctions &&
       !(Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || Opts.SYCLIsDevice))
-    GenerateArg(Args, OPT_fconvergent_functions, SA);
+    GenerateArg(Consumer, OPT_fconvergent_functions);
 
   if (Opts.NoBuiltin && !Opts.Freestanding)
-    GenerateArg(Args, OPT_fno_builtin, SA);
+    GenerateArg(Consumer, OPT_fno_builtin);
 
   if (!Opts.NoBuiltin)
     for (const auto &Func : Opts.NoBuiltinFuncs)
-      GenerateArg(Args, OPT_fno_builtin_, Func, SA);
+      GenerateArg(Consumer, OPT_fno_builtin_, Func);
 
   if (Opts.LongDoubleSize == 128)
-    GenerateArg(Args, OPT_mlong_double_128, SA);
+    GenerateArg(Consumer, OPT_mlong_double_128);
   else if (Opts.LongDoubleSize == 64)
-    GenerateArg(Args, OPT_mlong_double_64, SA);
+    GenerateArg(Consumer, OPT_mlong_double_64);
   else if (Opts.LongDoubleSize == 80)
-    GenerateArg(Args, OPT_mlong_double_80, SA);
+    GenerateArg(Consumer, OPT_mlong_double_80);
 
   // Not generating '-mrtd', it's just an alias for '-fdefault-calling-conv='.
 
   // OpenMP was requested via '-fopenmp', not implied by '-fopenmp-simd' or
   // '-fopenmp-targets='.
   if (Opts.OpenMP && !Opts.OpenMPSimd) {
-    GenerateArg(Args, OPT_fopenmp, SA);
+    GenerateArg(Consumer, OPT_fopenmp);
 
     if (Opts.OpenMP != 51)
-      GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
+      GenerateArg(Consumer, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP));
 
     if (!Opts.OpenMPUseTLS)
-      GenerateArg(Args, OPT_fnoopenmp_use_tls, SA);
+      GenerateArg(Consumer, OPT_fnoopenmp_use_tls);
 
     if (Opts.OpenMPIsTargetDevice)
-      GenerateArg(Args, OPT_fopenmp_is_target_device, SA);
+      GenerateArg(Consumer, OPT_fopenmp_is_target_device);
 
     if (Opts.OpenMPIRBuilder)
-      GenerateArg(Args, OPT_fopenmp_enable_irbuilder, SA);
+      GenerateArg(Consumer, OPT_fopenmp_enable_irbuilder);
   }
 
   if (Opts.OpenMPSimd) {
-    GenerateArg(Args, OPT_fopenmp_simd, SA);
+    GenerateArg(Consumer, OPT_fopenmp_simd);
 
     if (Opts.OpenMP != 51)
-      GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
+      GenerateArg(Consumer, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP));
   }
 
   if (Opts.OpenMPThreadSubscription)
-    GenerateArg(Args, OPT_fopenmp_assume_threads_oversubscription, SA);
+    GenerateArg(Consumer, OPT_fopenmp_assume_threads_oversubscription);
 
   if (Opts.OpenMPTeamSubscription)
-    GenerateArg(Args, OPT_fopenmp_assume_teams_oversubscription, SA);
+    GenerateArg(Consumer, OPT_fopenmp_assume_teams_oversubscription);
 
   if (Opts.OpenMPTargetDebug != 0)
-    GenerateArg(Args, OPT_fopenmp_target_debug_EQ,
-                Twine(Opts.OpenMPTargetDebug), SA);
+    GenerateArg(Consumer, OPT_fopenmp_target_debug_EQ,
+                Twine(Opts.OpenMPTargetDebug));
 
   if (Opts.OpenMPCUDANumSMs != 0)
-    GenerateArg(Args, OPT_fopenmp_cuda_number_of_sm_EQ,
-                Twine(Opts.OpenMPCUDANumSMs), SA);
+    GenerateArg(Consumer, OPT_fopenmp_cuda_number_of_sm_EQ,
+                Twine(Opts.OpenMPCUDANumSMs));
 
   if (Opts.OpenMPCUDABlocksPerSM != 0)
-    GenerateArg(Args, OPT_fopenmp_cuda_blocks_per_sm_EQ,
-                Twine(Opts.OpenMPCUDABlocksPerSM), SA);
+    GenerateArg(Consumer, OPT_fopenmp_cuda_blocks_per_sm_EQ,
+                Twine(Opts.OpenMPCUDABlocksPerSM));
 
   if (Opts.OpenMPCUDAReductionBufNum != 1024)
-    GenerateArg(Args, OPT_fopenmp_cuda_teams_reduction_recs_num_EQ,
-                Twine(Opts.OpenMPCUDAReductionBufNum), SA);
+    GenerateArg(Consumer, OPT_fopenmp_cuda_teams_reduction_recs_num_EQ,
+                Twine(Opts.OpenMPCUDAReductionBufNum));
 
   if (!Opts.OMPTargetTriples.empty()) {
     std::string Targets;
@@ -3452,83 +3428,83 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
     llvm::interleave(
         Opts.OMPTargetTriples, OS,
         [&OS](const llvm::Triple &T) { OS << T.str(); }, ",");
-    GenerateArg(Args, OPT_fopenmp_targets_EQ, OS.str(), SA);
+    GenerateArg(Consumer, OPT_fopenmp_targets_EQ, OS.str());
   }
 
   if (!Opts.OMPHostIRFile.empty())
-    GenerateArg(Args, OPT_fopenmp_host_ir_file_path, Opts.OMPHostIRFile, SA);
+    GenerateArg(Consumer, OPT_fopenmp_host_ir_file_path, Opts.OMPHostIRFile);
 
   if (Opts.OpenMPCUDAMode)
-    GenerateArg(Args, OPT_fopenmp_cuda_mode, SA);
+    GenerateArg(Consumer, OPT_fopenmp_cuda_mode);
 
   // The arguments used to set Optimize, OptimizeSize and NoInlineDefine are
   // generated from CodeGenOptions.
 
   if (Opts.DefaultFPContractMode == LangOptions::FPM_Fast)
-    GenerateArg(Args, OPT_ffp_contract, "fast", SA);
+    GenerateArg(Consumer, OPT_ffp_contract, "fast");
   else if (Opts.DefaultFPContractMode == LangOptions::FPM_On)
-    GenerateArg(Args, OPT_ffp_contract, "on", SA);
+    GenerateArg(Consumer, OPT_ffp_contract, "on");
   else if (Opts.DefaultFPContractMode == LangOptions::FPM_Off)
-    GenerateArg(Args, OPT_ffp_contract, "off", SA);
+    GenerateArg(Consumer, OPT_ffp_contract, "off");
   else if (Opts.DefaultFPContractMode == LangOptions::FPM_FastHonorPragmas)
-    GenerateArg(Args, OPT_ffp_contract, "fast-honor-pragmas", SA);
+    GenerateArg(Consumer, OPT_ffp_contract, "fast-honor-pragmas");
 
   for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
-    GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
+    GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
 
   // Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
   for (const std::string &F : Opts.NoSanitizeFiles)
-    GenerateArg(Args, OPT_fsanitize_ignorelist_EQ, F, SA);
+    GenerateArg(Consumer, OPT_fsanitize_ignorelist_EQ, F);
 
   if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver3_8)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "3.8", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "3.8");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver4)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "4.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "4.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver6)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "6.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "6.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver7)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "7.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "7.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver9)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "9.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "9.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver11)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "11.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "11.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver12)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "12.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "12.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver14)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "14.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "14.0");
   else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver15)
-    GenerateArg(Args, OPT_fclang_abi_compat_EQ, "15.0", SA);
+    GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "15.0");
 
   if (Opts.getSignReturnAddressScope() ==
       LangOptions::SignReturnAddressScopeKind::All)
-    GenerateArg(Args, OPT_msign_return_address_EQ, "all", SA);
+    GenerateArg(Consumer, OPT_msign_return_address_EQ, "all");
   else if (Opts.getSignReturnAddressScope() ==
            LangOptions::SignReturnAddressScopeKind::NonLeaf)
-    GenerateArg(Args, OPT_msign_return_address_EQ, "non-leaf", SA);
+    GenerateArg(Consumer, OPT_msign_return_address_EQ, "non-leaf");
 
   if (Opts.getSignReturnAddressKey() ==
       LangOptions::SignReturnAddressKeyKind::BKey)
-    GenerateArg(Args, OPT_msign_return_address_key_EQ, "b_key", SA);
+    GenerateArg(Consumer, OPT_msign_return_address_key_EQ, "b_key");
 
   if (Opts.CXXABI)
-    GenerateArg(Args, OPT_fcxx_abi_EQ, TargetCXXABI::getSpelling(*Opts.CXXABI),
-                SA);
+    GenerateArg(Consumer, OPT_fcxx_abi_EQ,
+                TargetCXXABI::getSpelling(*Opts.CXXABI));
 
   if (Opts.RelativeCXXABIVTables)
-    GenerateArg(Args, OPT_fexperimental_relative_cxx_abi_vtables, SA);
+    GenerateArg(Consumer, OPT_fexperimental_relative_cxx_abi_vtables);
   else
-    GenerateArg(Args, OPT_fno_experimental_relative_cxx_abi_vtables, SA);
+    GenerateArg(Consumer, OPT_fno_experimental_relative_cxx_abi_vtables);
 
   if (Opts.UseTargetPathSeparator)
-    GenerateArg(Args, OPT_ffile_reproducible, SA);
+    GenerateArg(Consumer, OPT_ffile_reproducible);
   else
-    GenerateArg(Args, OPT_fno_file_reproducible, SA);
+    GenerateArg(Consumer, OPT_fno_file_reproducible);
 
   for (const auto &MP : Opts.MacroPrefixMap)
-    GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA);
+    GenerateArg(Consumer, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second);
 
   if (!Opts.RandstructSeed.empty())
-    GenerateArg(Args, OPT_frandomize_layout_seed_EQ, Opts.RandstructSeed, SA);
+    GenerateArg(Consumer, OPT_frandomize_layout_seed_EQ, Opts.RandstructSeed);
 }
 
 bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
@@ -4129,29 +4105,27 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
 }
 
 static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
-                                     SmallVectorImpl<const char *> &Args,
-                                     CompilerInvocation::StringAllocator SA,
+                                     ArgumentConsumer Consumer,
                                      const LangOptions &LangOpts,
                                      const FrontendOptions &FrontendOpts,
                                      const CodeGenOptions &CodeGenOpts) {
   PreprocessorOptions *PreprocessorOpts = &Opts;
 
 #define PREPROCESSOR_OPTION_WITH_MARSHALLING(...)                              \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef PREPROCESSOR_OPTION_WITH_MARSHALLING
 
   if (Opts.PCHWithHdrStop && !Opts.PCHWithHdrStopCreate)
-    GenerateArg(Args, OPT_pch_through_hdrstop_use, SA);
+    GenerateArg(Consumer, OPT_pch_through_hdrstop_use);
 
   for (const auto &D : Opts.DeserializedPCHDeclsToErrorOn)
-    GenerateArg(Args, OPT_error_on_deserialized_pch_decl, D, SA);
+    GenerateArg(Consumer, OPT_error_on_deserialized_pch_decl, D);
 
   if (Opts.PrecompiledPreambleBytes != std::make_pair(0u, false))
-    GenerateArg(Args, OPT_preamble_bytes_EQ,
+    GenerateArg(Consumer, OPT_preamble_bytes_EQ,
                 Twine(Opts.PrecompiledPreambleBytes.first) + "," +
-                    (Opts.PrecompiledPreambleBytes.second ? "1" : "0"),
-                SA);
+                    (Opts.PrecompiledPreambleBytes.second ? "1" : "0"));
 
   for (const auto &M : Opts.Macros) {
     // Don't generate __CET__ macro definitions. They are implied by the
@@ -4166,7 +4140,7 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
         CodeGenOpts.CFProtectionBranch)
       continue;
 
-    GenerateArg(Args, M.second ? OPT_U : OPT_D, M.first, SA);
+    GenerateArg(Consumer, M.second ? OPT_U : OPT_D, M.first);
   }
 
   for (const auto &I : Opts.Includes) {
@@ -4181,17 +4155,17 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
     if (LangOpts.HLSL && I == "hlsl.h")
       continue;
 
-    GenerateArg(Args, OPT_include, I, SA);
+    GenerateArg(Consumer, OPT_include, I);
   }
 
   for (const auto &CI : Opts.ChainedIncludes)
-    GenerateArg(Args, OPT_chain_include, CI, SA);
+    GenerateArg(Consumer, OPT_chain_include, CI);
 
   for (const auto &RF : Opts.RemappedFiles)
-    GenerateArg(Args, OPT_remap_file, RF.first + ";" + RF.second, SA);
+    GenerateArg(Consumer, OPT_remap_file, RF.first + ";" + RF.second);
 
   if (Opts.SourceDateEpoch)
-    GenerateArg(Args, OPT_source_date_epoch, Twine(*Opts.SourceDateEpoch), SA);
+    GenerateArg(Consumer, OPT_source_date_epoch, Twine(*Opts.SourceDateEpoch));
 
   // Don't handle LexEditorPlaceholders. It is implied by the action that is
   // generated elsewhere.
@@ -4294,23 +4268,24 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
-static void GeneratePreprocessorOutputArgs(
-    const PreprocessorOutputOptions &Opts, SmallVectorImpl<const char *> &Args,
-    CompilerInvocation::StringAllocator SA, frontend::ActionKind Action) {
+static void
+GeneratePreprocessorOutputArgs(const PreprocessorOutputOptions &Opts,
+                               ArgumentConsumer Consumer,
+                               frontend::ActionKind Action) {
   const PreprocessorOutputOptions &PreprocessorOutputOpts = Opts;
 
 #define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING(...)                       \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING
 
   bool Generate_dM = isStrictlyPreprocessorAction(Action) && !Opts.ShowCPP;
   if (Generate_dM)
-    GenerateArg(Args, OPT_dM, SA);
+    GenerateArg(Consumer, OPT_dM);
   if (!Generate_dM && Opts.ShowMacros)
-    GenerateArg(Args, OPT_dD, SA);
+    GenerateArg(Consumer, OPT_dD);
   if (Opts.DirectivesOnly)
-    GenerateArg(Args, OPT_fdirectives_only, SA);
+    GenerateArg(Consumer, OPT_fdirectives_only);
 }
 
 static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -4333,20 +4308,19 @@ static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
 }
 
 static void GenerateTargetArgs(const TargetOptions &Opts,
-                               SmallVectorImpl<const char *> &Args,
-                               CompilerInvocation::StringAllocator SA) {
+                               ArgumentConsumer Consumer) {
   const TargetOptions *TargetOpts = &Opts;
 #define TARGET_OPTION_WITH_MARSHALLING(...)                                    \
-  GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__)
+  GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
 #include "clang/Driver/Options.inc"
 #undef TARGET_OPTION_WITH_MARSHALLING
 
   if (!Opts.SDKVersion.empty())
-    GenerateArg(Args, OPT_target_sdk_version_EQ, Opts.SDKVersion.getAsString(),
-                SA);
+    GenerateArg(Consumer, OPT_target_sdk_version_EQ,
+                Opts.SDKVersion.getAsString());
   if (!Opts.DarwinTargetVariantSDKVersion.empty())
-    GenerateArg(Args, OPT_darwin_target_variant_sdk_version_EQ,
-                Opts.DarwinTargetVariantSDKVersion.getAsString(), SA);
+    GenerateArg(Consumer, OPT_darwin_target_variant_sdk_version_EQ,
+                Opts.DarwinTargetVariantSDKVersion.getAsString());
 }
 
 static bool ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
@@ -4616,24 +4590,24 @@ std::string CompilerInvocation::getModuleHash() const {
 }
 
 void CompilerInvocation::generateCC1CommandLine(
-    SmallVectorImpl<const char *> &Args, StringAllocator SA) const {
+    ArgumentConsumer Consumer) const {
   llvm::Triple T(TargetOpts->Triple);
 
-  GenerateFileSystemArgs(FileSystemOpts, Args, SA);
-  GenerateMigratorArgs(MigratorOpts, Args, SA);
-  GenerateAnalyzerArgs(*AnalyzerOpts, Args, SA);
-  GenerateDiagnosticArgs(*DiagnosticOpts, Args, SA, false);
-  GenerateFrontendArgs(FrontendOpts, Args, SA, LangOpts->IsHeaderFile);
-  GenerateTargetArgs(*TargetOpts, Args, SA);
-  GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
-  GenerateLangArgs(*LangOpts, Args, SA, T, FrontendOpts.DashX);
-  GenerateCodeGenArgs(CodeGenOpts, Args, SA, T, FrontendOpts.OutputFile,
+  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, Args, SA, *LangOpts, FrontendOpts,
+  GeneratePreprocessorArgs(*PreprocessorOpts, Consumer, *LangOpts, FrontendOpts,
                            CodeGenOpts);
-  GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Args, SA,
+  GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Consumer,
                                  FrontendOpts.ProgramAction);
-  GenerateDependencyOutputArgs(DependencyOutputOpts, Args, SA);
+  GenerateDependencyOutputArgs(DependencyOutputOpts, Consumer);
 }
 
 std::vector<std::string> CompilerInvocation::getCC1CommandLine() const {


        


More information about the cfe-commits mailing list