[Mlir-commits] [clang] [clang-tools-extra] [lldb] [llvm] [mlir] [Support] Validate number of arguments passed to formatv() (PR #105745)

Rahul Joshi llvmlistbot at llvm.org
Thu Aug 22 18:58:40 PDT 2024


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/105745

>From afbbe584430034c8ef21905218849b11e23ffb81 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 22 Aug 2024 08:47:02 -0700
Subject: [PATCH 1/2] [Support] Detect invalid formatv() calls

- Detect formatv() calls where the number of replacement parameters
  expected after parsing the format string does not match the number
  provides in the formatv() call.
- assert() in debug builds, and fail the formatv() call in release
  builds by just emitting an error message in the stream.
---
 llvm/include/llvm/Support/FormatVariadic.h    | 21 ++++-
 llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp    |  3 +-
 llvm/lib/Support/FormatVariadic.cpp           | 10 ++-
 llvm/unittests/Support/FormatVariadicTest.cpp | 79 +++++++++++++------
 4 files changed, 81 insertions(+), 32 deletions(-)

diff --git a/llvm/include/llvm/Support/FormatVariadic.h b/llvm/include/llvm/Support/FormatVariadic.h
index 595f2cf559a428..c0c931b3541040 100644
--- a/llvm/include/llvm/Support/FormatVariadic.h
+++ b/llvm/include/llvm/Support/FormatVariadic.h
@@ -83,7 +83,20 @@ class formatv_object_base {
 
 public:
   void format(raw_ostream &S) const {
-    for (auto &R : parseFormatString(Fmt)) {
+    const auto [Replacements, NumExpectedParams] = parseFormatString(Fmt);
+    // Fail formatv() call if the number of replacement parameters provided
+    // does not match the expected number after parsing the format string.
+    // Assert in debug builds.
+    assert(NumExpectedParams == Adapters.size() &&
+           "Mismatch between replacement parameters expected and provided");
+    if (NumExpectedParams != Adapters.size()) {
+      S << "formatv() error: " << NumExpectedParams
+        << " replacement parameters expected, but " << Adapters.size()
+        << " provided";
+      return;
+    }
+
+    for (const auto &R : Replacements) {
       if (R.Type == ReplacementType::Empty)
         continue;
       if (R.Type == ReplacementType::Literal) {
@@ -101,7 +114,11 @@ class formatv_object_base {
       Align.format(S, R.Options);
     }
   }
-  static SmallVector<ReplacementItem, 2> parseFormatString(StringRef Fmt);
+
+  // Parse format string and return the array of replacement items as well as
+  // the number of values we expect to be supplied to the formatv() call.
+  static std::pair<SmallVector<ReplacementItem, 2>, size_t>
+  parseFormatString(StringRef Fmt);
 
   static std::optional<ReplacementItem> parseReplacementItem(StringRef Spec);
 
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 77e8ece9439cf9..eb2751ab30ac50 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -1518,8 +1518,7 @@ DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
         error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units "
                            "and abbreviation {1:x} has no DW_IDX_compile_unit "
                            "or DW_IDX_type_unit attribute.\n",
-                           NI.getUnitOffset(), Abbrev.Code,
-                           dwarf::DW_IDX_compile_unit);
+                           NI.getUnitOffset(), Abbrev.Code);
       });
       ++NumErrors;
     }
diff --git a/llvm/lib/Support/FormatVariadic.cpp b/llvm/lib/Support/FormatVariadic.cpp
index e25d036cdf1e8c..c355aa519b8c53 100644
--- a/llvm/lib/Support/FormatVariadic.cpp
+++ b/llvm/lib/Support/FormatVariadic.cpp
@@ -35,8 +35,7 @@ bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
 
   if (Spec.size() > 1) {
     // A maximum of 2 characters at the beginning can be used for something
-    // other
-    // than the width.
+    // other than the width.
     // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...]
     // contains the width.
     // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width.
@@ -143,16 +142,19 @@ formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) {
   return std::make_pair(ReplacementItem{Fmt}, StringRef());
 }
 
-SmallVector<ReplacementItem, 2>
+std::pair<SmallVector<ReplacementItem, 2>, size_t>
 formatv_object_base::parseFormatString(StringRef Fmt) {
   SmallVector<ReplacementItem, 2> Replacements;
+  size_t NumExpectedParams = 0;
   ReplacementItem I;
   while (!Fmt.empty()) {
     std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt);
     if (I.Type != ReplacementType::Empty)
       Replacements.push_back(I);
+    if (I.Type == ReplacementType::Format)
+      NumExpectedParams = std::max(NumExpectedParams, I.Index + 1);
   }
-  return Replacements;
+  return {Replacements, NumExpectedParams};
 }
 
 void support::detail::format_adapter::anchor() {}
diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index a78b25c53d7e43..b94c432f73b41a 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -36,13 +36,15 @@ static_assert(uses_missing_provider<NoFormat>::value, "");
 }
 
 TEST(FormatVariadicTest, EmptyFormatString) {
-  auto Replacements = formatv_object_base::parseFormatString("");
+  auto [Replacements, NumVals] = formatv_object_base::parseFormatString("");
   EXPECT_EQ(0U, Replacements.size());
+  EXPECT_EQ(0U, NumVals);
 }
 
 TEST(FormatVariadicTest, NoReplacements) {
   const StringRef kFormatString = "This is a test";
-  auto Replacements = formatv_object_base::parseFormatString(kFormatString);
+  auto [Replacements, NumVals] =
+      formatv_object_base::parseFormatString(kFormatString);
   ASSERT_EQ(1U, Replacements.size());
   EXPECT_EQ(kFormatString, Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
@@ -50,25 +52,27 @@ TEST(FormatVariadicTest, NoReplacements) {
 
 TEST(FormatVariadicTest, EscapedBrace) {
   // {{ should be replaced with {
-  auto Replacements = formatv_object_base::parseFormatString("{{");
+  auto [Replacements, NumVals] = formatv_object_base::parseFormatString("{{");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("{", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
 
   // An even number N of braces should be replaced with N/2 braces.
-  Replacements = formatv_object_base::parseFormatString("{{{{{{");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{{{{{{");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("{{{", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
 
   // } does not require doubling up.
-  Replacements = formatv_object_base::parseFormatString("}");
+  std::tie(Replacements, NumVals) = formatv_object_base::parseFormatString("}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("}", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
 
   // } does not require doubling up.
-  Replacements = formatv_object_base::parseFormatString("}}}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("}}}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("}}}", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
@@ -76,14 +80,15 @@ TEST(FormatVariadicTest, EscapedBrace) {
 
 TEST(FormatVariadicTest, ValidReplacementSequence) {
   // 1. Simple replacement - parameter index only
-  auto Replacements = formatv_object_base::parseFormatString("{0}");
+  auto [Replacements, NumVals] = formatv_object_base::parseFormatString("{0}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
   EXPECT_EQ(0u, Replacements[0].Align);
   EXPECT_EQ("", Replacements[0].Options);
 
-  Replacements = formatv_object_base::parseFormatString("{1}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{1}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(1u, Replacements[0].Index);
@@ -92,7 +97,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // 2. Parameter index with right alignment
-  Replacements = formatv_object_base::parseFormatString("{0,3}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,3}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -101,7 +107,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // 3. And left alignment
-  Replacements = formatv_object_base::parseFormatString("{0,-3}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,-3}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -110,7 +117,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // 4. And center alignment
-  Replacements = formatv_object_base::parseFormatString("{0,=3}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,=3}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -119,7 +127,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // 4. Parameter index with option string
-  Replacements = formatv_object_base::parseFormatString("{0:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -128,7 +137,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("foo", Replacements[0].Options);
 
   // 5. Parameter index with alignment before option string
-  Replacements = formatv_object_base::parseFormatString("{0,-3:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,-3:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -137,7 +147,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("foo", Replacements[0].Options);
 
   // 7. Parameter indices, options, and alignment can all have whitespace.
-  Replacements = formatv_object_base::parseFormatString("{ 0, -3 : foo }");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{ 0, -3 : foo }");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -147,7 +158,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
 
   // 8. Everything after the first option specifier is part of the style, even
   // if it contains another option specifier.
-  Replacements = formatv_object_base::parseFormatString("{0:0:1}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0:0:1}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0:0:1", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -157,7 +169,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("0:1", Replacements[0].Options);
 
   // 9. Custom padding character
-  Replacements = formatv_object_base::parseFormatString("{0,p+4:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,p+4:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0,p+4:foo", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -168,7 +181,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ("foo", Replacements[0].Options);
 
   // Format string special characters are allowed as padding character
-  Replacements = formatv_object_base::parseFormatString("{0,-+4:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,-+4:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0,-+4:foo", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -178,7 +192,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ('-', Replacements[0].Pad);
   EXPECT_EQ("foo", Replacements[0].Options);
 
-  Replacements = formatv_object_base::parseFormatString("{0,+-4:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,+-4:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0,+-4:foo", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -188,7 +203,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ('+', Replacements[0].Pad);
   EXPECT_EQ("foo", Replacements[0].Options);
 
-  Replacements = formatv_object_base::parseFormatString("{0,==4:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,==4:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0,==4:foo", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -198,7 +214,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
   EXPECT_EQ('=', Replacements[0].Pad);
   EXPECT_EQ("foo", Replacements[0].Options);
 
-  Replacements = formatv_object_base::parseFormatString("{0,:=4:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,:=4:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ("0,:=4:foo", Replacements[0].Spec);
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
@@ -211,7 +228,8 @@ TEST(FormatVariadicTest, ValidReplacementSequence) {
 
 TEST(FormatVariadicTest, DefaultReplacementValues) {
   // 2. If options string is missing, it defaults to empty.
-  auto Replacements = formatv_object_base::parseFormatString("{0,3}");
+  auto [Replacements, NumVals] =
+      formatv_object_base::parseFormatString("{0,3}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -219,7 +237,8 @@ TEST(FormatVariadicTest, DefaultReplacementValues) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // Including if the colon is present but contains no text.
-  Replacements = formatv_object_base::parseFormatString("{0,3:}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0,3:}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(0u, Replacements[0].Index);
@@ -227,7 +246,8 @@ TEST(FormatVariadicTest, DefaultReplacementValues) {
   EXPECT_EQ("", Replacements[0].Options);
 
   // 3. If alignment is missing, it defaults to 0, right, space
-  Replacements = formatv_object_base::parseFormatString("{0:foo}");
+  std::tie(Replacements, NumVals) =
+      formatv_object_base::parseFormatString("{0:foo}");
   ASSERT_EQ(1u, Replacements.size());
   EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
   EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
@@ -238,7 +258,7 @@ TEST(FormatVariadicTest, DefaultReplacementValues) {
 }
 
 TEST(FormatVariadicTest, MultipleReplacements) {
-  auto Replacements =
+  auto [Replacements, NumVals] =
       formatv_object_base::parseFormatString("{0} {1:foo}-{2,-3:bar}");
   ASSERT_EQ(5u, Replacements.size());
   // {0}
@@ -698,6 +718,17 @@ TEST(FormatVariadicTest, FormatError) {
   EXPECT_FALSE(E1.isA<StringError>()); // consumed
 }
 
+TEST(FormatVariadicTest, FormatErrorNumArgMismatch) {
+#ifndef NDEBUG
+  EXPECT_EQ(
+      formatv("{0}", 0, 1).str(),
+      "formatv() error: 1 replacement parameters expected, but 2 provided");
+  EXPECT_EQ(
+      formatv("{0} {4}", 0, 1).str(),
+      "formatv() error: 5 replacement parameters expected, but 2 provided");
+#endif
+}
+
 TEST(FormatVariadicTest, FormatFilterRange) {
   std::vector<int> Vec{0, 1, 2};
   auto Range = map_range(Vec, [](int V) { return V + 1; });

>From 3b26f9aac46720524f4dddebe08cc828f3fc2f47 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 22 Aug 2024 14:48:53 -0700
Subject: [PATCH 2/2] [Support] Validate number of arguments passed to
 formatv()

- Change formatv() to validate that the number of arguments passed matches
  number of replacement parameters in the format string.
- When the format string is a literal, this failure can be easily fixed,
  but when its dynamically generated, it may not be as straightforward.
- So changed existing formatv() to only accept literal strings as a
  format string and enable argument count validation for that case only.
- Add a `formatvv` variant that allows non-literal format strings and
  disables argument count verification.
---
 clang-tools-extra/clangd/JSONTransport.cpp    |   2 +-
 .../clangd/index/dex/dexp/Dexp.cpp            |   2 +-
 .../clangd/refactor/tweaks/SpecialMembers.cpp |   4 +-
 clang-tools-extra/clangd/support/Logger.h     |   6 +-
 .../GlobalCompilationDatabaseTests.cpp        |   8 +-
 clang-tools-extra/pseudo/lib/Forest.cpp       |   5 +-
 .../Checkers/CheckPlacementNew.cpp            |   2 +-
 .../Checkers/StdLibraryFunctionsChecker.cpp   |   2 +-
 lldb/include/lldb/Core/Debugger.h             |   4 +-
 lldb/include/lldb/Core/Module.h               |  10 +-
 .../lldb/Interpreter/CommandReturnObject.h    |   6 +-
 lldb/include/lldb/Utility/Log.h               |   6 +-
 lldb/include/lldb/Utility/Status.h            |   4 +-
 lldb/include/lldb/Utility/Stream.h            |   2 +-
 lldb/source/Core/FormatEntity.cpp             |   4 +-
 .../source/Plugins/ABI/AArch64/ABIAArch64.cpp |   2 +-
 .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp  |   2 +-
 lldb/source/Utility/Log.cpp                   |   2 +-
 lldb/tools/lldb-test/FormatUtil.h             |   2 +-
 lldb/tools/lldb-test/lldb-test.cpp            |   2 +-
 .../tools/lldb-server/tests/MessageObjects.h  |   2 +-
 .../llvm/DebugInfo/PDB/Native/LinePrinter.h   |   4 +-
 llvm/include/llvm/Support/FormatVariadic.h    |  39 ++++--
 llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp  |   2 +-
 .../DWARFLinker/Parallel/DWARFLinkerImpl.cpp  |   2 +-
 llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp     |   2 +-
 .../Orc/CompileOnDemandLayer.cpp              |   8 +-
 llvm/tools/llvm-exegesis/lib/Analysis.cpp     |   2 +-
 .../Analysis/ProfileSummaryInfoTest.cpp       |   4 +-
 llvm/unittests/Support/FormatVariadicTest.cpp |  10 +-
 mlir/include/mlir/TableGen/CodeGenHelpers.h   |   9 +-
 .../mlir/Tools/lsp-server-support/Logging.h   |   6 +-
 .../Linalg/TransformOps/LinalgMatchOps.cpp    |   2 +-
 .../X86Vector/Transforms/AVXTranspose.cpp     |   2 +-
 mlir/lib/TableGen/CodeGenHelpers.cpp          |  16 +--
 mlir/lib/TableGen/Pattern.cpp                 |  31 ++---
 mlir/lib/Tools/PDLL/CodeGen/CPPGen.cpp        |   2 +-
 .../Tools/lsp-server-support/Transport.cpp    |   2 +-
 .../Transforms/Utils/DialectConversion.cpp    |   5 +-
 mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp   |  22 ++--
 .../tools/mlir-tblgen/AttrOrTypeFormatGen.cpp |  22 ++--
 mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp |  12 +-
 mlir/tools/mlir-tblgen/DialectGen.cpp         |  26 ++--
 mlir/tools/mlir-tblgen/EnumsGen.cpp           |  16 +--
 .../tools/mlir-tblgen/LLVMIRConversionGen.cpp |   2 +-
 mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp   | 118 +++++++++---------
 mlir/tools/mlir-tblgen/OpFormatGen.cpp        | 105 ++++++++--------
 mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp | 101 +++++++--------
 mlir/tools/mlir-tblgen/PassCAPIGen.cpp        |  10 +-
 mlir/tools/mlir-tblgen/PassGen.cpp            |  24 ++--
 mlir/tools/mlir-tblgen/RewriterGen.cpp        |   4 +-
 51 files changed, 357 insertions(+), 332 deletions(-)

diff --git a/clang-tools-extra/clangd/JSONTransport.cpp b/clang-tools-extra/clangd/JSONTransport.cpp
index 3c0e198433f360..eebc9cab8acc88 100644
--- a/clang-tools-extra/clangd/JSONTransport.cpp
+++ b/clang-tools-extra/clangd/JSONTransport.cpp
@@ -135,7 +135,7 @@ class JSONTransport : public Transport {
   void sendMessage(llvm::json::Value Message) {
     OutputBuffer.clear();
     llvm::raw_svector_ostream OS(OutputBuffer);
-    OS << llvm::formatv(Pretty ? "{0:2}" : "{0}", Message);
+    OS << llvm::formatvv(Pretty ? "{0:2}" : "{0}", Message);
     Out << "Content-Length: " << OutputBuffer.size() << "\r\n\r\n"
         << OutputBuffer;
     Out.flush();
diff --git a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
index cea59ae409914c..d3e6ab58bbed2a 100644
--- a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
+++ b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
@@ -161,7 +161,7 @@ class FuzzyFind : public Command {
     }
     Request.AnyScope = Request.Scopes.empty();
     // FIXME(kbobyrev): Print symbol final scores to see the distribution.
-    static const auto *OutputFormat = "{0,-4} | {1,-40} | {2,-25}\n";
+    static const char OutputFormat[] = "{0,-4} | {1,-40} | {2,-25}\n";
     llvm::outs() << llvm::formatv(OutputFormat, "Rank", "Symbol ID",
                                   "Symbol Name");
     size_t Rank = 0;
diff --git a/clang-tools-extra/clangd/refactor/tweaks/SpecialMembers.cpp b/clang-tools-extra/clangd/refactor/tweaks/SpecialMembers.cpp
index 0b86b484227071..54178535fc0177 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/SpecialMembers.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/SpecialMembers.cpp
@@ -50,8 +50,8 @@ std::string buildSpecialMemberDeclarations(const CXXRecordDecl &Class) {
     bool Delete = !D || D->isDeleted();
     OS << llvm::formatv(
         "{0} = {1};\n",
-        llvm::formatv(MemberPattern, Class.getName(),
-                      llvm::formatv(ParmPattern, Class.getName())),
+        llvm::formatvv(MemberPattern, Class.getName(),
+                       llvm::formatvv(ParmPattern, Class.getName())),
         Delete ? "delete" : "default");
   };
   auto PrintMembers = [&](const Members &M, const char *MemberPattern) {
diff --git a/clang-tools-extra/clangd/support/Logger.h b/clang-tools-extra/clangd/support/Logger.h
index dba33be48f56df..1cc872114b6b1e 100644
--- a/clang-tools-extra/clangd/support/Logger.h
+++ b/clang-tools-extra/clangd/support/Logger.h
@@ -46,7 +46,7 @@ inline decltype(fmt_consume(llvm::Error::success())) wrap(llvm::Error &&V) {
 template <typename... Ts>
 void log(Logger::Level L, const char *Fmt, Ts &&... Vals) {
   detail::logImpl(L, Fmt,
-                  llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...));
+                  llvm::formatvv(Fmt, detail::wrap(std::forward<Ts>(Vals))...));
 }
 
 llvm::Error error(std::error_code, std::string &&);
@@ -79,13 +79,13 @@ template <typename... Ts>
 llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals) {
   // We must render the formatv_object eagerly, while references are valid.
   return detail::error(
-      EC, llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
+      EC, llvm::formatvv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
 }
 // Overload with no error_code conversion, the error will be inconvertible.
 template <typename... Ts> llvm::Error error(const char *Fmt, Ts &&... Vals) {
   return detail::error(
       llvm::inconvertibleErrorCode(),
-      llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
+      llvm::formatvv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
 }
 // Overload to avoid formatv complexity for simple strings.
 inline llvm::Error error(std::error_code EC, std::string Msg) {
diff --git a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index a2ffdefe1bbcb2..1299e1fdfb6c6d 100644
--- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -179,7 +179,7 @@ TEST_F(OverlayCDBTest, ExpandedResponseFiles) {
 }
 
 TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) {
-  const char *const CDBOuter =
+  const char CDBOuter[] =
       R"cdb(
       [
         {
@@ -199,7 +199,7 @@ TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) {
         }
       ]
       )cdb";
-  const char *const CDBInner =
+  const char CDBInner[] =
       R"cdb(
       [
         {
@@ -317,7 +317,7 @@ TEST(GlobalCompilationDatabaseTest, BuildDir) {
         .CommandLine;
   };
   EXPECT_THAT(Command("x/foo.cc"), IsEmpty());
-  const char *const CDB =
+  const char CDB[] =
       R"cdb(
       [
         {
@@ -456,7 +456,7 @@ TEST(GlobalCompilationDatabaseTest, InferenceWithResponseFile) {
   OutStream << "-DXYZZY";
   OutStream.close();
 
-  const char *const CDB =
+  const char CDB[] =
       R"cdb(
       [
         {
diff --git a/clang-tools-extra/pseudo/lib/Forest.cpp b/clang-tools-extra/pseudo/lib/Forest.cpp
index e8e60e5ec475a4..99d40161679cbc 100644
--- a/clang-tools-extra/pseudo/lib/Forest.cpp
+++ b/clang-tools-extra/pseudo/lib/Forest.cpp
@@ -63,6 +63,7 @@ std::string ForestNode::dump(const Grammar &G) const {
 std::string ForestNode::dumpRecursive(const Grammar &G,
                                       bool Abbreviated) const {
   using llvm::formatv;
+  using llvm::formatvv;
   Token::Index MaxToken = 0;
   // Count visits of nodes so we can mark those seen multiple times.
   llvm::DenseMap<const ForestNode *, /*VisitCount*/ unsigned> VisitCounts;
@@ -128,9 +129,9 @@ std::string ForestNode::dumpRecursive(const Grammar &G,
         }
 
         if (End == KEnd)
-          Result += formatv(RangeFormat.c_str(), P->startTokenIndex(), "end");
+          Result += formatvv(RangeFormat.c_str(), P->startTokenIndex(), "end");
         else
-          Result += formatv(RangeFormat.c_str(), P->startTokenIndex(), End);
+          Result += formatvv(RangeFormat.c_str(), P->startTokenIndex(), End);
         Result += LineDec.Prefix;
         Result += LineDec.First;
         if (ElidedParent) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
index 99e11a15c08dc2..1b89951397cfb1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
@@ -131,7 +131,7 @@ bool PlacementNewChecker::checkPlaceCapacityIsSufficient(
             "Storage provided to placement new is only {0} bytes, "
             "whereas the allocated array type requires more space for "
             "internal needs",
-            SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()));
+            SizeOfPlaceCI->getValue()));
       else
         Msg = std::string(llvm::formatv(
             "Storage provided to placement new is only {0} bytes, "
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 8f4bd17afc8581..60c035612dcd44 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -1401,7 +1401,7 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
         ErrnoNote =
             llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
     } else {
-      CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
+      CaseNote = llvm::formatvv(Case.getNote().str().c_str(), FunctionName);
     }
     const SVal RV = Call.getReturnValue();
 
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index a72c2596cc2c5e..cbfd688b536f8f 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -435,7 +435,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
       if (!cur_func)
         cur_func = "<UNKNOWN>";
       ReportInterruption(InterruptionReport(
-          cur_func, llvm::formatv(formatv, std::forward<Args>(args)...)));
+          cur_func, llvm::formatvv(formatv, std::forward<Args>(args)...)));
     }
     return ret_val;
   }
@@ -466,7 +466,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
                        Args &&...args)
         : InterruptionReport(
               function_name,
-              llvm::formatv(format, std::forward<Args>(args)...)) {}
+              llvm::formatvv(format, std::forward<Args>(args)...)) {}
 
     std::string m_function_name;
     std::string m_description;
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 5589c1c9a350dc..6efda666c86e3d 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -781,24 +781,24 @@ class Module : public std::enable_shared_from_this<Module>,
   // own and keeps the output a bit more consistent.
   template <typename... Args>
   void LogMessage(Log *log, const char *format, Args &&...args) {
-    LogMessage(log, llvm::formatv(format, std::forward<Args>(args)...));
+    LogMessage(log, llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   template <typename... Args>
   void LogMessageVerboseBacktrace(Log *log, const char *format,
                                   Args &&...args) {
     LogMessageVerboseBacktrace(
-        log, llvm::formatv(format, std::forward<Args>(args)...));
+        log, llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   template <typename... Args>
   void ReportWarning(const char *format, Args &&...args) {
-    ReportWarning(llvm::formatv(format, std::forward<Args>(args)...));
+    ReportWarning(llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   template <typename... Args>
   void ReportError(const char *format, Args &&...args) {
-    ReportError(llvm::formatv(format, std::forward<Args>(args)...));
+    ReportError(llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   // Only report an error once when the module is first detected to be modified
@@ -806,7 +806,7 @@ class Module : public std::enable_shared_from_this<Module>,
   template <typename... Args>
   void ReportErrorIfModifyDetected(const char *format, Args &&...args) {
     ReportErrorIfModifyDetected(
-        llvm::formatv(format, std::forward<Args>(args)...));
+        llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   void ReportWarningOptimization(std::optional<lldb::user_id_t> debugger_id);
diff --git a/lldb/include/lldb/Interpreter/CommandReturnObject.h b/lldb/include/lldb/Interpreter/CommandReturnObject.h
index 8c4dcb54d708f0..d580dffb7dbdb6 100644
--- a/lldb/include/lldb/Interpreter/CommandReturnObject.h
+++ b/lldb/include/lldb/Interpreter/CommandReturnObject.h
@@ -118,17 +118,17 @@ class CommandReturnObject {
 
   template <typename... Args>
   void AppendMessageWithFormatv(const char *format, Args &&... args) {
-    AppendMessage(llvm::formatv(format, std::forward<Args>(args)...).str());
+    AppendMessage(llvm::formatvv(format, std::forward<Args>(args)...).str());
   }
 
   template <typename... Args>
   void AppendWarningWithFormatv(const char *format, Args &&... args) {
-    AppendWarning(llvm::formatv(format, std::forward<Args>(args)...).str());
+    AppendWarning(llvm::formatvv(format, std::forward<Args>(args)...).str());
   }
 
   template <typename... Args>
   void AppendErrorWithFormatv(const char *format, Args &&... args) {
-    AppendError(llvm::formatv(format, std::forward<Args>(args)...).str());
+    AppendError(llvm::formatvv(format, std::forward<Args>(args)...).str());
   }
 
   void SetError(const Status &error, const char *fallback_error_cstr = nullptr);
diff --git a/lldb/include/lldb/Utility/Log.h b/lldb/include/lldb/Utility/Log.h
index 27707c17f9b824..3357ce579433be 100644
--- a/lldb/include/lldb/Utility/Log.h
+++ b/lldb/include/lldb/Utility/Log.h
@@ -237,7 +237,7 @@ class Log final {
   template <typename... Args>
   void Format(llvm::StringRef file, llvm::StringRef function,
               const char *format, Args &&... args) {
-    Format(file, function, llvm::formatv(format, std::forward<Args>(args)...));
+    Format(file, function, llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   template <typename... Args>
@@ -245,8 +245,8 @@ class Log final {
                    llvm::StringRef function, const char *format,
                    Args &&... args) {
     Format(file, function,
-           llvm::formatv(format, llvm::toString(std::move(error)),
-                         std::forward<Args>(args)...));
+           llvm::formatvv(format, llvm::toString(std::move(error)),
+                          std::forward<Args>(args)...));
   }
 
   void Formatf(llvm::StringRef file, llvm::StringRef function,
diff --git a/lldb/include/lldb/Utility/Status.h b/lldb/include/lldb/Utility/Status.h
index fa5768141fa45d..2a9ff15cc9f76c 100644
--- a/lldb/include/lldb/Utility/Status.h
+++ b/lldb/include/lldb/Utility/Status.h
@@ -66,7 +66,7 @@ class Status {
 
   template <typename... Args>
   static Status createWithFormat(const char *format, Args &&...args) {
-    return Status(llvm::formatv(format, std::forward<Args>(args)...));
+    return Status(llvm::formatvv(format, std::forward<Args>(args)...));
   }
 
   ~Status();
@@ -167,7 +167,7 @@ class Status {
 
   template <typename... Args>
   void SetErrorStringWithFormatv(const char *format, Args &&... args) {
-    SetErrorString(llvm::formatv(format, std::forward<Args>(args)...).str());
+    SetErrorString(llvm::formatvv(format, std::forward<Args>(args)...).str());
   }
 
   /// Test for success condition.
diff --git a/lldb/include/lldb/Utility/Stream.h b/lldb/include/lldb/Utility/Stream.h
index 37bcdc99241715..9277882bb3cdaf 100644
--- a/lldb/include/lldb/Utility/Stream.h
+++ b/lldb/include/lldb/Utility/Stream.h
@@ -351,7 +351,7 @@ class Stream {
   size_t PrintfVarArg(const char *format, va_list args);
 
   template <typename... Args> void Format(const char *format, Args &&... args) {
-    PutCString(llvm::formatv(format, std::forward<Args>(args)...).str());
+    PutCString(llvm::formatvv(format, std::forward<Args>(args)...).str());
   }
 
   /// Output a quoted C string value to the stream.
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 4e1f37099148b4..33924f17898805 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -674,12 +674,12 @@ static bool DumpValueWithLLVMFormat(Stream &s, llvm::StringRef options,
       bool success = false;
       int64_t integer = valobj.GetValueAsSigned(0, &success);
       if (success)
-        formatted = llvm::formatv(llvm_format.data(), integer);
+        formatted = llvm::formatvv(llvm_format.data(), integer);
     } else {
       bool success = false;
       uint64_t integer = valobj.GetValueAsUnsigned(0, &success);
       if (success)
-        formatted = llvm::formatv(llvm_format.data(), integer);
+        formatted = llvm::formatvv(llvm_format.data(), integer);
     }
   }
 
diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
index 256c1f828feb38..71f819cf97e71e 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
@@ -111,7 +111,7 @@ static void addPartialRegisters(
 
     lldb_private::DynamicRegisterInfo::Register partial_reg{
         lldb_private::ConstString(
-            llvm::formatv(partial_reg_format, it.index()).str()),
+            llvm::formatvv(partial_reg_format, it.index()).str()),
         lldb_private::ConstString(),
         lldb_private::ConstString("supplementary registers"),
         partial_reg_size,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index e2660735ea7dec..16d9f5ad4ce163 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -49,7 +49,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,
     unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
         "[{0:x16}]: {1}, please file a bug and "
         "attach the file at the start of this error message",
-        static_cast<uint64_t>(m_offset), llvm::formatv(fmt, vals...));
+        static_cast<uint64_t>(m_offset), llvm::formatvv(fmt, vals...));
     *offset_ptr = std::numeric_limits<lldb::offset_t>::max();
     return false;
   };
diff --git a/lldb/source/Utility/Log.cpp b/lldb/source/Utility/Log.cpp
index 6713a5bd758204..c55c8cf585b7ff 100644
--- a/lldb/source/Utility/Log.cpp
+++ b/lldb/source/Utility/Log.cpp
@@ -343,7 +343,7 @@ void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
     llvm::SmallString<12> format_str;
     llvm::raw_svector_ostream format_os(format_str);
     format_os << "{0,-" << llvm::alignTo<16>(thread_name.size()) << "} ";
-    OS << llvm::formatv(format_str.c_str(), thread_name);
+    OS << llvm::formatvv(format_str.c_str(), thread_name);
   }
 
   if (options.Test(LLDB_LOG_OPTION_BACKTRACE))
diff --git a/lldb/tools/lldb-test/FormatUtil.h b/lldb/tools/lldb-test/FormatUtil.h
index 2b2266e8dfbd6b..657931de6c05d9 100644
--- a/lldb/tools/lldb-test/FormatUtil.h
+++ b/lldb/tools/lldb-test/FormatUtil.h
@@ -46,7 +46,7 @@ class LinePrinter {
 
   void printLine(const llvm::Twine &T) { line() << T; }
   template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) {
-    printLine(llvm::formatv(Fmt, std::forward<Ts>(Items)...));
+    printLine(llvm::formatvv(Fmt, std::forward<Ts>(Items)...));
   }
 
   void formatBinary(llvm::StringRef Label, llvm::ArrayRef<uint8_t> Data,
diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp
index 535422a6d827be..df3a8f3c373925 100644
--- a/lldb/tools/lldb-test/lldb-test.cpp
+++ b/lldb/tools/lldb-test/lldb-test.cpp
@@ -337,7 +337,7 @@ llvm::SmallVector<CompilerContext, 4> parseCompilerContext() {
 template <typename... Args>
 static Error make_string_error(const char *Format, Args &&... args) {
   return llvm::make_error<llvm::StringError>(
-      llvm::formatv(Format, std::forward<Args>(args)...).str(),
+      llvm::formatvv(Format, std::forward<Args>(args)...).str(),
       llvm::inconvertibleErrorCode());
 }
 
diff --git a/lldb/unittests/tools/lldb-server/tests/MessageObjects.h b/lldb/unittests/tools/lldb-server/tests/MessageObjects.h
index 0e0a3b2a927266..1c493282f2da6f 100644
--- a/lldb/unittests/tools/lldb-server/tests/MessageObjects.h
+++ b/lldb/unittests/tools/lldb-server/tests/MessageObjects.h
@@ -172,7 +172,7 @@ template <typename... Args>
 llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) {
   std::string error =
       "Unable to parse " +
-      llvm::formatv(format.data(), std::forward<Args>(args)...).str();
+      llvm::formatvv(format.data(), std::forward<Args>(args)...).str();
   return llvm::make_error<llvm::StringError>(error,
                                              llvm::inconvertibleErrorCode());
 }
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/LinePrinter.h b/llvm/include/llvm/DebugInfo/PDB/Native/LinePrinter.h
index bb029e534c74e0..9b443948506517 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/LinePrinter.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/LinePrinter.h
@@ -61,10 +61,10 @@ class LinePrinter {
   void printLine(const Twine &T);
   void print(const Twine &T);
   template <typename... Ts> void formatLine(const char *Fmt, Ts &&...Items) {
-    printLine(formatv(Fmt, std::forward<Ts>(Items)...));
+    printLine(formatvv(Fmt, std::forward<Ts>(Items)...));
   }
   template <typename... Ts> void format(const char *Fmt, Ts &&...Items) {
-    print(formatv(Fmt, std::forward<Ts>(Items)...));
+    print(formatvv(Fmt, std::forward<Ts>(Items)...));
   }
 
   void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
diff --git a/llvm/include/llvm/Support/FormatVariadic.h b/llvm/include/llvm/Support/FormatVariadic.h
index c0c931b3541040..dbac5816782ffd 100644
--- a/llvm/include/llvm/Support/FormatVariadic.h
+++ b/llvm/include/llvm/Support/FormatVariadic.h
@@ -66,6 +66,7 @@ struct ReplacementItem {
 class formatv_object_base {
 protected:
   StringRef Fmt;
+  bool ValidateNumArgs;
   ArrayRef<support::detail::format_adapter *> Adapters;
 
   static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
@@ -74,9 +75,9 @@ class formatv_object_base {
   static std::pair<ReplacementItem, StringRef>
   splitLiteralAndReplacement(StringRef Fmt);
 
-  formatv_object_base(StringRef Fmt,
+  formatv_object_base(StringRef Fmt, bool ValidateNumArgs,
                       ArrayRef<support::detail::format_adapter *> Adapters)
-      : Fmt(Fmt), Adapters(Adapters) {}
+      : Fmt(Fmt), ValidateNumArgs(ValidateNumArgs), Adapters(Adapters) {}
 
   formatv_object_base(formatv_object_base const &rhs) = delete;
   formatv_object_base(formatv_object_base &&rhs) = default;
@@ -87,9 +88,11 @@ class formatv_object_base {
     // Fail formatv() call if the number of replacement parameters provided
     // does not match the expected number after parsing the format string.
     // Assert in debug builds.
-    assert(NumExpectedParams == Adapters.size() &&
-           "Mismatch between replacement parameters expected and provided");
-    if (NumExpectedParams != Adapters.size()) {
+    if (ValidateNumArgs && NumExpectedParams != Adapters.size()) {
+      errs() << "Invalid format() in formatv: " << Fmt << "\n";
+      assert(0 &&
+             "Mismatch between replacement parameters expected and provided");
+
       S << "formatv() error: " << NumExpectedParams
         << " replacement parameters expected, but " << Adapters.size()
         << " provided";
@@ -166,8 +169,8 @@ template <typename Tuple> class formatv_object : public formatv_object_base {
   };
 
 public:
-  formatv_object(StringRef Fmt, Tuple &&Params)
-      : formatv_object_base(Fmt, ParameterPointers),
+  formatv_object(StringRef Fmt, bool ValidateNumArgs, Tuple &&Params)
+      : formatv_object_base(Fmt, ValidateNumArgs, ParameterPointers),
         Parameters(std::move(Params)) {
     ParameterPointers = std::apply(create_adapters(), Parameters);
   }
@@ -264,15 +267,31 @@ template <typename Tuple> class formatv_object : public formatv_object_base {
 // assertion.  Otherwise, it will try to do something reasonable, but in general
 // the details of what that is are undefined.
 //
+
+// formatv() with a literal string as as the format.
+template <size_t N, typename... Ts>
+inline auto formatv(const char (&Fmt)[N], Ts &&...Vals)
+    -> formatv_object<decltype(std::make_tuple(
+        support::detail::build_format_adapter(std::forward<Ts>(Vals))...))> {
+  using ParamTuple = decltype(std::make_tuple(
+      support::detail::build_format_adapter(std::forward<Ts>(Vals))...));
+  return formatv_object<ParamTuple>(
+      Fmt, /*ValidateNumArgs=*/true,
+      std::make_tuple(
+          support::detail::build_format_adapter(std::forward<Ts>(Vals))...));
+}
+
+// formatvv() with a variable string as as the format.
 template <typename... Ts>
-inline auto formatv(const char *Fmt, Ts &&...Vals)
+inline auto formatvv(const char *Fmt, Ts &&...Vals)
     -> formatv_object<decltype(std::make_tuple(
         support::detail::build_format_adapter(std::forward<Ts>(Vals))...))> {
   using ParamTuple = decltype(std::make_tuple(
       support::detail::build_format_adapter(std::forward<Ts>(Vals))...));
   return formatv_object<ParamTuple>(
-      Fmt, std::make_tuple(support::detail::build_format_adapter(
-               std::forward<Ts>(Vals))...));
+      Fmt, /*ValidateNumArgs=*/false,
+      std::make_tuple(
+          support::detail::build_format_adapter(std::forward<Ts>(Vals))...));
 }
 
 } // end namespace llvm
diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
index 280d3f1861ff00..8ad45d1e6f07be 100644
--- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
@@ -2986,7 +2986,7 @@ Error DWARFLinker::link() {
 
     int64_t InputTotal = 0;
     int64_t OutputTotal = 0;
-    const char *FormatStr = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n";
+    const char FormatStr[] = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n";
 
     // Print header.
     outs() << ".debug_info section size (in bytes)\n";
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
index 6d9e3319db7e5e..2dd56f779eabfd 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
@@ -915,7 +915,7 @@ void DWARFLinkerImpl::printStatistic() {
 
   int64_t InputTotal = 0;
   int64_t OutputTotal = 0;
-  const char *FormatStr = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n";
+  const char FormatStr[] = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n";
 
   // Print header.
   outs() << ".debug_info section size (in bytes)\n";
diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp
index 2729e323696543..00dc22abb61109 100644
--- a/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp
+++ b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp
@@ -35,7 +35,7 @@ static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) {
   SmallString<64> MessageStorage;
   StringRef Context;
   if (sizeof...(Args) > 0) {
-    MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str();
+    MessageStorage = formatvv(Str, std::forward<Ts>(Args)...).str();
     Context = MessageStorage;
   } else
     Context = Str;
diff --git a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp
index 6448adaa0ceb36..48ee16e7574fd7 100644
--- a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp
@@ -348,10 +348,10 @@ void CompileOnDemandLayer::emitPartition(
             HC = hash_combine(HC, hash_combine_range(GVName.begin(), GVName.end()));
           }
           raw_string_ostream(SubModuleName)
-            << ".submodule."
-            << formatv(sizeof(size_t) == 8 ? "{0:x16}" : "{0:x8}",
-                       static_cast<size_t>(HC))
-            << ".ll";
+              << ".submodule."
+              << formatvv(sizeof(size_t) == 8 ? "{0:x16}" : "{0:x8}",
+                          static_cast<size_t>(HC))
+              << ".ll";
         }
 
         // Extract the requested partiton (plus any necessary aliases) and
diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
index be10c32cf08d56..96d73b50dd934d 100644
--- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
@@ -94,7 +94,7 @@ static void writeMeasurementValue(raw_ostream &OS, const double Value) {
   static constexpr StringLiteral SimpleFloatFormat = StringLiteral("{0:F}");
 
   writeEscaped<Tag>(
-      OS, formatv(SimpleFloatFormat.data(), Value).sstr<SerializationLen>());
+      OS, formatvv(SimpleFloatFormat.data(), Value).sstr<SerializationLen>());
 }
 
 template <typename EscapeTag, EscapeTag Tag>
diff --git a/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp b/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
index f36d3ba99775b4..f214122366c2e1 100644
--- a/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
+++ b/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
@@ -51,7 +51,7 @@ class ProfileSummaryInfoTest : public testing::Test {
                                          double PartialProfileRatio = 0.0,
                                          uint64_t HotNumCounts = 3,
                                          uint64_t ColdNumCounts = 10) {
-    const char *ModuleString =
+    const char ModuleString[] =
         "define i32 @g(i32 %x) !prof !21 {{\n"
         "  ret i32 0\n"
         "}\n"
@@ -91,7 +91,7 @@ class ProfileSummaryInfoTest : public testing::Test {
         "!22 = !{{!\"function_entry_count\", i64 100}\n"
         "!23 = !{{!\"branch_weights\", i32 64, i32 4}\n"
         "{0}";
-    const char *SummaryString =
+    const char SummaryString[] =
         "!llvm.module.flags = !{{!1}\n"
         "!1 = !{{i32 1, !\"ProfileSummary\", !2}\n"
         "!2 = !{{!3, !4, !5, !6, !7, !8, !9, !10, !11, !12}\n"
diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index b94c432f73b41a..a7e43ca47b685d 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -520,7 +520,7 @@ struct format_tuple {
   explicit format_tuple(const char *Fmt) : Fmt(Fmt) {}
 
   template <typename... Ts> auto operator()(Ts &&... Values) const {
-    return formatv(Fmt, std::forward<Ts>(Values)...);
+    return formatvv(Fmt, std::forward<Ts>(Values)...);
   }
 };
 
@@ -536,12 +536,12 @@ TEST(FormatVariadicTest, BigTest) {
             .08215f, (void *)nullptr, 0, 6.62E-34, -908234908423,
             908234908422234, std::numeric_limits<double>::infinity(), 0x0)};
   // Test long string formatting with many edge cases combined.
-  const char *Intro =
+  const char Intro[] =
       "There are {{{0}} items in the tuple, and {{{1}} tuple(s) in the array.";
-  const char *Header =
+  const char Header[] =
       "{0,6}|{1,8}|{2,=10}|{3,=10}|{4,=13}|{5,7}|{6,7}|{7,10}|{8,"
       "-7}|{9,10}|{10,16}|{11,17}|{12,6}|{13,4}";
-  const char *Line =
+  const char Line[] =
       "{0,6}|{1,8:X}|{2,=10}|{3,=10:5}|{4,=13}|{5,7:3}|{6,7:P2}|{7,"
       "10:X8}|{8,-7:N}|{9,10:E4}|{10,16:N}|{11,17:D}|{12,6}|{13,"
       "4:X}";
@@ -719,7 +719,7 @@ TEST(FormatVariadicTest, FormatError) {
 }
 
 TEST(FormatVariadicTest, FormatErrorNumArgMismatch) {
-#ifndef NDEBUG
+#ifdef NDEBUG // Disable the test in debug builds where it will assert.
   EXPECT_EQ(
       formatv("{0}", 0, 1).str(),
       "formatv() error: 1 replacement parameters expected, but 2 provided");
diff --git a/mlir/include/mlir/TableGen/CodeGenHelpers.h b/mlir/include/mlir/TableGen/CodeGenHelpers.h
index c263c69c53d1e3..4df4c5f375d85d 100644
--- a/mlir/include/mlir/TableGen/CodeGenHelpers.h
+++ b/mlir/include/mlir/TableGen/CodeGenHelpers.h
@@ -31,11 +31,16 @@ class Constraint;
 class DagLeaf;
 
 // Format into a std::string
-template <typename... Parameters>
-std::string strfmt(const char *fmt, Parameters &&...parameters) {
+template <size_t N, typename... Parameters>
+std::string strfmt(const char (&fmt)[N], Parameters &&...parameters) {
   return llvm::formatv(fmt, std::forward<Parameters>(parameters)...).str();
 }
 
+template <typename... Parameters>
+std::string strfmtv(const char *fmt, Parameters &&...parameters) {
+  return llvm::formatvv(fmt, std::forward<Parameters>(parameters)...).str();
+}
+
 // Simple RAII helper for defining ifdef-undef-endif scopes.
 class IfDefScope {
 public:
diff --git a/mlir/include/mlir/Tools/lsp-server-support/Logging.h b/mlir/include/mlir/Tools/lsp-server-support/Logging.h
index 9b090d05f7fa47..aacc61b6098f2a 100644
--- a/mlir/include/mlir/Tools/lsp-server-support/Logging.h
+++ b/mlir/include/mlir/Tools/lsp-server-support/Logging.h
@@ -32,15 +32,15 @@ class Logger {
   /// after a call to `initialize`.
   template <typename... Ts>
   static void debug(const char *fmt, Ts &&...vals) {
-    log(Level::Debug, fmt, llvm::formatv(fmt, std::forward<Ts>(vals)...));
+    log(Level::Debug, fmt, llvm::formatvv(fmt, std::forward<Ts>(vals)...));
   }
   template <typename... Ts>
   static void info(const char *fmt, Ts &&...vals) {
-    log(Level::Info, fmt, llvm::formatv(fmt, std::forward<Ts>(vals)...));
+    log(Level::Info, fmt, llvm::formatvv(fmt, std::forward<Ts>(vals)...));
   }
   template <typename... Ts>
   static void error(const char *fmt, Ts &&...vals) {
-    log(Level::Error, fmt, llvm::formatv(fmt, std::forward<Ts>(vals)...));
+    log(Level::Error, fmt, llvm::formatvv(fmt, std::forward<Ts>(vals)...));
   }
 
 private:
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
index be4ab361083b9a..209abd092ec5df 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
@@ -333,7 +333,7 @@ static DiagnosedSilenceableFailure containsAll(ArrayRef<unsigned> reference,
         })) {
       continue;
     }
-    return emitSilenceableFailure(loc) << llvm::formatv(message, value);
+    return emitSilenceableFailure(loc) << llvm::formatvv(message, value);
   }
   return DiagnosedSilenceableFailure::success();
 }
diff --git a/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp b/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
index edd939eda7c599..523561b10cd253 100644
--- a/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
+++ b/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
@@ -33,7 +33,7 @@ Value mlir::x86vector::avx2::inline_asm::mm256BlendPsAsm(
     ImplicitLocOpBuilder &b, Value v1, Value v2, uint8_t mask) {
   auto asmDialectAttr =
       LLVM::AsmDialectAttr::get(b.getContext(), LLVM::AsmDialect::AD_Intel);
-  const auto *asmTp = "vblendps $0, $1, $2, {0}";
+  const char asmTp[] = "vblendps $0, $1, $2, {0}";
   const auto *asmCstr =
       "=x,x,x"; // Careful: constraint parser is very brittle: no ws!
   SmallVector<Value> asmVals{v1, v2};
diff --git a/mlir/lib/TableGen/CodeGenHelpers.cpp b/mlir/lib/TableGen/CodeGenHelpers.cpp
index 718a8136944bdf..d366c2d2c80a4f 100644
--- a/mlir/lib/TableGen/CodeGenHelpers.cpp
+++ b/mlir/lib/TableGen/CodeGenHelpers.cpp
@@ -110,7 +110,7 @@ StringRef StaticVerifierFunctionEmitter::getRegionConstraintFn(
 
 /// Code for a type constraint. These may be called on the type of either
 /// operands or results.
-static const char *const typeConstraintCode = R"(
+static const char typeConstraintCode[] = R"(
 static ::llvm::LogicalResult {0}(
     ::mlir::Operation *op, ::mlir::Type type, ::llvm::StringRef valueKind,
     unsigned valueIndex) {
@@ -128,7 +128,7 @@ static ::llvm::LogicalResult {0}(
 ///
 /// TODO: Unique constraints for adaptors. However, most Adaptor::verify
 /// functions are stripped anyways.
-static const char *const attrConstraintCode = R"(
+static const char attrConstraintCode[] = R"(
 static ::llvm::LogicalResult {0}(
     ::mlir::Attribute attr, ::llvm::StringRef attrName, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) {{
   if (attr && !({1}))
@@ -145,7 +145,7 @@ static ::llvm::LogicalResult {0}(
 )";
 
 /// Code for a successor constraint.
-static const char *const successorConstraintCode = R"(
+static const char successorConstraintCode[] = R"(
 static ::llvm::LogicalResult {0}(
     ::mlir::Operation *op, ::mlir::Block *successor,
     ::llvm::StringRef successorName, unsigned successorIndex) {
@@ -159,7 +159,7 @@ static ::llvm::LogicalResult {0}(
 
 /// Code for a region constraint. Callers will need to pass in the region's name
 /// for emitting an error message.
-static const char *const regionConstraintCode = R"(
+static const char regionConstraintCode[] = R"(
 static ::llvm::LogicalResult {0}(
     ::mlir::Operation *op, ::mlir::Region &region, ::llvm::StringRef regionName,
     unsigned regionIndex) {
@@ -175,7 +175,7 @@ static ::llvm::LogicalResult {0}(
 /// Code for a pattern type or attribute constraint.
 ///
 /// {3}: "Type type" or "Attribute attr".
-static const char *const patternAttrOrTypeConstraintCode = R"(
+static const char patternAttrOrTypeConstraintCode[] = R"(
 static ::llvm::LogicalResult {0}(
     ::mlir::PatternRewriter &rewriter, ::mlir::Operation *op, ::mlir::{3},
     ::llvm::StringRef failureStr) {
@@ -194,9 +194,9 @@ void StaticVerifierFunctionEmitter::emitConstraints(
   FmtContext ctx;
   ctx.addSubst("_op", "*op").withSelf(selfName);
   for (auto &it : constraints) {
-    os << formatv(codeTemplate, it.second,
-                  tgfmt(it.first.getConditionTemplate(), &ctx),
-                  escapeString(it.first.getSummary()));
+    os << formatvv(codeTemplate, it.second,
+                   tgfmt(it.first.getConditionTemplate(), &ctx),
+                   escapeString(it.first.getSummary()));
   }
 }
 
diff --git a/mlir/lib/TableGen/Pattern.cpp b/mlir/lib/TableGen/Pattern.cpp
index afb69e7cc55866..3a1bdac6dabe49 100644
--- a/mlir/lib/TableGen/Pattern.cpp
+++ b/mlir/lib/TableGen/Pattern.cpp
@@ -27,6 +27,7 @@ using namespace mlir;
 using namespace tblgen;
 
 using llvm::formatv;
+using llvm::formatvv;
 
 //===----------------------------------------------------------------------===//
 // DagLeaf
@@ -295,7 +296,7 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
   switch (kind) {
   case Kind::Attr: {
     assert(index < 0);
-    auto repl = formatv(fmt, name);
+    auto repl = formatvv(fmt, name);
     LLVM_DEBUG(llvm::dbgs() << repl << " (Attr)\n");
     return std::string(repl);
   }
@@ -306,11 +307,11 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
     // index, then return the full variadic operand_range. Otherwise, return
     // the value itself.
     if (operand->isVariableLength() && !getVariadicSubIndex().has_value()) {
-      auto repl = formatv(fmt, name);
+      auto repl = formatvv(fmt, name);
       LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicOperand)\n");
       return std::string(repl);
     }
-    auto repl = formatv(fmt, formatv("(*{0}.begin())", name));
+    auto repl = formatvv(fmt, formatv("(*{0}.begin())", name));
     LLVM_DEBUG(llvm::dbgs() << repl << " (SingleOperand)\n");
     return std::string(repl);
   }
@@ -322,7 +323,7 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
           std::string(formatv("{0}.getODSResults({1})", name, index));
       if (!op->getResult(index).isVariadic())
         v = std::string(formatv("(*{0}.begin())", v));
-      auto repl = formatv(fmt, v);
+      auto repl = formatvv(fmt, v);
       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
       return std::string(repl);
     }
@@ -331,7 +332,7 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
     // means we want to capture the op itself.
     if (op->getNumResults() == 0) {
       LLVM_DEBUG(llvm::dbgs() << name << " (Op)\n");
-      return formatv(fmt, name);
+      return formatvv(fmt, name);
     }
 
     // We are referencing all results of the multi-result op. A specific result
@@ -344,7 +345,7 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
       if (!op->getResult(i).isVariadic()) {
         v = std::string(formatv("(*{0}.begin())", v));
       }
-      values.push_back(std::string(formatv(fmt, v)));
+      values.push_back(std::string(formatvv(fmt, v)));
     }
     auto repl = llvm::join(values, separator);
     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
@@ -353,7 +354,7 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
   case Kind::Value: {
     assert(index < 0);
     assert(op == nullptr);
-    auto repl = formatv(fmt, name);
+    auto repl = formatvv(fmt, name);
     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
     return std::string(repl);
   }
@@ -362,13 +363,13 @@ std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
     assert(index < getSize());
     if (index >= 0) {
       std::string repl =
-          formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
+          formatvv(fmt, std::string(formatv("{0}[{1}]", name, index)));
       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
       return repl;
     }
     // If it doesn't specify certain element, unpack them all.
     auto repl =
-        formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
+        formatvv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
     return std::string(repl);
   }
@@ -383,13 +384,13 @@ std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
   case Kind::Attr:
   case Kind::Operand: {
     assert(index < 0 && "only allowed for symbol bound to result");
-    auto repl = formatv(fmt, name);
+    auto repl = formatvv(fmt, name);
     LLVM_DEBUG(llvm::dbgs() << repl << " (Operand/Attr)\n");
     return std::string(repl);
   }
   case Kind::Result: {
     if (index >= 0) {
-      auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index));
+      auto repl = formatvv(fmt, formatv("{0}.getODSResults({1})", name, index));
       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
       return std::string(repl);
     }
@@ -401,7 +402,7 @@ std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
 
     for (int i = 0, e = op->getNumResults(); i < e; ++i) {
       values.push_back(std::string(
-          formatv(fmt, formatv("{0}.getODSResults({1})", name, i))));
+          formatvv(fmt, formatv("{0}.getODSResults({1})", name, i))));
     }
     auto repl = llvm::join(values, separator);
     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
@@ -410,7 +411,7 @@ std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
   case Kind::Value: {
     assert(index < 0 && "only allowed for symbol bound to result");
     assert(op == nullptr);
-    auto repl = formatv(fmt, formatv("{{{0}}", name));
+    auto repl = formatvv(fmt, formatv("{{{0}}", name));
     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
     return std::string(repl);
   }
@@ -419,12 +420,12 @@ std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
     assert(index < getSize());
     if (index >= 0) {
       std::string repl =
-          formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
+          formatvv(fmt, std::string(formatv("{0}[{1}]", name, index)));
       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
       return repl;
     }
     auto repl =
-        formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
+        formatvv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
     return std::string(repl);
   }
diff --git a/mlir/lib/Tools/PDLL/CodeGen/CPPGen.cpp b/mlir/lib/Tools/PDLL/CodeGen/CPPGen.cpp
index 611b734dc4b056..539548ea5c2d38 100644
--- a/mlir/lib/Tools/PDLL/CodeGen/CPPGen.cpp
+++ b/mlir/lib/Tools/PDLL/CodeGen/CPPGen.cpp
@@ -105,7 +105,7 @@ void CodeGen::generate(const ast::Module &astModule, ModuleOp module) {
 
 void CodeGen::generate(pdl::PatternOp pattern, StringRef patternName,
                        StringSet<> &nativeFunctions) {
-  const char *patternClassStartStr = R"(
+  const char patternClassStartStr[] = R"(
 struct {0} : ::mlir::PDLPatternModule {{
   template <typename... ConfigsT>
   {0}(::mlir::MLIRContext *context, ConfigsT &&...configs)
diff --git a/mlir/lib/Tools/lsp-server-support/Transport.cpp b/mlir/lib/Tools/lsp-server-support/Transport.cpp
index ca7ffdf78d3a1b..82294df22da48b 100644
--- a/mlir/lib/Tools/lsp-server-support/Transport.cpp
+++ b/mlir/lib/Tools/lsp-server-support/Transport.cpp
@@ -230,7 +230,7 @@ llvm::Error JSONTransport::run(MessageHandler &handler) {
 void JSONTransport::sendMessage(llvm::json::Value msg) {
   outputBuffer.clear();
   llvm::raw_svector_ostream os(outputBuffer);
-  os << llvm::formatv(prettyOutput ? "{0:2}\n" : "{0}", msg);
+  os << llvm::formatvv(prettyOutput ? "{0:2}\n" : "{0}", msg);
   out << "Content-Length: " << outputBuffer.size() << "\r\n\r\n"
       << outputBuffer;
   out.flush();
diff --git a/mlir/lib/Transforms/Utils/DialectConversion.cpp b/mlir/lib/Transforms/Utils/DialectConversion.cpp
index bf2990c257bad2..89828820d93565 100644
--- a/mlir/lib/Transforms/Utils/DialectConversion.cpp
+++ b/mlir/lib/Transforms/Utils/DialectConversion.cpp
@@ -37,7 +37,8 @@ static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
     os.startLine() << "} -> SUCCESS";
     if (!fmt.empty())
       os.getOStream() << " : "
-                      << llvm::formatv(fmt.data(), std::forward<Args>(args)...);
+                      << llvm::formatvv(fmt.data(),
+                                        std::forward<Args>(args)...);
     os.getOStream() << "\n";
   });
 }
@@ -48,7 +49,7 @@ static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
   LLVM_DEBUG({
     os.unindent();
     os.startLine() << "} -> FAILURE : "
-                   << llvm::formatv(fmt.data(), std::forward<Args>(args)...)
+                   << llvm::formatvv(fmt.data(), std::forward<Args>(args)...)
                    << "\n";
   });
 }
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
index eccd8029d950ff..a78b94407d94ed 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
@@ -326,7 +326,7 @@ void DefGen::emitVerifierDecl() {
                          "emitError"}}));
 }
 
-static const char *const patternParameterVerificationCode = R"(
+static const char patternParameterVerificationCode[] = R"(
 if (!({0})) {
   emitError() << "failed to verify '{1}': {2}";
   return ::mlir::failure();
@@ -800,7 +800,7 @@ void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) {
 /// {0}: the dialect fully qualified class name.
 /// {1}: the optional code for the dynamic attribute parser dispatch.
 /// {2}: the optional code for the dynamic attribute printer dispatch.
-static const char *const dialectDefaultAttrPrinterParserDispatch = R"(
+static const char dialectDefaultAttrPrinterParserDispatch[] = R"(
 /// Parse an attribute registered to this dialect.
 ::mlir::Attribute {0}::parseAttribute(::mlir::DialectAsmParser &parser,
                                       ::mlir::Type type) const {{
@@ -827,7 +827,7 @@ void {0}::printAttribute(::mlir::Attribute attr,
 )";
 
 /// The code block for dynamic attribute parser dispatch boilerplate.
-static const char *const dialectDynamicAttrParserDispatch = R"(
+static const char dialectDynamicAttrParserDispatch[] = R"(
   {
     ::mlir::Attribute genAttr;
     auto parseResult = parseOptionalDynamicAttr(attrTag, parser, genAttr);
@@ -840,7 +840,7 @@ static const char *const dialectDynamicAttrParserDispatch = R"(
 )";
 
 /// The code block for dynamic type printer dispatch boilerplate.
-static const char *const dialectDynamicAttrPrinterDispatch = R"(
+static const char dialectDynamicAttrPrinterDispatch[] = R"(
   if (::mlir::succeeded(printIfDynamicAttr(attr, printer)))
     return;
 )";
@@ -849,7 +849,7 @@ static const char *const dialectDynamicAttrPrinterDispatch = R"(
 /// {0}: the dialect fully qualified class name.
 /// {1}: the optional code for the dynamic type parser dispatch.
 /// {2}: the optional code for the dynamic type printer dispatch.
-static const char *const dialectDefaultTypePrinterParserDispatch = R"(
+static const char dialectDefaultTypePrinterParserDispatch[] = R"(
 /// Parse a type registered to this dialect.
 ::mlir::Type {0}::parseType(::mlir::DialectAsmParser &parser) const {{
   ::llvm::SMLoc typeLoc = parser.getCurrentLocation();
@@ -873,7 +873,7 @@ void {0}::printType(::mlir::Type type,
 )";
 
 /// The code block for dynamic type parser dispatch boilerplate.
-static const char *const dialectDynamicTypeParserDispatch = R"(
+static const char dialectDynamicTypeParserDispatch[] = R"(
   {
     auto parseResult = parseOptionalDynamicType(mnemonic, parser, genType);
     if (parseResult.has_value()) {
@@ -885,7 +885,7 @@ static const char *const dialectDynamicTypeParserDispatch = R"(
 )";
 
 /// The code block for dynamic type printer dispatch boilerplate.
-static const char *const dialectDynamicTypePrinterDispatch = R"(
+static const char dialectDynamicTypePrinterDispatch[] = R"(
   if (::mlir::succeeded(printIfDynamicType(type, printer)))
     return;
 )";
@@ -918,7 +918,7 @@ void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) {
   parse.body() << "  return "
                   "::mlir::AsmParser::KeywordSwitch<::mlir::"
                   "OptionalParseResult>(parser)\n";
-  const char *const getValueForMnemonic =
+  static const char getValueForMnemonic[] =
       R"(    .Case({0}::getMnemonic(), [&](llvm::StringRef, llvm::SMLoc) {{
       value = {0}::{1};
       return ::mlir::success(!!value);
@@ -929,7 +929,7 @@ void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) {
   // printer.
   printer.body() << "  return ::llvm::TypeSwitch<::mlir::" << valueType
                  << ", ::llvm::LogicalResult>(def)";
-  const char *const printValue = R"(    .Case<{0}>([&](auto t) {{
+  static const char printValue[] = R"(    .Case<{0}>([&](auto t) {{
       printer << {0}::getMnemonic();{1}
       return ::mlir::success();
     })
@@ -1048,7 +1048,7 @@ getAllTypeConstraints(const llvm::RecordKeeper &records) {
 
 static void emitTypeConstraintDecls(const llvm::RecordKeeper &records,
                                     raw_ostream &os) {
-  static const char *const typeConstraintDecl = R"(
+  static const char typeConstraintDecl[] = R"(
 bool {0}(::mlir::Type type);
 )";
 
@@ -1058,7 +1058,7 @@ bool {0}(::mlir::Type type);
 
 static void emitTypeConstraintDefs(const llvm::RecordKeeper &records,
                                    raw_ostream &os) {
-  static const char *const typeConstraintDef = R"(
+  static const char typeConstraintDef[] = R"(
 bool {0}(::mlir::Type type) {
   return ({1});
 }
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
index a4ae271edb6bd2..ab19f5b3f446c5 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
@@ -138,21 +138,21 @@ class StructDirective : public ParamsDirectiveBase<DirectiveElement::Struct> {
 //===----------------------------------------------------------------------===//
 
 /// Default parser for attribute or type parameters.
-static const char *const defaultParameterParser =
+static const char defaultParameterParser[] =
     "::mlir::FieldParser<$0>::parse($_parser)";
 
 /// Default printer for attribute or type parameters.
-static const char *const defaultParameterPrinter =
+static const char defaultParameterPrinter[] =
     "$_printer.printStrippedAttrOrType($_self)";
 
 /// Qualified printer for attribute or type parameters: it does not elide
 /// dialect and mnemonic.
-static const char *const qualifiedParameterPrinter = "$_printer << $_self";
+static const char qualifiedParameterPrinter[] = "$_printer << $_self";
 
 /// Print an error when failing to parse an element.
 ///
 /// $0: The parameter C++ class name.
-static const char *const parserErrorStr =
+static const char parserErrorStr[] =
     "$_parser.emitError($_parser.getCurrentLocation(), ";
 
 /// Code format to parse a variable. Separate by lines because variable parsers
@@ -164,7 +164,7 @@ static const char *const parserErrorStr =
 /// {3}: Name of the attribute or type.
 /// {4}: C++ class of the parameter.
 /// {5}: Optional code to preload the dialect for this variable.
-static const char *const variableParser = R"(
+static const char variableParser[] = R"(
 // Parse variable '{0}'{5}
 _result_{0} = {1};
 if (::mlir::failed(_result_{0})) {{
@@ -500,12 +500,12 @@ void DefFormat::genStructParser(StructDirective *el, FmtContext &ctx,
   // Loop declaration for struct parser with only required parameters.
   //
   // $0: Number of expected parameters.
-  const char *const loopHeader = R"(
+  static const char loopHeader[] = R"(
   for (unsigned odsStructIndex = 0; odsStructIndex < $0; ++odsStructIndex) {
 )";
 
   // Loop body start for struct parser.
-  const char *const loopStart = R"(
+  static const char loopStart[] = R"(
     ::llvm::StringRef _paramKey;
     if ($_parser.parseKeyword(&_paramKey)) {
       $_parser.emitError($_parser.getCurrentLocation(),
@@ -518,7 +518,7 @@ void DefFormat::genStructParser(StructDirective *el, FmtContext &ctx,
   // Struct parser loop end. Check for duplicate or unknown struct parameters.
   //
   // {0}: Code template for printing an error.
-  const char *const loopEnd = R"({{
+  static const char loopEnd[] = R"({{
   {0}"duplicate or unknown struct parameter name: ") << _paramKey;
   return {{};
 }
@@ -527,7 +527,7 @@ void DefFormat::genStructParser(StructDirective *el, FmtContext &ctx,
   // Struct parser loop terminator. Parse a comma except on the last element.
   //
   // {0}: Number of elements in the struct.
-  const char *const loopTerminator = R"(
+  static const char loopTerminator[] = R"(
   if ((odsStructIndex != {0} - 1) && odsParser.parseComma())
     return {{};
 }
@@ -536,7 +536,7 @@ void DefFormat::genStructParser(StructDirective *el, FmtContext &ctx,
   // Check that a mandatory parameter was parse.
   //
   // {0}: Name of the parameter.
-  const char *const checkParam = R"(
+  static const char checkParam[] = R"(
     if (!_seen_{0}) {
       {1}"struct is missing required parameter: ") << "{0}";
       return {{};
@@ -544,7 +544,7 @@ void DefFormat::genStructParser(StructDirective *el, FmtContext &ctx,
 )";
 
   // First iteration of the loop parsing an optional struct.
-  const char *const optionalStructFirst = R"(
+  static const char optionalStructFirst[] = R"(
   ::llvm::StringRef _paramKey;
   if (!$_parser.parseOptionalKeyword(&_paramKey)) {
     if (!_loop_body(_paramKey)) return {};
diff --git a/mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp b/mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp
index 66a3750d7c8266..0f90f9721fdc22 100644
--- a/mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp
+++ b/mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp
@@ -87,14 +87,14 @@ static std::string getCType(Record *def) {
     if (def->isAnonymous())
       PrintFatalError(def->getLoc(), "Unable to determine cType");
 
-    return formatv(format.c_str(), def->getName().str());
+    return formatvv(format.c_str(), def->getName().str());
   }
-  return formatv(format.c_str(), cType.str());
+  return formatvv(format.c_str(), cType.str());
 }
 
 void Generator::emitParseDispatch(StringRef kind, ArrayRef<Record *> vec) {
   mlir::raw_indented_ostream os(output);
-  char const *head =
+  char const head[] =
       R"(static {0} read{0}(MLIRContext* context, DialectBytecodeReader &reader))";
   os << formatv(head, capitalize(kind));
   auto funScope = os.scope(" {\n", "}\n\n");
@@ -130,7 +130,7 @@ void Generator::emitParse(StringRef kind, Record &x) {
   if (x.getNameInitAsString() == "ReservedOrDead")
     return;
 
-  char const *head =
+  char const head[] =
       R"(static {0} read{1}(MLIRContext* context, DialectBytecodeReader &reader) )";
   mlir::raw_indented_ostream os(output);
   std::string returnType = getCType(&x);
@@ -297,7 +297,7 @@ void Generator::emitPrint(StringRef kind, StringRef type,
   if (type == "ReservedOrDead")
     return;
 
-  char const *head =
+  char const head[] =
       R"(static void write({0} {1}, DialectBytecodeWriter &writer) )";
   mlir::raw_indented_ostream os(output);
   os << formatv(head, type, kind);
@@ -401,7 +401,7 @@ void Generator::emitPrintHelper(Record *memberRec, StringRef kind,
 
 void Generator::emitPrintDispatch(StringRef kind, ArrayRef<std::string> vec) {
   mlir::raw_indented_ostream os(output);
-  char const *head = R"(static LogicalResult write{0}({0} {1},
+  char const head[] = R"(static LogicalResult write{0}({0} {1},
                                 DialectBytecodeWriter &writer))";
   os << formatv(head, capitalize(kind), kind);
   auto funScope = os.scope(" {\n", "}\n\n");
diff --git a/mlir/tools/mlir-tblgen/DialectGen.cpp b/mlir/tools/mlir-tblgen/DialectGen.cpp
index 2412876958a0c9..3560611fadf035 100644
--- a/mlir/tools/mlir-tblgen/DialectGen.cpp
+++ b/mlir/tools/mlir-tblgen/DialectGen.cpp
@@ -106,7 +106,7 @@ tblgen::findDialectToGenerate(ArrayRef<Dialect> dialects) {
 /// {0}: The name of the dialect class.
 /// {1}: The dialect namespace.
 /// {2}: The dialect parent class.
-static const char *const dialectDeclBeginStr = R"(
+static const char dialectDeclBeginStr[] = R"(
 class {0} : public ::mlir::{2} {
   explicit {0}(::mlir::MLIRContext *context);
 
@@ -121,11 +121,11 @@ class {0} : public ::mlir::{2} {
 
 /// Registration for a single dependent dialect: to be inserted in the ctor
 /// above for each dependent dialect.
-const char *const dialectRegistrationTemplate =
+static const char dialectRegistrationTemplate[] =
     "getContext()->loadDialect<{0}>();";
 
 /// The code block for the attribute parser/printer hooks.
-static const char *const attrParserDecl = R"(
+static const char attrParserDecl[] = R"(
   /// Parse an attribute registered to this dialect.
   ::mlir::Attribute parseAttribute(::mlir::DialectAsmParser &parser,
                                    ::mlir::Type type) const override;
@@ -136,7 +136,7 @@ static const char *const attrParserDecl = R"(
 )";
 
 /// The code block for the type parser/printer hooks.
-static const char *const typeParserDecl = R"(
+static const char typeParserDecl[] = R"(
   /// Parse a type registered to this dialect.
   ::mlir::Type parseType(::mlir::DialectAsmParser &parser) const override;
 
@@ -146,14 +146,14 @@ static const char *const typeParserDecl = R"(
 )";
 
 /// The code block for the canonicalization pattern registration hook.
-static const char *const canonicalizerDecl = R"(
+static const char canonicalizerDecl[] = R"(
   /// Register canonicalization patterns.
   void getCanonicalizationPatterns(
       ::mlir::RewritePatternSet &results) const override;
 )";
 
 /// The code block for the constant materializer hook.
-static const char *const constantMaterializerDecl = R"(
+static const char constantMaterializerDecl[] = R"(
   /// Materialize a single constant operation from a given attribute value with
   /// the desired resultant type.
   ::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder,
@@ -163,7 +163,7 @@ static const char *const constantMaterializerDecl = R"(
 )";
 
 /// The code block for the operation attribute verifier hook.
-static const char *const opAttrVerifierDecl = R"(
+static const char opAttrVerifierDecl[] = R"(
     /// Provides a hook for verifying dialect attributes attached to the given
     /// op.
     ::llvm::LogicalResult verifyOperationAttribute(
@@ -171,7 +171,7 @@ static const char *const opAttrVerifierDecl = R"(
 )";
 
 /// The code block for the region argument attribute verifier hook.
-static const char *const regionArgAttrVerifierDecl = R"(
+static const char regionArgAttrVerifierDecl[] = R"(
     /// Provides a hook for verifying dialect attributes attached to the given
     /// op's region argument.
     ::llvm::LogicalResult verifyRegionArgAttribute(
@@ -180,7 +180,7 @@ static const char *const regionArgAttrVerifierDecl = R"(
 )";
 
 /// The code block for the region result attribute verifier hook.
-static const char *const regionResultAttrVerifierDecl = R"(
+static const char regionResultAttrVerifierDecl[] = R"(
     /// Provides a hook for verifying dialect attributes attached to the given
     /// op's region result.
     ::llvm::LogicalResult verifyRegionResultAttribute(
@@ -189,14 +189,14 @@ static const char *const regionResultAttrVerifierDecl = R"(
 )";
 
 /// The code block for the op interface fallback hook.
-static const char *const operationInterfaceFallbackDecl = R"(
+static const char operationInterfaceFallbackDecl[] = R"(
     /// Provides a hook for op interface.
     void *getRegisteredInterfaceForOp(mlir::TypeID interfaceID,
                                       mlir::OperationName opName) override;
 )";
 
 /// The code block for the discardable attribute helper.
-static const char *const discardableAttrHelperDecl = R"(
+static const char discardableAttrHelperDecl[] = R"(
     /// Helper to manage the discardable attribute `{1}`.
     class {0}AttrHelper {{
       ::mlir::StringAttr name;
@@ -322,7 +322,7 @@ static bool emitDialectDecls(const llvm::RecordKeeper &recordKeeper,
 ///      initialize(), such as dependent dialect registration.
 /// {2}: The dialect parent class.
 /// {3}: Extra members to initialize
-static const char *const dialectConstructorStr = R"(
+static const char dialectConstructorStr[] = R"(
 {0}::{0}(::mlir::MLIRContext *context)
     : ::mlir::{2}(getDialectNamespace(), context, ::mlir::TypeID::get<{0}>())
     {3}
@@ -335,7 +335,7 @@ static const char *const dialectConstructorStr = R"(
 /// The code block to generate a default destructor definition.
 ///
 /// {0}: The name of the dialect class.
-static const char *const dialectDestructorStr = R"(
+static const char dialectDestructorStr[] = R"(
 {0}::~{0}() = default;
 
 )";
diff --git a/mlir/tools/mlir-tblgen/EnumsGen.cpp b/mlir/tools/mlir-tblgen/EnumsGen.cpp
index f1d7a233b66a9a..0d9537872ddabf 100644
--- a/mlir/tools/mlir-tblgen/EnumsGen.cpp
+++ b/mlir/tools/mlir-tblgen/EnumsGen.cpp
@@ -81,7 +81,7 @@ static void emitParserPrinter(const EnumAttr &enumAttr, StringRef qualName,
       nonKeywordCases.set(index);
 
   // Generate the parser and the start of the printer for the enum.
-  const char *parsedAndPrinterStart = R"(
+  static const char parsedAndPrinterStart[] = R"(
 namespace mlir {
 template <typename T, typename>
 struct FieldParser;
@@ -177,7 +177,7 @@ static void emitDenseMapInfo(StringRef qualName, std::string underlyingType,
     underlyingType =
         std::string(formatv("std::underlying_type_t<{0}>", qualName));
 
-  const char *const mapInfo = R"(
+  static const char mapInfo[] = R"(
 namespace llvm {
 template<> struct DenseMapInfo<{0}> {{
   using StorageInfo = ::llvm::DenseMapInfo<{1}>;
@@ -252,7 +252,7 @@ static void emitOperators(const Record &enumDef, raw_ostream &os) {
   StringRef enumName = enumAttr.getEnumClassName();
   std::string underlyingType = std::string(enumAttr.getUnderlyingType());
   int64_t validBits = enumDef.getValueAsInt("validBits");
-  const char *const operators = R"(
+  static const char operators[] = R"(
 inline constexpr {0} operator|({0} a, {0} b) {{
   return static_cast<{0}>(static_cast<{1}>(a) | static_cast<{1}>(b));
 }
@@ -331,7 +331,7 @@ static void emitSymToStrFnForBitEnum(const Record &enumDef, raw_ostream &os) {
 
   // Add case string if the value has all case bits, and remove them to avoid
   // printing again. Used only for groups, when printBitEnumPrimaryGroups is 1.
-  const char *const formatCompareRemove = R"(
+  static const char formatCompareRemove[] = R"(
   if ({0}u == ({0}u & val)) {{
     strs.push_back("{1}");
     val &= ~static_cast<{2}>({0});
@@ -339,7 +339,7 @@ static void emitSymToStrFnForBitEnum(const Record &enumDef, raw_ostream &os) {
 )";
   // Add case string if the value has all case bits. Used for individual bit
   // cases, and for groups when printBitEnumPrimaryGroups is 0.
-  const char *const formatCompare = R"(
+  static const char formatCompare[] = R"(
   if ({0}u == ({0}u & val))
     strs.push_back("{1}");
 )";
@@ -594,7 +594,7 @@ static void emitEnumDecl(const Record &enumDef, raw_ostream &os) {
 
   // Generate a generic `stringifyEnum` function that forwards to the method
   // specified by the user.
-  const char *const stringifyEnumStr = R"(
+  static const char stringifyEnumStr[] = R"(
 inline {0} stringifyEnum({1} enumValue) {{
   return {2}(enumValue);
 }
@@ -603,7 +603,7 @@ inline {0} stringifyEnum({1} enumValue) {{
 
   // Generate a generic `symbolizeEnum` function that forwards to the method
   // specified by the user.
-  const char *const symbolizeEnumStr = R"(
+  static const char symbolizeEnumStr[] = R"(
 template <typename EnumType>
 ::std::optional<EnumType> symbolizeEnum(::llvm::StringRef);
 
@@ -614,7 +614,7 @@ inline ::std::optional<{0}> symbolizeEnum<{0}>(::llvm::StringRef str) {
 )";
   os << formatv(symbolizeEnumStr, enumName, strToSymFnName);
 
-  const char *const attrClassDecl = R"(
+  static const char attrClassDecl[] = R"(
 class {1} : public ::mlir::{2} {
 public:
   using ValueType = {0};
diff --git a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
index ebadfe4499a54d..5560298831865f 100644
--- a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
+++ b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
@@ -519,7 +519,7 @@ static void emitOneCEnumFromConversion(const llvm::Record *record,
   os << formatv(
       "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM(int64_t "
       "value) {{\n",
-      cppNamespace, cppClassName, llvmClass);
+      cppNamespace, cppClassName);
   os << "  switch (value) {\n";
 
   for (const auto &enumerant : enumAttr.getAllCases()) {
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 66dbb16760ebb0..2017ce60e54073 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -67,7 +67,7 @@ static const char *const resultSegmentAttrName = "resultSegmentSizes";
 /// {2}: The upper bound on the sorted subrange.
 /// {3}: Code snippet to get the array of named attributes.
 /// {4}: "Named" to get the named attribute.
-static const char *const subrangeGetAttr =
+static const char subrangeGetAttr[] =
     "::mlir::impl::get{4}AttrFromSortedRange({3}.begin() + {1}, {3}.end() - "
     "{2}, {0})";
 
@@ -81,7 +81,7 @@ static const char *const subrangeGetAttr =
 /// {2}: The total number of variadic operands/results.
 /// {3}: The total number of actual values.
 /// {4}: "operand" or "result".
-static const char *const sameVariadicSizeValueRangeCalcCode = R"(
+static const char sameVariadicSizeValueRangeCalcCode[] = R"(
   bool isVariadic[] = {{{0}};
   int prevVariadicCount = 0;
   for (unsigned i = 0; i < index; ++i)
@@ -103,7 +103,7 @@ static const char *const sameVariadicSizeValueRangeCalcCode = R"(
 /// of an op with variadic operands/results. Note that this logic is assumes
 /// the op has an attribute specifying the size of each operand/result segment
 /// (variadic or not).
-static const char *const attrSizedSegmentValueRangeCalcCode = R"(
+static const char attrSizedSegmentValueRangeCalcCode[] = R"(
   unsigned start = 0;
   for (unsigned i = 0; i < index; ++i)
     start += sizeAttr[i];
@@ -112,18 +112,18 @@ static const char *const attrSizedSegmentValueRangeCalcCode = R"(
 /// The code snippet to initialize the sizes for the value range calculation.
 ///
 /// {0}: The code to get the attribute.
-static const char *const adapterSegmentSizeAttrInitCode = R"(
+static const char adapterSegmentSizeAttrInitCode[] = R"(
   assert({0} && "missing segment size attribute for op");
   auto sizeAttr = ::llvm::cast<::mlir::DenseI32ArrayAttr>({0});
 )";
-static const char *const adapterSegmentSizeAttrInitCodeProperties = R"(
+static const char adapterSegmentSizeAttrInitCodeProperties[] = R"(
   ::llvm::ArrayRef<int32_t> sizeAttr = {0};
 )";
 
 /// The code snippet to initialize the sizes for the value range calculation.
 ///
 /// {0}: The code to get the attribute.
-static const char *const opSegmentSizeAttrInitCode = R"(
+static const char opSegmentSizeAttrInitCode[] = R"(
   auto sizeAttr = ::llvm::cast<::mlir::DenseI32ArrayAttr>({0});
 )";
 
@@ -133,7 +133,7 @@ static const char *const opSegmentSizeAttrInitCode = R"(
 /// {0}: The name of the segment attribute.
 /// {1}: The index of the main operand.
 /// {2}: The range type of adaptor.
-static const char *const variadicOfVariadicAdaptorCalcCode = R"(
+static const char variadicOfVariadicAdaptorCalcCode[] = R"(
   auto tblgenTmpOperands = getODSOperands({1});
   auto sizes = {0}();
 
@@ -149,7 +149,7 @@ static const char *const variadicOfVariadicAdaptorCalcCode = R"(
 ///
 /// {0}: The begin iterator of the actual values.
 /// {1}: The call to generate the start and length of the value range.
-static const char *const valueRangeReturnCode = R"(
+static const char valueRangeReturnCode[] = R"(
   auto valueRange = {1};
   return {{std::next({0}, valueRange.first),
            std::next({0}, valueRange.first + valueRange.second)};
@@ -157,7 +157,7 @@ static const char *const valueRangeReturnCode = R"(
 
 /// Parse operand/result segment_size property.
 /// {0}: Number of elements in the segment array
-static const char *const parseTextualSegmentSizeFormat = R"(
+static const char parseTextualSegmentSizeFormat[] = R"(
   size_t i = 0;
   auto parseElem = [&]() -> ::mlir::ParseResult {
     if (i >= {0})
@@ -177,7 +177,7 @@ static const char *const parseTextualSegmentSizeFormat = R"(
   return success();
 )";
 
-static const char *const printTextualSegmentSize = R"(
+static const char printTextualSegmentSize[] = R"(
   [&]() {
     $_printer << '[';
     ::llvm::interleaveComma($_storage, $_printer);
@@ -186,12 +186,12 @@ static const char *const printTextualSegmentSize = R"(
 )";
 
 /// Read operand/result segment_size from bytecode.
-static const char *const readBytecodeSegmentSizeNative = R"(
+static const char readBytecodeSegmentSizeNative[] = R"(
   if ($_reader.getBytecodeVersion() >= /*kNativePropertiesODSSegmentSize=*/6)
     return $_reader.readSparseArray(::llvm::MutableArrayRef($_storage));
 )";
 
-static const char *const readBytecodeSegmentSizeLegacy = R"(
+static const char readBytecodeSegmentSizeLegacy[] = R"(
   if ($_reader.getBytecodeVersion() < /*kNativePropertiesODSSegmentSize=*/6) {
     auto &$_storage = prop.$_propName;
     ::mlir::DenseI32ArrayAttr attr;
@@ -205,13 +205,13 @@ static const char *const readBytecodeSegmentSizeLegacy = R"(
 )";
 
 /// Write operand/result segment_size to bytecode.
-static const char *const writeBytecodeSegmentSizeNative = R"(
+static const char writeBytecodeSegmentSizeNative[] = R"(
   if ($_writer.getBytecodeVersion() >= /*kNativePropertiesODSSegmentSize=*/6)
     $_writer.writeSparseArray(::llvm::ArrayRef($_storage));
 )";
 
 /// Write operand/result segment_size to bytecode.
-static const char *const writeBytecodeSegmentSizeLegacy = R"(
+static const char writeBytecodeSegmentSizeLegacy[] = R"(
 if ($_writer.getBytecodeVersion() < /*kNativePropertiesODSSegmentSize=*/6) {
   auto &$_storage = prop.$_propName;
   $_writer.writeAttribute(::mlir::DenseI32ArrayAttr::get($_ctxt, $_storage));
@@ -222,7 +222,7 @@ if ($_writer.getBytecodeVersion() < /*kNativePropertiesODSSegmentSize=*/6) {
 ///
 /// {0}: Some text, or a class name.
 /// {1}: Some text.
-static const char *const opCommentHeader = R"(
+static const char opCommentHeader[] = R"(
 //===----------------------------------------------------------------------===//
 // {0} {1}
 //===----------------------------------------------------------------------===//
@@ -375,10 +375,10 @@ class OpOrAdaptorHelper {
   // Get the call to get an operand or segment of operands.
   Formatter getOperand(unsigned index) const {
     return [this, index](raw_ostream &os) -> raw_ostream & {
-      return os << formatv(op.getOperand(index).isVariadic()
-                               ? "this->getODSOperands({0})"
-                               : "(*this->getODSOperands({0}).begin())",
-                           index);
+      return os << formatvv(op.getOperand(index).isVariadic()
+                                ? "this->getODSOperands({0})"
+                                : "(*this->getODSOperands({0}).begin())",
+                            index);
     };
   }
 
@@ -387,10 +387,10 @@ class OpOrAdaptorHelper {
     return [this, index](raw_ostream &os) -> raw_ostream & {
       if (!emitForOp)
         return os << "<no results should be generated>";
-      return os << formatv(op.getResult(index).isVariadic()
-                               ? "this->getODSResults({0})"
-                               : "(*this->getODSResults({0}).begin())",
-                           index);
+      return os << formatvv(op.getResult(index).isVariadic()
+                                ? "this->getODSResults({0})"
+                                : "(*this->getODSResults({0}).begin())",
+                            index);
     };
   }
 
@@ -822,7 +822,7 @@ static void genNativeTraitAttrVerifier(MethodBody &body,
   // {1}: Expected number of elements.
   // {2}: "operand" or "result".
   // {3}: Emit error prefix.
-  const char *const checkAttrSizedValueSegmentsCode = R"(
+  const char checkAttrSizedValueSegmentsCode[] = R"(
   {
     auto sizeAttr = ::llvm::cast<::mlir::DenseI32ArrayAttr>(tblgen_{0});
     auto numElements = sizeAttr.asArrayRef().size();
@@ -893,7 +893,7 @@ genAttributeVerifier(const OpOrAdaptorHelper &emitHelper, FmtContext &ctx,
   // {2}: Emit error prefix.
   // {3}: Attribute name.
   // {4}: Attribute/constraint description.
-  const char *const verifyAttrInline = R"(
+  const char verifyAttrInline[] = R"(
   if ({0} && !({1}))
     return {2}"attribute '{3}' failed to satisfy constraint: {4}");
 )";
@@ -903,7 +903,7 @@ genAttributeVerifier(const OpOrAdaptorHelper &emitHelper, FmtContext &ctx,
   // {0}: Unique constraint name.
   // {1}: Attribute variable name.
   // {2}: Attribute name.
-  const char *const verifyAttrUnique = R"(
+  const char verifyAttrUnique[] = R"(
   if (::mlir::failed({0}(*this, {1}, "{2}")))
     return ::mlir::failure();
 )";
@@ -914,7 +914,7 @@ genAttributeVerifier(const OpOrAdaptorHelper &emitHelper, FmtContext &ctx,
   // {0}: Code to get the name of the attribute.
   // {1}: The emit error prefix.
   // {2}: The name of the attribute.
-  const char *const findRequiredAttr = R"(
+  const char findRequiredAttr[] = R"(
 while (true) {{
   if (namedAttrIt == namedAttrRange.end())
     return {1}"requires attribute '{2}'");
@@ -927,13 +927,13 @@ while (true) {{
   //
   // {0}: Code to get the name of the attribute.
   // {1}: The name of the attribute.
-  const char *const checkOptionalAttr = R"(
+  const char checkOptionalAttr[] = R"(
   else if (namedAttrIt->getName() == {0}) {{
     tblgen_{1} = namedAttrIt->getValue();
   })";
 
   // Emit the start of the loop for checking trailing attributes.
-  const char *const checkTrailingAttrs = R"(while (true) {
+  const char checkTrailingAttrs[] = R"(while (true) {
   if (namedAttrIt == namedAttrRange.end()) {
     break;
   })";
@@ -1192,7 +1192,7 @@ void OpEmitter::genAttrNameGetters() {
     if (attributes.empty()) {
       method->body() << "  return {};";
     } else {
-      const char *const getAttrName = R"(
+      const char getAttrName[] = R"(
   assert(index < {0} && "invalid attribute index");
   assert(name.getStringRef() == getOperationName() && "invalid operation name");
   assert(name.isRegistered() && "Operation isn't registered, missing a "
@@ -1205,7 +1205,7 @@ void OpEmitter::genAttrNameGetters() {
 
   // Generate the <attr>AttrName methods, that expose the attribute names to
   // users.
-  const char *attrNameMethodBody = "  return getAttributeNameForIndex({0});";
+  const char attrNameMethodBody[] = "  return getAttributeNameForIndex({0});";
   for (auto [index, attr] :
        llvm::enumerate(llvm::make_first_range(attributes))) {
     std::string name = op.getGetterName(attr);
@@ -1373,18 +1373,18 @@ void OpEmitter::genPropertiesSupport() {
     return ::mlir::failure();
   }
     )decl";
-  const char *propFromAttrFmt = R"decl(
+  const char propFromAttrFmt[] = R"decl(
       auto setFromAttr = [] (auto &propStorage, ::mlir::Attribute propAttr,
                ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) -> ::mlir::LogicalResult {{
         {0}
       };
       {2};
 )decl";
-  const char *attrGetNoDefaultFmt = R"decl(;
+  const char attrGetNoDefaultFmt[] = R"decl(;
       if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
         return ::mlir::failure();
 )decl";
-  const char *attrGetDefaultFmt = R"decl(;
+  const char attrGetDefaultFmt[] = R"decl(;
       if (attr) {{
         if (::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
           return ::mlir::failure();
@@ -1471,7 +1471,7 @@ void OpEmitter::genPropertiesSupport() {
 
   getPropMethod << "    ::mlir::SmallVector<::mlir::NamedAttribute> attrs;\n"
                 << "    ::mlir::Builder odsBuilder{ctx};\n";
-  const char *propToAttrFmt = R"decl(
+  const char propToAttrFmt[] = R"decl(
     {
       const auto &propStorage = prop.{0};
       auto attr = [&]() -> ::mlir::Attribute {{
@@ -1514,7 +1514,7 @@ void OpEmitter::genPropertiesSupport() {
 
   // Hashing for the property
 
-  const char *propHashFmt = R"decl(
+  const char propHashFmt[] = R"decl(
   auto hash_{0} = [] (const auto &propStorage) -> llvm::hash_code {
     return {1};
   };
@@ -1555,17 +1555,18 @@ void OpEmitter::genPropertiesSupport() {
       });
   hashMethod << ");\n";
 
-  const char *getInherentAttrMethodFmt = R"decl(
+  const char getInherentAttrMethodFmt[] = R"decl(
     if (name == "{0}")
       return prop.{0};
 )decl";
-  const char *setInherentAttrMethodFmt = R"decl(
+  const char setInherentAttrMethodFmt[] = R"decl(
     if (name == "{0}") {{
-       prop.{0} = ::llvm::dyn_cast_or_null<std::remove_reference_t<decltype(prop.{0})>>(value);
+       prop.{0} = ::llvm::dyn_cast_or_null<
+                        std::remove_reference_t<decltype(prop.{0})>>(value);
        return;
     }
 )decl";
-  const char *populateInherentAttrsMethodFmt = R"decl(
+  const char populateInherentAttrsMethodFmt[] = R"decl(
     if (prop.{0}) attrs.append("{0}", prop.{0});
 )decl";
   for (const auto &attrOrProp : attrOrProperties) {
@@ -1980,7 +1981,7 @@ void OpEmitter::genAttrSetters() {
     // std::optional<>).
     StringRef paramStr = isUnitAttr ? "attrValue" : "*attrValue";
     if (!useProperties) {
-      const char *optionalCodeBody = R"(
+      const char optionalCodeBody[] = R"(
     if (attrValue)
       return (*this)->setAttr({0}AttrName(), {1});
     (*this)->removeAttr({0}AttrName());)";
@@ -1988,7 +1989,7 @@ void OpEmitter::genAttrSetters() {
           optionalCodeBody, getterName,
           constBuildAttrFromParam(baseAttr, fctx, paramStr));
     } else {
-      const char *optionalCodeBody = R"(
+      const char optionalCodeBody[] = R"(
     auto &odsProp = getProperties().{0};
     if (attrValue)
       odsProp = {1};
@@ -2768,11 +2769,10 @@ void OpEmitter::genInferredTypeCollectiveParamBuilder() {
          << "u && \"mismatched number of return types\");";
   body << "\n    " << builderOpState << ".addTypes(inferredReturnTypes);";
 
-  body << formatv(R"(
-  } else {{
+  body << R"(
+  } else {
     ::llvm::report_fatal_error("Failed to infer result type(s).");
-  })",
-                  opClass.getClassName(), builderOpState);
+  })";
 }
 
 void OpEmitter::genUseOperandAsResultTypeSeparateParamBuilder() {
@@ -3502,7 +3502,7 @@ void OpEmitter::genSideEffectInterfaceMethods() {
   // {2}: The side effect stage.
   // {3}: Does this side effect act on every single value of resource.
   // {4}: The resource class.
-  const char *addEffectCode =
+  const char addEffectCode[] =
       "  effects.emplace_back({0}::get(), {1}{2}, {3}, {4}::get());\n";
 
   for (auto &it : interfaceEffects) {
@@ -3745,7 +3745,7 @@ void OpEmitter::genOperandResultVerifier(MethodBody &body,
   //
   // {0}: Value index.
   // {1}: "operand" or "result"
-  const char *const verifyOptional = R"(
+  const char verifyOptional[] = R"(
     if (valueGroup{0}.size() > 1) {
       return emitOpError("{1} group starting at #") << index
           << " requires 0 or 1 element, but found " << valueGroup{0}.size();
@@ -3756,7 +3756,7 @@ void OpEmitter::genOperandResultVerifier(MethodBody &body,
   // {0}: Value index.
   // {1}: Type constraint function.
   // {2}: "operand" or "result"
-  const char *const verifyValues = R"(
+  const char verifyValues[] = R"(
     for (auto v : valueGroup{0}) {
       if (::mlir::failed({1}(*this, v.getType(), "{2}", index++)))
         return ::mlir::failure();
@@ -3819,7 +3819,7 @@ void OpEmitter::genRegionVerifier(MethodBody &body) {
   /// {1}: The region constraint.
   /// {2}: The region's name.
   /// {3}: The region description.
-  const char *const verifyRegion = R"(
+  const char verifyRegion[] = R"(
     for (auto &region : {0})
       if (::mlir::failed({1}(*this, region, "{2}", index++)))
         return ::mlir::failure();
@@ -3827,7 +3827,7 @@ void OpEmitter::genRegionVerifier(MethodBody &body) {
   /// Get a single region.
   ///
   /// {0}: The region's index.
-  const char *const getSingleRegion =
+  const char getSingleRegion[] =
       "::llvm::MutableArrayRef((*this)->getRegion({0}))";
 
   // If we have no regions, there is nothing more to do.
@@ -3855,7 +3855,7 @@ void OpEmitter::genRegionVerifier(MethodBody &body) {
 }
 
 void OpEmitter::genSuccessorVerifier(MethodBody &body) {
-  const char *const verifySuccessor = R"(
+  const char verifySuccessor[] = R"(
     for (auto *successor : {0})
       if (::mlir::failed({1}(*this, successor, "{2}", index++)))
         return ::mlir::failure();
@@ -3863,7 +3863,7 @@ void OpEmitter::genSuccessorVerifier(MethodBody &body) {
   /// Get a single successor.
   ///
   /// {0}: The successor's name.
-  const char *const getSingleSuccessor = "::llvm::MutableArrayRef({0}())";
+  const char getSingleSuccessor[] = "::llvm::MutableArrayRef({0}())";
 
   // If we have no successors, there is nothing more to do.
   const auto canSkip = [](const NamedSuccessor &successor) {
@@ -3881,8 +3881,8 @@ void OpEmitter::genSuccessorVerifier(MethodBody &body) {
       continue;
 
     auto getSuccessor =
-        formatv(successor.isVariadic() ? "{0}()" : getSingleSuccessor,
-                successor.name, it.index())
+        formatvv(successor.isVariadic() ? "{0}()" : getSingleSuccessor,
+                 successor.name, it.index())
             .str();
     auto constraintFn =
         staticVerifierEmitter.getSuccessorConstraintFn(successor.constraint);
@@ -4123,7 +4123,7 @@ OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(
         comparatorOs << "        rhs." << name << " == this->" << name
                      << " &&\n";
         // Emit accessors using the interface type.
-        const char *accessorFmt = R"decl(;
+        const char accessorFmt[] = R"decl(;
     {0} get{1}() const {
       auto &propStorage = this->{2};
       return {3};
@@ -4169,7 +4169,7 @@ OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(
 
       // Emit accessors using the interface type.
       if (attr) {
-        const char *accessorFmt = R"decl(
+        const char accessorFmt[] = R"decl(
     auto get{0}() {
       auto &propStorage = this->{1};
       return ::llvm::{2}<{3}>(propStorage);
@@ -4597,7 +4597,7 @@ static bool emitOpDecls(const RecordKeeper &recordKeeper, raw_ostream &os) {
   Dialect dialect = Operator(defs.front()).getDialect();
   NamespaceEmitter ns(os, dialect);
 
-  const char *const opRegistrationHook =
+  const char opRegistrationHook[] =
       "void register{0}Operations{1}({2}::{0} *dialect);\n";
   os << formatv(opRegistrationHook, dialect.getCppClassName(), "",
                 dialect.getCppNamespace());
@@ -4621,7 +4621,7 @@ static void emitOpDefShard(const RecordKeeper &recordKeeper,
   IfDefScope scope(shardGuard, os);
 
   // Emit the op registration hook in the first shard.
-  const char *const opRegistrationHook =
+  const char opRegistrationHook[] =
       "void {0}::register{1}Operations{2}({0}::{1} *dialect) {{\n";
   if (shardIndex == 0) {
     os << formatv(opRegistrationHook, dialect.getCppNamespace(),
diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
index 9a95f495b77658..a3cd3388ed37a1 100644
--- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
@@ -443,7 +443,7 @@ static bool shouldFormatSymbolNameAttr(const NamedAttribute *attr) {
 ///
 /// {0}: The name of the attribute.
 /// {1}: The type for the attribute.
-const char *const attrParserCode = R"(
+const char attrParserCode[] = R"(
   if (parser.parseCustomAttributeWithFallback({0}Attr, {1})) {{
     return ::mlir::failure();
   }
@@ -453,12 +453,12 @@ const char *const attrParserCode = R"(
 ///
 /// {0}: The name of the attribute.
 /// {1}: The type for the attribute.
-const char *const genericAttrParserCode = R"(
+const char genericAttrParserCode[] = R"(
   if (parser.parseAttribute({0}Attr, {1}))
     return ::mlir::failure();
 )";
 
-const char *const optionalAttrParserCode = R"(
+const char optionalAttrParserCode[] = R"(
   ::mlir::OptionalParseResult parseResult{0}Attr =
     parser.parseOptionalAttribute({0}Attr, {1});
   if (parseResult{0}Attr.has_value() && failed(*parseResult{0}Attr))
@@ -469,11 +469,11 @@ const char *const optionalAttrParserCode = R"(
 /// The code snippet used to generate a parser call for a symbol name attribute.
 ///
 /// {0}: The name of the attribute.
-const char *const symbolNameAttrParserCode = R"(
+const char symbolNameAttrParserCode[] = R"(
   if (parser.parseSymbolName({0}Attr))
     return ::mlir::failure();
 )";
-const char *const optionalSymbolNameAttrParserCode = R"(
+const char optionalSymbolNameAttrParserCode[] = R"(
   // Parsing an optional symbol name doesn't fail, so no need to check the
   // result.
   (void)parser.parseOptionalSymbolName({0}Attr);
@@ -488,7 +488,7 @@ const char *const optionalSymbolNameAttrParserCode = R"(
 /// {4}: The set of allowed enum keywords.
 /// {5}: The error message on failure when the enum isn't present.
 /// {6}: The attribute assignment expression
-const char *const enumAttrParserCode = R"(
+const char enumAttrParserCode[] = R"(
   {
     ::llvm::StringRef attrStr;
     ::mlir::NamedAttrList attrStorage;
@@ -524,7 +524,7 @@ const char *const enumAttrParserCode = R"(
 /// {1}: The C++ class name of the operation
 /// {2}: The property's parser code with appropriate substitutions performed
 /// {3}: The description of the expected property for the error message.
-const char *const propertyParserCode = R"(
+const char propertyParserCode[] = R"(
   auto {0}PropLoc = parser.getCurrentLocation();
   auto {0}PropParseResult = [&](auto& propStorage) -> ::mlir::ParseResult {{
     {2}
@@ -539,7 +539,7 @@ const char *const propertyParserCode = R"(
 /// {0}: The name of the property
 /// {1}: The C++ class name of the operation
 /// {2}: The property's parser code with appropriate substitutions performed
-const char *const optionalPropertyParserCode = R"(
+const char optionalPropertyParserCode[] = R"(
   auto {0}PropParseResult = [&](auto& propStorage) -> ::mlir::OptionalParseResult {{
     {2}
     return ::mlir::success();
@@ -552,12 +552,12 @@ const char *const optionalPropertyParserCode = R"(
 /// The code snippet used to generate a parser call for an operand.
 ///
 /// {0}: The name of the operand.
-const char *const variadicOperandParserCode = R"(
+const char variadicOperandParserCode[] = R"(
   {0}OperandsLoc = parser.getCurrentLocation();
   if (parser.parseOperandList({0}Operands))
     return ::mlir::failure();
 )";
-const char *const optionalOperandParserCode = R"(
+const char optionalOperandParserCode[] = R"(
   {
     {0}OperandsLoc = parser.getCurrentLocation();
     ::mlir::OpAsmParser::UnresolvedOperand operand;
@@ -570,7 +570,7 @@ const char *const optionalOperandParserCode = R"(
     }
   }
 )";
-const char *const operandParserCode = R"(
+const char operandParserCode[] = R"(
   {0}OperandsLoc = parser.getCurrentLocation();
   if (parser.parseOperand({0}RawOperand))
     return ::mlir::failure();
@@ -579,8 +579,7 @@ const char *const operandParserCode = R"(
 /// operand.
 ///
 /// {0}: The name of the operand.
-/// {1}: The name of segment size attribute.
-const char *const variadicOfVariadicOperandParserCode = R"(
+const char variadicOfVariadicOperandParserCode[] = R"(
   {
     {0}OperandsLoc = parser.getCurrentLocation();
     int32_t curSize = 0;
@@ -598,7 +597,7 @@ const char *const variadicOfVariadicOperandParserCode = R"(
 /// The code snippet used to generate a parser call for a type list.
 ///
 /// {0}: The name for the type list.
-const char *const variadicOfVariadicTypeParserCode = R"(
+const char variadicOfVariadicTypeParserCode[] = R"(
   do {
     if (parser.parseOptionalLParen())
       break;
@@ -607,11 +606,11 @@ const char *const variadicOfVariadicTypeParserCode = R"(
       return ::mlir::failure();
   } while (succeeded(parser.parseOptionalComma()));
 )";
-const char *const variadicTypeParserCode = R"(
+const char variadicTypeParserCode[] = R"(
   if (parser.parseTypeList({0}Types))
     return ::mlir::failure();
 )";
-const char *const optionalTypeParserCode = R"(
+const char optionalTypeParserCode[] = R"(
   {
     ::mlir::Type optionalType;
     ::mlir::OptionalParseResult parseResult =
@@ -623,7 +622,7 @@ const char *const optionalTypeParserCode = R"(
     }
   }
 )";
-const char *const typeParserCode = R"(
+const char typeParserCode[] = R"(
   {
     {0} type;
     if (parser.parseCustomTypeWithFallback(type))
@@ -631,7 +630,7 @@ const char *const typeParserCode = R"(
     {1}RawType = type;
   }
 )";
-const char *const qualifiedTypeParserCode = R"(
+const char qualifiedTypeParserCode[] = R"(
   if (parser.parseType({1}RawType))
     return ::mlir::failure();
 )";
@@ -640,7 +639,7 @@ const char *const qualifiedTypeParserCode = R"(
 ///
 /// {0}: The name for the input type list.
 /// {1}: The name for the result type list.
-const char *const functionalTypeParserCode = R"(
+const char functionalTypeParserCode[] = R"(
   ::mlir::FunctionType {0}__{1}_functionType;
   if (parser.parseType({0}__{1}_functionType))
     return ::mlir::failure();
@@ -651,7 +650,7 @@ const char *const functionalTypeParserCode = R"(
 /// The code snippet used to generate a parser call to infer return types.
 ///
 /// {0}: The operation class name
-const char *const inferReturnTypesParserCode = R"(
+const char inferReturnTypesParserCode[] = R"(
   ::llvm::SmallVector<::mlir::Type> inferredReturnTypes;
   if (::mlir::failed({0}::inferReturnTypes(parser.getContext(),
       result.location, result.operands,
@@ -665,7 +664,7 @@ const char *const inferReturnTypesParserCode = R"(
 /// The code snippet used to generate a parser call for a region list.
 ///
 /// {0}: The name for the region list.
-const char *regionListParserCode = R"(
+const char regionListParserCode[] = R"(
   {
     std::unique_ptr<::mlir::Region> region;
     auto firstRegionResult = parser.parseOptionalRegion(region);
@@ -688,7 +687,7 @@ const char *regionListParserCode = R"(
 /// The code snippet used to ensure a list of regions have terminators.
 ///
 /// {0}: The name of the region list.
-const char *regionListEnsureTerminatorParserCode = R"(
+const char regionListEnsureTerminatorParserCode[] = R"(
   for (auto &region : {0}Regions)
     ensureTerminator(*region, parser.getBuilder(), result.location);
 )";
@@ -696,7 +695,7 @@ const char *regionListEnsureTerminatorParserCode = R"(
 /// The code snippet used to ensure a list of regions have a block.
 ///
 /// {0}: The name of the region list.
-const char *regionListEnsureSingleBlockParserCode = R"(
+const char regionListEnsureSingleBlockParserCode[] = R"(
   for (auto &region : {0}Regions)
     if (region->empty()) region->emplaceBlock();
 )";
@@ -704,7 +703,7 @@ const char *regionListEnsureSingleBlockParserCode = R"(
 /// The code snippet used to generate a parser call for an optional region.
 ///
 /// {0}: The name of the region.
-const char *optionalRegionParserCode = R"(
+const char optionalRegionParserCode[] = R"(
   {
      auto parseResult = parser.parseOptionalRegion(*{0}Region);
      if (parseResult.has_value() && failed(*parseResult))
@@ -715,7 +714,7 @@ const char *optionalRegionParserCode = R"(
 /// The code snippet used to generate a parser call for a region.
 ///
 /// {0}: The name of the region.
-const char *regionParserCode = R"(
+const char regionParserCode[] = R"(
   if (parser.parseRegion(*{0}Region))
     return ::mlir::failure();
 )";
@@ -723,21 +722,21 @@ const char *regionParserCode = R"(
 /// The code snippet used to ensure a region has a terminator.
 ///
 /// {0}: The name of the region.
-const char *regionEnsureTerminatorParserCode = R"(
+const char regionEnsureTerminatorParserCode[] = R"(
   ensureTerminator(*{0}Region, parser.getBuilder(), result.location);
 )";
 
 /// The code snippet used to ensure a region has a block.
 ///
 /// {0}: The name of the region.
-const char *regionEnsureSingleBlockParserCode = R"(
+const char regionEnsureSingleBlockParserCode[] = R"(
   if ({0}Region->empty()) {0}Region->emplaceBlock();
 )";
 
 /// The code snippet used to generate a parser call for a successor list.
 ///
 /// {0}: The name for the successor list.
-const char *successorListParserCode = R"(
+const char successorListParserCode[] = R"(
   {
     ::mlir::Block *succ;
     auto firstSucc = parser.parseOptionalSuccessor(succ);
@@ -759,7 +758,7 @@ const char *successorListParserCode = R"(
 /// The code snippet used to generate a parser call for a successor.
 ///
 /// {0}: The name of the successor.
-const char *successorParserCode = R"(
+const char successorParserCode[] = R"(
   if (parser.parseSuccessor({0}Successor))
     return ::mlir::failure();
 )";
@@ -767,7 +766,7 @@ const char *successorParserCode = R"(
 /// The code snippet used to generate a parser for OIList
 ///
 /// {0}: literal keyword corresponding to a case for oilist
-const char *oilistParserCode = R"(
+const char oilistParserCode[] = R"(
   if ({0}Clause) {
     return parser.emitError(parser.getNameLoc())
           << "`{0}` clause can appear at most once in the expansion of the "
@@ -1122,7 +1121,7 @@ static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body,
             "      {0}Operands.append(subRange.begin(), subRange.end());\n"
             "      {0}OperandGroupSizes.push_back(subRange.size());\n"
             "    }\n",
-            var->name, var->constraint.getVariadicOfVariadicSegmentSizeAttr());
+            var->name);
       }
     } else if (auto *dir = dyn_cast<TypeDirective>(param)) {
       ArgumentLengthKind lengthKind;
@@ -1233,9 +1232,9 @@ static void genAttrParser(AttributeVariable *attr, MethodBody &body,
 
   // Check to see if we should parse this as a symbol name attribute.
   if (shouldFormatSymbolNameAttr(var)) {
-    body << formatv(parseAsOptional ? optionalSymbolNameAttrParserCode
-                                    : symbolNameAttrParserCode,
-                    var->name);
+    body << formatvv(parseAsOptional ? optionalSymbolNameAttrParserCode
+                                     : symbolNameAttrParserCode,
+                     var->name);
   } else {
 
     // If this attribute has a buildable type, use that when parsing the
@@ -1299,7 +1298,7 @@ if (!dict) {
   // {0}: fromAttribute call
   // {1}: property name
   // {2}: isRequired
-  const char *propFromAttrFmt = R"decl(
+  const char propFromAttrFmt[] = R"decl(
 auto setFromAttr = [] (auto &propStorage, ::mlir::Attribute propAttr,
          ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) -> ::mlir::LogicalResult {{
   {0};
@@ -1575,9 +1574,7 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
     ArgumentLengthKind lengthKind = getArgumentLengthKind(operand->getVar());
     StringRef name = operand->getVar()->name;
     if (lengthKind == ArgumentLengthKind::VariadicOfVariadic)
-      body << llvm::formatv(
-          variadicOfVariadicOperandParserCode, name,
-          operand->getVar()->constraint.getVariadicOfVariadicSegmentSizeAttr());
+      body << llvm::formatv(variadicOfVariadicOperandParserCode, name);
     else if (lengthKind == ArgumentLengthKind::Variadic)
       body << llvm::formatv(variadicOperandParserCode, name);
     else if (lengthKind == ArgumentLengthKind::Optional)
@@ -1587,21 +1584,21 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
 
   } else if (auto *region = dyn_cast<RegionVariable>(element)) {
     bool isVariadic = region->getVar()->isVariadic();
-    body << llvm::formatv(isVariadic ? regionListParserCode : regionParserCode,
-                          region->getVar()->name);
+    body << llvm::formatvv(isVariadic ? regionListParserCode : regionParserCode,
+                           region->getVar()->name);
     if (hasImplicitTermTrait)
-      body << llvm::formatv(isVariadic ? regionListEnsureTerminatorParserCode
-                                       : regionEnsureTerminatorParserCode,
-                            region->getVar()->name);
+      body << llvm::formatvv(isVariadic ? regionListEnsureTerminatorParserCode
+                                        : regionEnsureTerminatorParserCode,
+                             region->getVar()->name);
     else if (hasSingleBlockTrait)
-      body << llvm::formatv(isVariadic ? regionListEnsureSingleBlockParserCode
-                                       : regionEnsureSingleBlockParserCode,
-                            region->getVar()->name);
+      body << llvm::formatvv(isVariadic ? regionListEnsureSingleBlockParserCode
+                                        : regionEnsureSingleBlockParserCode,
+                             region->getVar()->name);
 
   } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) {
     bool isVariadic = successor->getVar()->isVariadic();
-    body << formatv(isVariadic ? successorListParserCode : successorParserCode,
-                    successor->getVar()->name);
+    body << formatvv(isVariadic ? successorListParserCode : successorParserCode,
+                     successor->getVar()->name);
 
     /// Directives.
   } else if (auto *attrDict = dyn_cast<AttrDictDirective>(element)) {
@@ -1656,12 +1653,12 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
           dir->shouldBeQualified() ? qualifiedTypeParserCode : typeParserCode;
       TypeSwitch<FormatElement *>(dir->getArg())
           .Case<OperandVariable, ResultVariable>([&](auto operand) {
-            body << formatv(parserCode,
-                            operand->getVar()->constraint.getCppType(),
-                            listName);
+            body << formatvv(parserCode,
+                             operand->getVar()->constraint.getCppType(),
+                             listName);
           })
           .Default([&](auto operand) {
-            body << formatv(parserCode, "::mlir::Type", listName);
+            body << formatvv(parserCode, "::mlir::Type", listName);
           });
     }
   } else if (auto *dir = dyn_cast<FunctionalTypeDirective>(element)) {
@@ -1954,7 +1951,7 @@ void OperationFormat::genParserVariadicSegmentResolution(Operator &op,
 // operation that has the SingleBlockImplicitTerminator trait.
 ///
 /// {0}: The name of the region.
-const char *regionSingleBlockImplicitTerminatorPrinterCode = R"(
+const char regionSingleBlockImplicitTerminatorPrinterCode[] = R"(
   {
     bool printTerminator = true;
     if (auto *term = {0}.empty() ? nullptr : {0}.begin()->getTerminator()) {{
@@ -1972,7 +1969,7 @@ const char *regionSingleBlockImplicitTerminatorPrinterCode = R"(
 ///
 /// {0}: The name of the enum attribute.
 /// {1}: The name of the enum attributes symbolToString function.
-const char *enumAttrBeginPrinterCode = R"(
+const char enumAttrBeginPrinterCode[] = R"(
   {
     auto caseValue = {0}();
     auto caseValueStr = {1}(caseValue);
diff --git a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
index 052020acdcb764..2637e2b2dada3d 100644
--- a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
@@ -26,7 +26,7 @@ using namespace mlir::tblgen;
 
 /// File header and includes.
 ///   {0} is the dialect namespace.
-constexpr const char *fileHeader = R"Py(
+constexpr const char fileHeader[] = R"Py(
 # Autogenerated by mlir-tblgen; don't manually edit.
 
 from ._ods_common import _cext as _ods_cext
@@ -47,20 +47,20 @@ from typing import Sequence as _Sequence, Union as _Union
 
 /// Template for dialect class:
 ///   {0} is the dialect namespace.
-constexpr const char *dialectClassTemplate = R"Py(
+constexpr const char dialectClassTemplate[] = R"Py(
 @_ods_cext.register_dialect
 class _Dialect(_ods_ir.Dialect):
   DIALECT_NAMESPACE = "{0}"
 )Py";
 
-constexpr const char *dialectExtensionTemplate = R"Py(
+constexpr const char dialectExtensionTemplate[] = R"Py(
 from ._{0}_ops_gen import _Dialect
 )Py";
 
 /// Template for operation class:
 ///   {0} is the Python class name;
 ///   {1} is the operation name.
-constexpr const char *opClassTemplate = R"Py(
+constexpr const char opClassTemplate[] = R"Py(
 @_ods_cext.register_operation(_Dialect)
 class {0}(_ods_ir.OpView):
   OPERATION_NAME = "{1}"
@@ -75,14 +75,14 @@ class {0}(_ods_ir.OpView):
 ///   1 = single element (expect non sequence operand/result)
 ///   0 = optional element (expect a value or std::nullopt)
 ///   -1 = operand/result is a sequence corresponding to a variadic
-constexpr const char *opClassSizedSegmentsTemplate = R"Py(
+constexpr const char opClassSizedSegmentsTemplate[] = R"Py(
   _ODS_{0}_SEGMENTS = {1}
 )Py";
 
 /// Template for class level declarations of the _ODS_REGIONS spec:
 ///   {0} is the minimum number of regions
 ///   {1} is the Python bool literal for hasNoVariadicRegions
-constexpr const char *opClassRegionSpecTemplate = R"Py(
+constexpr const char opClassRegionSpecTemplate[] = R"Py(
   _ODS_REGIONS = ({0}, {1})
 )Py";
 
@@ -90,7 +90,7 @@ constexpr const char *opClassRegionSpecTemplate = R"Py(
 ///   {0} is the name of the accessor;
 ///   {1} is either 'operand' or 'result';
 ///   {2} is the position in the element list.
-constexpr const char *opSingleTemplate = R"Py(
+constexpr const char opSingleTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     return self.operation.{1}s[{2}]
@@ -103,7 +103,7 @@ constexpr const char *opSingleTemplate = R"Py(
 ///   {3} is the position of the current group in the group list.
 /// This works for both a single variadic group (non-negative length) and an
 /// single optional element (zero length if the element is absent).
-constexpr const char *opSingleAfterVariableTemplate = R"Py(
+constexpr const char opSingleAfterVariableTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     _ods_variadic_group_length = len(self.operation.{1}s) - {2} + 1
@@ -118,7 +118,7 @@ constexpr const char *opSingleAfterVariableTemplate = R"Py(
 /// This works if we have only one variable-length group (and it's the optional
 /// operand/result): we can deduce it's absent if the `len(operation.{1}s)` is
 /// smaller than the total number of groups.
-constexpr const char *opOneOptionalTemplate = R"Py(
+constexpr const char opOneOptionalTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     return None if len(self.operation.{1}s) < {2} else self.operation.{1}s[{3}]
@@ -129,7 +129,7 @@ constexpr const char *opOneOptionalTemplate = R"Py(
 ///   {1} is either 'operand' or 'result';
 ///   {2} is the total number of element groups;
 ///   {3} is the position of the current group in the group list.
-constexpr const char *opOneVariadicTemplate = R"Py(
+constexpr const char opOneVariadicTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     _ods_variadic_group_length = len(self.operation.{1}s) - {2} + 1
@@ -142,7 +142,7 @@ constexpr const char *opOneVariadicTemplate = R"Py(
 ///   {2} is the total number of variadic groups;
 ///   {3} is the number of non-variadic groups preceding the current group;
 ///   {3} is the number of variadic groups preceding the current group.
-constexpr const char *opVariadicEqualPrefixTemplate = R"Py(
+constexpr const char opVariadicEqualPrefixTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     start, pg = _ods_equally_sized_accessor(operation.{1}s, {2}, {3}, {4}))Py";
@@ -150,14 +150,14 @@ constexpr const char *opVariadicEqualPrefixTemplate = R"Py(
 /// Second part of the template for equally-sized case, accessing a single
 /// element:
 ///   {0} is either 'operand' or 'result'.
-constexpr const char *opVariadicEqualSimpleTemplate = R"Py(
+constexpr const char opVariadicEqualSimpleTemplate[] = R"Py(
     return self.operation.{0}s[start]
 )Py";
 
 /// Second part of the template for equally-sized case, accessing a variadic
 /// group:
 ///   {0} is either 'operand' or 'result'.
-constexpr const char *opVariadicEqualVariadicTemplate = R"Py(
+constexpr const char opVariadicEqualVariadicTemplate[] = R"Py(
     return self.operation.{0}s[start:start + pg]
 )Py";
 
@@ -167,7 +167,7 @@ constexpr const char *opVariadicEqualVariadicTemplate = R"Py(
 ///   {2} is the position of the group in the group list;
 ///   {3} is a return suffix (expected [0] for single-element, empty for
 ///       variadic, and opVariadicSegmentOptionalTrailingTemplate for optional).
-constexpr const char *opVariadicSegmentTemplate = R"Py(
+constexpr const char opVariadicSegmentTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     {1}_range = _ods_segmented_accessor(
@@ -179,13 +179,13 @@ constexpr const char *opVariadicSegmentTemplate = R"Py(
 /// Template for a suffix when accessing an optional element in the
 /// attribute-sized case:
 ///   {0} is either 'operand' or 'result';
-constexpr const char *opVariadicSegmentOptionalTrailingTemplate =
+constexpr const char opVariadicSegmentOptionalTrailingTemplate[] =
     R"Py([0] if len({0}_range) > 0 else None)Py";
 
 /// Template for an operation attribute getter:
 ///   {0} is the name of the attribute sanitized for Python;
 ///   {1} is the original name of the attribute.
-constexpr const char *attributeGetterTemplate = R"Py(
+constexpr const char attributeGetterTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     return self.operation.attributes["{1}"]
@@ -194,7 +194,7 @@ constexpr const char *attributeGetterTemplate = R"Py(
 /// Template for an optional operation attribute getter:
 ///   {0} is the name of the attribute sanitized for Python;
 ///   {1} is the original name of the attribute.
-constexpr const char *optionalAttributeGetterTemplate = R"Py(
+constexpr const char optionalAttributeGetterTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     if "{1}" not in self.operation.attributes:
@@ -207,7 +207,7 @@ constexpr const char *optionalAttributeGetterTemplate = R"Py(
 /// by mere presence):
 ///    {0} is the name of the attribute sanitized for Python,
 ///    {1} is the original name of the attribute.
-constexpr const char *unitAttributeGetterTemplate = R"Py(
+constexpr const char unitAttributeGetterTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     return "{1}" in self.operation.attributes
@@ -216,7 +216,7 @@ constexpr const char *unitAttributeGetterTemplate = R"Py(
 /// Template for an operation attribute setter:
 ///    {0} is the name of the attribute sanitized for Python;
 ///    {1} is the original name of the attribute.
-constexpr const char *attributeSetterTemplate = R"Py(
+constexpr const char attributeSetterTemplate[] = R"Py(
   @{0}.setter
   def {0}(self, value):
     if value is None:
@@ -228,7 +228,7 @@ constexpr const char *attributeSetterTemplate = R"Py(
 /// removes the attribute:
 ///    {0} is the name of the attribute sanitized for Python;
 ///    {1} is the original name of the attribute.
-constexpr const char *optionalAttributeSetterTemplate = R"Py(
+constexpr const char optionalAttributeSetterTemplate[] = R"Py(
   @{0}.setter
   def {0}(self, value):
     if value is not None:
@@ -241,7 +241,7 @@ constexpr const char *optionalAttributeSetterTemplate = R"Py(
 /// False removes the attribute:
 ///    {0} is the name of the attribute sanitized for Python;
 ///    {1} is the original name of the attribute.
-constexpr const char *unitAttributeSetterTemplate = R"Py(
+constexpr const char unitAttributeSetterTemplate[] = R"Py(
   @{0}.setter
   def {0}(self, value):
     if bool(value):
@@ -254,19 +254,19 @@ constexpr const char *unitAttributeSetterTemplate = R"Py(
 /// the attribute from the operation:
 ///    {0} is the name of the attribute sanitized for Python;
 ///    {1} is the original name of the attribute.
-constexpr const char *attributeDeleterTemplate = R"Py(
+constexpr const char attributeDeleterTemplate[] = R"Py(
   @{0}.deleter
   def {0}(self):
     del self.operation.attributes["{1}"]
 )Py";
 
-constexpr const char *regionAccessorTemplate = R"Py(
+constexpr const char regionAccessorTemplate[] = R"Py(
   @builtins.property
   def {0}(self):
     return self.regions[{1}]
 )Py";
 
-constexpr const char *valueBuilderTemplate = R"Py(
+constexpr const char valueBuilderTemplate[] = R"Py(
 def {0}({2}) -> {4}:
   return _get_op_result_or_op_results({1}({3}))
 )Py";
@@ -353,10 +353,10 @@ static void emitElementAccessors(
       if (element.name.empty())
         continue;
       if (element.isVariableLength()) {
-        os << llvm::formatv(element.isOptional() ? opOneOptionalTemplate
-                                                 : opOneVariadicTemplate,
-                            sanitizeName(element.name), kind,
-                            getNumElements(op), i);
+        os << llvm::formatvv(element.isOptional() ? opOneOptionalTemplate
+                                                  : opOneVariadicTemplate,
+                             sanitizeName(element.name), kind,
+                             getNumElements(op), i);
       } else if (seenVariableLength) {
         os << llvm::formatv(opSingleAfterVariableTemplate,
                             sanitizeName(element.name), kind,
@@ -379,10 +379,10 @@ static void emitElementAccessors(
         os << llvm::formatv(opVariadicEqualPrefixTemplate,
                             sanitizeName(element.name), kind, numVariableLength,
                             numPrecedingSimple, numPrecedingVariadic);
-        os << llvm::formatv(element.isVariableLength()
-                                ? opVariadicEqualVariadicTemplate
-                                : opVariadicEqualSimpleTemplate,
-                            kind);
+        os << llvm::formatvv(element.isVariableLength()
+                                 ? opVariadicEqualVariadicTemplate
+                                 : opVariadicEqualSimpleTemplate,
+                             kind);
       }
       if (element.isVariableLength())
         ++numPrecedingVariadic;
@@ -489,7 +489,7 @@ static void emitAttributeAccessors(const Operator &op, raw_ostream &os) {
 ///       `loc` and `ip`;
 ///   {1} is the code populating `operands`, `results` and `attributes`,
 ///       `successors` fields.
-constexpr const char *initTemplate = R"Py(
+constexpr const char initTemplate[] = R"Py(
   def __init__(self, {0}):
     operands = []
     results = []
@@ -501,27 +501,27 @@ constexpr const char *initTemplate = R"Py(
 
 /// Template for appending a single element to the operand/result list.
 ///   {0} is the field name.
-constexpr const char *singleOperandAppendTemplate =
+constexpr const char singleOperandAppendTemplate[] =
     "operands.append(_get_op_result_or_value({0}))";
 constexpr const char *singleResultAppendTemplate = "results.append({0})";
 
 /// Template for appending an optional element to the operand/result list.
 ///   {0} is the field name.
-constexpr const char *optionalAppendOperandTemplate =
+constexpr const char optionalAppendOperandTemplate[] =
     "if {0} is not None: operands.append(_get_op_result_or_value({0}))";
-constexpr const char *optionalAppendAttrSizedOperandsTemplate =
+constexpr const char optionalAppendAttrSizedOperandsTemplate[] =
     "operands.append(_get_op_result_or_value({0}) if {0} is not None else "
     "None)";
-constexpr const char *optionalAppendResultTemplate =
+constexpr const char optionalAppendResultTemplate[] =
     "if {0} is not None: results.append({0})";
 
 /// Template for appending a list of elements to the operand/result list.
 ///   {0} is the field name.
-constexpr const char *multiOperandAppendTemplate =
+constexpr const char multiOperandAppendTemplate[] =
     "operands.extend(_get_op_results_or_values({0}))";
-constexpr const char *multiOperandAppendPackTemplate =
+constexpr const char multiOperandAppendPackTemplate[] =
     "operands.append(_get_op_results_or_values({0}))";
-constexpr const char *multiResultAppendTemplate = "results.extend({0})";
+constexpr const char multiResultAppendTemplate[] = "results.extend({0})";
 
 /// Template for attribute builder from raw input in the operation builder.
 ///   {0} is the builder argument name;
@@ -529,7 +529,7 @@ constexpr const char *multiResultAppendTemplate = "results.extend({0})";
 ///   {2} is the attribute builder from raw.
 /// Use the value the user passed in if either it is already an Attribute or
 /// there is no method registered to make it an Attribute.
-constexpr const char *initAttributeWithBuilderTemplate =
+constexpr const char initAttributeWithBuilderTemplate[] =
     R"Py(attributes["{1}"] = ({0} if (
     isinstance({0}, _ods_ir.Attribute) or
     not _ods_ir.AttrBuilder.contains('{2}')) else
@@ -542,25 +542,25 @@ constexpr const char *initAttributeWithBuilderTemplate =
 ///   {2} is the attribute builder from raw.
 /// Use the value the user passed in if either it is already an Attribute or
 /// there is no method registered to make it an Attribute.
-constexpr const char *initOptionalAttributeWithBuilderTemplate =
+constexpr const char initOptionalAttributeWithBuilderTemplate[] =
     R"Py(if {0} is not None: attributes["{1}"] = ({0} if (
         isinstance({0}, _ods_ir.Attribute) or
         not _ods_ir.AttrBuilder.contains('{2}')) else
           _ods_ir.AttrBuilder.get('{2}')({0}, context=_ods_context)))Py";
 
-constexpr const char *initUnitAttributeTemplate =
+constexpr const char initUnitAttributeTemplate[] =
     R"Py(if bool({1}): attributes["{0}"] = _ods_ir.UnitAttr.get(
       _ods_get_default_loc_context(loc)))Py";
 
 /// Template to initialize the successors list in the builder if there are any
 /// successors.
 ///   {0} is the value to initialize the successors list to.
-constexpr const char *initSuccessorsTemplate = R"Py(_ods_successors = {0})Py";
+constexpr const char initSuccessorsTemplate[] = R"Py(_ods_successors = {0})Py";
 
 /// Template to append or extend the list of successors in the builder.
 ///   {0} is the list method ('append' or 'extend');
 ///   {1} is the value to add.
-constexpr const char *addSuccessorTemplate = R"Py(_ods_successors.{0}({1}))Py";
+constexpr const char addSuccessorTemplate[] = R"Py(_ods_successors.{0}({1}))Py";
 
 /// Returns true if the SameArgumentAndResultTypes trait can be used to infer
 /// result types of the given operation.
@@ -674,7 +674,7 @@ populateBuilderLinesAttr(const Operator &op,
       continue;
     }
 
-    builderLines.push_back(llvm::formatv(
+    builderLines.push_back(llvm::formatvv(
         attribute->attr.isOptional() || attribute->attr.hasDefaultValue()
             ? initOptionalAttributeWithBuilderTemplate
             : initAttributeWithBuilderTemplate,
@@ -737,14 +737,14 @@ populateBuilderLinesOperand(const Operator &op,
       }
     }
 
-    builderLines.push_back(llvm::formatv(formatString.data(), name));
+    builderLines.push_back(llvm::formatvv(formatString.data(), name));
   }
 }
 
 /// Python code template for deriving the operation result types from its
 /// attribute:
 ///   - {0} is the name of the attribute from which to derive the types.
-constexpr const char *deriveTypeFromAttrTemplate =
+constexpr const char deriveTypeFromAttrTemplate[] =
     R"Py(_ods_result_type_source_attr = attributes["{0}"]
 _ods_derived_result_type = (
     _ods_ir.TypeAttr(_ods_result_type_source_attr).value
@@ -752,7 +752,8 @@ _ods_derived_result_type = (
     _ods_result_type_source_attr.type))Py";
 
 /// Python code template appending {0} type {1} times to the results list.
-constexpr const char *appendSameResultsTemplate = "results.extend([{0}] * {1})";
+constexpr const char appendSameResultsTemplate[] =
+    "results.extend([{0}] * {1})";
 
 /// Appends the given multiline string as individual strings into
 /// `builderLines`.
@@ -818,7 +819,7 @@ populateBuilderLinesResult(const Operator &op,
       }
     }
 
-    builderLines.push_back(llvm::formatv(formatString.data(), name));
+    builderLines.push_back(llvm::formatvv(formatString.data(), name));
   }
 }
 
diff --git a/mlir/tools/mlir-tblgen/PassCAPIGen.cpp b/mlir/tools/mlir-tblgen/PassCAPIGen.cpp
index 9f33a4129aacca..d7bbb1f759903b 100644
--- a/mlir/tools/mlir-tblgen/PassCAPIGen.cpp
+++ b/mlir/tools/mlir-tblgen/PassCAPIGen.cpp
@@ -30,14 +30,14 @@ static llvm::cl::opt<std::string>
                              "prefix can avoid conflicts across libraries."),
               llvm::cl::cat(passGenCat));
 
-const char *const passDecl = R"(
+const char passDecl[] = R"(
 /* Create {0} Pass. */
 MLIR_CAPI_EXPORTED MlirPass mlirCreate{0}{1}(void);
 MLIR_CAPI_EXPORTED void mlirRegister{0}{1}(void);
 
 )";
 
-const char *const fileHeader = R"(
+const char fileHeader[] = R"(
 /* Autogenerated by mlir-tblgen; don't manually edit. */
 
 #include "mlir-c/Pass.h"
@@ -48,7 +48,7 @@ extern "C" {
 
 )";
 
-const char *const fileFooter = R"(
+const char fileFooter[] = R"(
 
 #ifdef __cplusplus
 }
@@ -70,7 +70,7 @@ static bool emitCAPIHeader(const llvm::RecordKeeper &records, raw_ostream &os) {
   return false;
 }
 
-const char *const passCreateDef = R"(
+const char passCreateDef[] = R"(
 MlirPass mlirCreate{0}{1}(void) {
   return wrap({2}.release());
 }
@@ -81,7 +81,7 @@ void mlirRegister{0}{1}(void) {
 )";
 
 /// {0}: The name of the pass group.
-const char *const passGroupRegistrationCode = R"(
+const char passGroupRegistrationCode[] = R"(
 //===----------------------------------------------------------------------===//
 // {0} Group Registration
 //===----------------------------------------------------------------------===//
diff --git a/mlir/tools/mlir-tblgen/PassGen.cpp b/mlir/tools/mlir-tblgen/PassGen.cpp
index 90aa67115a4007..da128bf050a356 100644
--- a/mlir/tools/mlir-tblgen/PassGen.cpp
+++ b/mlir/tools/mlir-tblgen/PassGen.cpp
@@ -37,7 +37,7 @@ static std::vector<Pass> getPasses(const llvm::RecordKeeper &recordKeeper) {
   return passes;
 }
 
-const char *const passHeader = R"(
+const char passHeader[] = R"(
 //===----------------------------------------------------------------------===//
 // {0}
 //===----------------------------------------------------------------------===//
@@ -51,7 +51,7 @@ const char *const passHeader = R"(
 ///
 /// {0}: The def name of the pass record.
 /// {1}: The pass constructor call.
-const char *const passRegistrationCode = R"(
+const char passRegistrationCode[] = R"(
 //===----------------------------------------------------------------------===//
 // {0} Registration
 //===----------------------------------------------------------------------===//
@@ -74,7 +74,7 @@ inline void register{0}Pass() {{
 /// group.
 ///
 /// {0}: The name of the pass group.
-const char *const passGroupRegistrationCode = R"(
+const char passGroupRegistrationCode[] = R"(
 //===----------------------------------------------------------------------===//
 // {0} Registration
 //===----------------------------------------------------------------------===//
@@ -175,7 +175,7 @@ static void emitRegistrations(llvm::ArrayRef<Pass> passes, raw_ostream &os) {
 /// {2): The command line argument for the pass.
 /// {3}: The summary for the pass.
 /// {4}: The dependent dialects registration.
-const char *const baseClassBegin = R"(
+const char baseClassBegin[] = R"(
 template <typename DerivedT>
 class {0}Base : public {1} {
 public:
@@ -226,39 +226,39 @@ class {0}Base : public {1} {
 
 /// Registration for a single dependent dialect, to be inserted for each
 /// dependent dialect in the `getDependentDialects` above.
-const char *const dialectRegistrationTemplate = "registry.insert<{0}>();";
+const char dialectRegistrationTemplate[] = "registry.insert<{0}>();";
 
-const char *const friendDefaultConstructorDeclTemplate = R"(
+const char friendDefaultConstructorDeclTemplate[] = R"(
 namespace impl {{
   std::unique_ptr<::mlir::Pass> create{0}();
 } // namespace impl
 )";
 
-const char *const friendDefaultConstructorWithOptionsDeclTemplate = R"(
+const char friendDefaultConstructorWithOptionsDeclTemplate[] = R"(
 namespace impl {{
   std::unique_ptr<::mlir::Pass> create{0}(const {0}Options &options);
 } // namespace impl
 )";
 
-const char *const friendDefaultConstructorDefTemplate = R"(
+const char friendDefaultConstructorDefTemplate[] = R"(
   friend std::unique_ptr<::mlir::Pass> create{0}() {{
     return std::make_unique<DerivedT>();
   }
 )";
 
-const char *const friendDefaultConstructorWithOptionsDefTemplate = R"(
+const char friendDefaultConstructorWithOptionsDefTemplate[] = R"(
   friend std::unique_ptr<::mlir::Pass> create{0}(const {0}Options &options) {{
     return std::make_unique<DerivedT>(options);
   }
 )";
 
-const char *const defaultConstructorDefTemplate = R"(
+const char defaultConstructorDefTemplate[] = R"(
 std::unique_ptr<::mlir::Pass> create{0}() {{
   return impl::create{0}();
 }
 )";
 
-const char *const defaultConstructorWithOptionsDefTemplate = R"(
+const char defaultConstructorWithOptionsDefTemplate[] = R"(
 std::unique_ptr<::mlir::Pass> create{0}(const {0}Options &options) {{
   return impl::create{0}(options);
 }
@@ -376,7 +376,7 @@ static void emitPass(const Pass &pass, raw_ostream &os) {
 // TODO: Drop old pass declarations.
 // The old pass base class is being kept until all the passes have switched to
 // the new decls/defs design.
-const char *const oldPassDeclBegin = R"(
+const char oldPassDeclBegin[] = R"(
 template <typename DerivedT>
 class {0}Base : public {1} {
 public:
diff --git a/mlir/tools/mlir-tblgen/RewriterGen.cpp b/mlir/tools/mlir-tblgen/RewriterGen.cpp
index 2c79ba2cd6353e..5ea6cd93910b3f 100644
--- a/mlir/tools/mlir-tblgen/RewriterGen.cpp
+++ b/mlir/tools/mlir-tblgen/RewriterGen.cpp
@@ -1797,7 +1797,7 @@ void PatternEmitter::createAggregateLocalVarsForOpArgs(
   os << formatv("::llvm::SmallVector<::mlir::NamedAttribute, 4> "
                 "tblgen_attrs; (void)tblgen_attrs;\n");
 
-  const char *addAttrCmd =
+  const char addAttrCmd[] =
       "if (auto tmpAttr = {1}) {\n"
       "  tblgen_attrs.emplace_back(rewriter.getStringAttr(\"{0}\"), "
       "tmpAttr);\n}\n";
@@ -1876,7 +1876,7 @@ void PatternEmitter::createAggregateLocalVarsForOpArgs(
     const auto *sameVariadicSize =
         resultOp.getTrait("::mlir::OpTrait::SameVariadicOperandSize");
     if (!sameVariadicSize) {
-      const char *setSizes = R"(
+      const char setSizes[] = R"(
         tblgen_attrs.emplace_back(rewriter.getStringAttr("operandSegmentSizes"),
           rewriter.getDenseI32ArrayAttr({{ {0} }));
           )";



More information about the Mlir-commits mailing list