[llvm] [Support] formatv: non-negative-plus for integral numbers (PR #185008)

Konrad Kleine via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 11 08:24:12 PDT 2026


https://github.com/kwk updated https://github.com/llvm/llvm-project/pull/185008

>From c856bc8724f95bfd0e8e3dc5abb1c0e735a0a480 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Mon, 9 Feb 2026 10:56:42 +0000
Subject: [PATCH 1/8] [Support] formatv: non-neative-plus for integral numbers

The older `format()` allows you to print a `+` sign for non-negative
integral numbers upon request.

Examples:

```c++
format("%+d", 255); // -> "+255"
format("%+d", -12); // -> "-12"
```

This change adds the ability to do the same with `formatv()`:

```c++
formatv("{0:+d}", 255); // -> "+255"
formatv("{0:+d}", -12); // -> "-12"
```

The default behaviour is not changed. That means, for a format specifier
like "{0:d}" we still print the positive integer without a "+" prefix.

The special case of "+0" is exactly like it is handled with `format()`:

```c++
format("%+d", 0); // -> "+0"
```

This work is related to #35980.
---
 llvm/include/llvm/Support/FormatProviders.h   | 15 +++++-
 llvm/include/llvm/Support/NativeFormatting.h  | 13 ++---
 llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp  |  3 +-
 .../DWARF/DWARFExpressionPrinter.cpp          |  9 ++--
 llvm/lib/Support/NativeFormatting.cpp         | 43 ++++++++-------
 llvm/unittests/Support/FormatVariadicTest.cpp | 53 +++++++++++++++++--
 6 files changed, 100 insertions(+), 36 deletions(-)

diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h
index 3377781873b8c..64b9347214447 100644
--- a/llvm/include/llvm/Support/FormatProviders.h
+++ b/llvm/include/llvm/Support/FormatProviders.h
@@ -112,6 +112,8 @@ class HelperFunctions {
 ///   | X+ / X  | Hex + prefix, upper  |   42   |   0x2A  | Minimum # digits   |
 ///   | N / n   | Digit grouped number | 123456 | 123,456 | Ignored            |
 ///   | D / d   | Integer              | 100000 | 100000  | Ignored            |
+///   |+D /+d   | Integer w/ + for >=0 | 100000 | +100000 | Ignored            |
+///   |   +     | Same as +D / +d      |        |         |                    |
 ///   | (empty) | Same as D / d        |        |         |                    |
 ///   ==========================================================================
 ///
@@ -130,6 +132,10 @@ struct format_provider<
       return;
     }
 
+    // A + prefix indicates that a plus sign shall be
+    // prefixed to non-negativ numbers
+    bool NonNegativePlus = Style.consume_front('+');
+
     IntegerStyle IS = IntegerStyle::Integer;
     if (Style.consume_front("N") || Style.consume_front("n"))
       IS = IntegerStyle::Number;
@@ -138,7 +144,11 @@ struct format_provider<
 
     Style.consumeInteger(10, Digits);
     assert(Style.empty() && "Invalid integral format style!");
-    write_integer(Stream, V, Digits, IS);
+
+    // We currently only support the + for integer style numbers.
+    NonNegativePlus = NonNegativePlus && IS == IntegerStyle::Integer;
+
+    write_integer(Stream, V, Digits, IS, NonNegativePlus);
   }
 };
 
@@ -248,7 +258,7 @@ struct format_provider<
 ///   ==================================
 ///   |    Y    |       YES / NO       |
 ///   |    y    |       yes / no       |
-///   |  D / d  |    Integer 0 or 1    |
+///   |  D /  d |    Integer 0 or 1    |
 ///   |    T    |     TRUE / FALSE     |
 ///   |    t    |     true / false     |
 ///   | (empty) |   Equivalent to 't'  |
@@ -295,6 +305,7 @@ struct format_provider<
     : public support::detail::HelperFunctions {
   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
     FloatStyle S;
+
     if (Style.consume_front("P") || Style.consume_front("p"))
       S = FloatStyle::Percent;
     else if (Style.consume_front("F") || Style.consume_front("f"))
diff --git a/llvm/include/llvm/Support/NativeFormatting.h b/llvm/include/llvm/Support/NativeFormatting.h
index 45336511ae9b7..ae9134b5e154d 100644
--- a/llvm/include/llvm/Support/NativeFormatting.h
+++ b/llvm/include/llvm/Support/NativeFormatting.h
@@ -27,17 +27,18 @@ LLVM_ABI size_t getDefaultPrecision(FloatStyle Style);
 LLVM_ABI bool isPrefixedHexStyle(HexPrintStyle S);
 
 LLVM_ABI void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
-                            IntegerStyle Style);
+                            IntegerStyle Style, bool NonNegativePlus = false);
 LLVM_ABI void write_integer(raw_ostream &S, int N, size_t MinDigits,
-                            IntegerStyle Style);
+                            IntegerStyle Style, bool NonNegativePlus = false);
 LLVM_ABI void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
-                            IntegerStyle Style);
+                            IntegerStyle Style, bool NonNegativePlus = false);
 LLVM_ABI void write_integer(raw_ostream &S, long N, size_t MinDigits,
-                            IntegerStyle Style);
+                            IntegerStyle Style, bool NonNegativePlus = false);
 LLVM_ABI void write_integer(raw_ostream &S, unsigned long long N,
-                            size_t MinDigits, IntegerStyle Style);
+                            size_t MinDigits, IntegerStyle Style,
+                            bool NonNegativePlus = false);
 LLVM_ABI void write_integer(raw_ostream &S, long long N, size_t MinDigits,
-                            IntegerStyle Style);
+                            IntegerStyle Style, bool NonNegativePlus = false);
 
 LLVM_ABI void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
                         std::optional<size_t> Width = std::nullopt);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp
index 4d879b69c387d..0b74f352b4bb1 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cinttypes>
@@ -64,7 +65,7 @@ static void printOperand(raw_ostream &OS, const DIDumpOptions &DumpOpts,
     // The offsets are all encoded in a unsigned form, but in practice
     // consumers use them signed. It's most certainly legacy due to
     // the lack of signed variants in the first Dwarf standards.
-    OS << format(" %+" PRId64, int64_t(Operand));
+    OS << formatv(" {0:+d}", int64_t(Operand));
     break;
   case CFIProgram::OT_FactoredCodeOffset: // Always Unsigned
     if (P.codeAlign())
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
index fcd2316c30aef..5a3c1dd057193 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
@@ -11,6 +11,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
 #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
 #include <cassert>
 #include <cstdint>
 
@@ -153,7 +154,7 @@ static bool printOp(const DWARFExpression::Operation *Op, raw_ostream &OS,
                        static_cast<uint8_t>(Expr->getData()[Offset++]));
       } else {
         if (Signed)
-          OS << format(" %+" PRId64, (int64_t)Op->getRawOperand(Operand));
+          OS << formatv(" {0:+d}", (int64_t)Op->getRawOperand(Operand));
         else if (Op->getCode() != DW_OP_entry_value &&
                  Op->getCode() != DW_OP_GNU_entry_value)
           OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));
@@ -257,7 +258,7 @@ static bool printCompactDWARFExpr(
       raw_svector_ostream S(Stack.emplace_back().String);
       S << RegName;
       if (Offset)
-        S << format("%+" PRId64, Offset);
+        S << formatv("{0:+d}", Offset);
       break;
     }
     case dwarf::DW_OP_entry_value:
@@ -310,7 +311,7 @@ static bool printCompactDWARFExpr(
         raw_svector_ostream S(Stack.emplace_back().String);
         S << RegName;
         if (Offset)
-          S << format("%+" PRId64, Offset);
+          S << formatv("{0:+d}", Offset);
       } else {
         return UnknownOpcode(OS, Opcode, std::nullopt);
       }
@@ -364,7 +365,7 @@ bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
   if (!RegName.empty()) {
     if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
         Opcode == DW_OP_bregx || SubOpcode == DW_OP_LLVM_aspace_bregx)
-      OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]);
+      OS << ' ' << RegName << formatv("{0:+d}", int64_t(Operands[OpNum]));
     else
       OS << ' ' << RegName.data();
 
diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp
index 7a64730434193..d3bb5db4c6728 100644
--- a/llvm/lib/Support/NativeFormatting.cpp
+++ b/llvm/lib/Support/NativeFormatting.cpp
@@ -53,7 +53,8 @@ static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
 
 template <typename T>
 static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
-                                IntegerStyle Style, bool IsNegative) {
+                                IntegerStyle Style, bool IsNegative,
+                                bool NonNegativePlus) {
   static_assert(std::is_unsigned_v<T>, "Value is not unsigned!");
 
   char NumberBuffer[128];
@@ -61,6 +62,8 @@ static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
 
   if (IsNegative)
     S << '-';
+  else if (NonNegativePlus)
+    S << '+';
 
   if (Len < MinDigits && Style != IntegerStyle::Number) {
     for (size_t I = Len; I < MinDigits; ++I)
@@ -76,59 +79,61 @@ static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
 
 template <typename T>
 static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
-                           IntegerStyle Style, bool IsNegative = false) {
+                           IntegerStyle Style, bool IsNegative = false,
+                           bool NonNegativePlus = false) {
   // Output using 32-bit div/mod if possible.
   if (N == static_cast<uint32_t>(N))
     write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
-                        IsNegative);
+                        IsNegative, NonNegativePlus);
   else
-    write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
+    write_unsigned_impl(S, N, MinDigits, Style, IsNegative, NonNegativePlus);
 }
 
 template <typename T>
 static void write_signed(raw_ostream &S, T N, size_t MinDigits,
-                         IntegerStyle Style) {
+                         IntegerStyle Style, bool NonNegativePlus = false) {
   static_assert(std::is_signed_v<T>, "Value is not signed!");
 
   using UnsignedT = std::make_unsigned_t<T>;
 
   if (N >= 0) {
-    write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
+    write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style, false,
+                   NonNegativePlus);
     return;
   }
 
   UnsignedT UN = -(UnsignedT)N;
-  write_unsigned(S, UN, MinDigits, Style, true);
+  write_unsigned(S, UN, MinDigits, Style, true, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_unsigned(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_unsigned(S, N, MinDigits, Style, false, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_signed(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_signed(S, N, MinDigits, Style, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_unsigned(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_unsigned(S, N, MinDigits, Style, false, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_signed(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_signed(S, N, MinDigits, Style, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_unsigned(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NoneNegativePlus) {
+  write_unsigned(S, N, MinDigits, Style, false, NoneNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
-                         IntegerStyle Style) {
-  write_signed(S, N, MinDigits, Style);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_signed(S, N, MinDigits, Style, NonNegativePlus);
 }
 
 void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index a3e9841536fdc..71a8881ef54e2 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -391,7 +391,7 @@ TEST(FormatVariadicTest, IntegralHexFormatting) {
 }
 
 template <typename FormatTy>
-std::string printToString(unsigned MaxN, FormatTy &&Fmt) {
+static std::string printToString(FormatTy &&Fmt, unsigned MaxN = 100) {
   std::vector<char> Dst(MaxN + 2);
   int N = Fmt.snprint(Dst.data(), Dst.size());
   Dst.back() = 0;
@@ -402,18 +402,63 @@ TEST(FormatAndFormatvTest, EquivalentHexFormatting) {
   uint8_t HexDigits = 10;
   uint64_t N = 255;
 
+  // with format()
+  // -------------
   // Here's the old format() way of printing a hex number with
   // dynamic width and precision, both being the same.
-  EXPECT_EQ(
-      "0x00000000ff",
-      printToString(100, format("0x%*.*" PRIx64, HexDigits, HexDigits, N)));
+  EXPECT_EQ("0x00000000ff",
+            printToString(format("0x%*.*" PRIx64, HexDigits, HexDigits, N)));
 
+  // with formatv()
+  // --------------
   // Now, do the same with formatv()
   EXPECT_EQ("0x00000000ff",
             formatv("0x{0:x-}", fmt_align(N, AlignStyle::Right, HexDigits, '0'))
                 .str());
 }
 
+TEST(FormatAndFormatvTest, NonNegativePlusInteger) {
+  // with format()
+  // -------------
+  EXPECT_EQ("-255", printToString(format("%+d", -255)));
+  EXPECT_EQ("+255", printToString(format("%+d", 255)));
+  EXPECT_EQ("+0", printToString(format("%+d", 0)));
+  EXPECT_EQ("-7", printToString(format("%+d", -7)));
+
+  // with formatv()
+  // --------------
+  // Check that +d works for signed and unsigned integral values.
+  // Ensure the default is not changes (a + is not added without requesting it).
+  EXPECT_EQ("+1", formatv("{0:+d}", static_cast<unsigned int>(1)).str());
+  EXPECT_EQ("+2", formatv("{0:+d}", static_cast<int>(2)).str());
+  EXPECT_EQ("+3", formatv("{0:+d}", static_cast<unsigned long>(3)).str());
+  EXPECT_EQ("+4", formatv("{0:+d}", static_cast<long>(4)).str());
+  EXPECT_EQ("+5", formatv("{0:+d}", static_cast<unsigned long long>(5)).str());
+  EXPECT_EQ("+6", formatv("{0:+d}", static_cast<long long>(6)).str());
+  EXPECT_EQ("-7", formatv("{0:+d}", static_cast<int>(-7)).str());
+  EXPECT_EQ("-8", formatv("{0:+d}", static_cast<long>(-8)).str());
+  EXPECT_EQ("-9", formatv("{0:+d}", static_cast<long long>(-9)).str());
+
+  EXPECT_EQ("11", formatv("{0:d}", static_cast<unsigned int>(11)).str());
+  EXPECT_EQ("22", formatv("{0:d}", static_cast<int>(22)).str());
+  EXPECT_EQ("33", formatv("{0:d}", static_cast<unsigned long>(33)).str());
+  EXPECT_EQ("44", formatv("{0:d}", static_cast<long>(44)).str());
+  EXPECT_EQ("55", formatv("{0:d}", static_cast<unsigned long long>(55)).str());
+  EXPECT_EQ("66", formatv("{0:d}", static_cast<long long>(66)).str());
+  EXPECT_EQ("-77", formatv("{0:d}", static_cast<int>(-77)).str());
+  EXPECT_EQ("-88", formatv("{0:d}", static_cast<long>(-88)).str());
+  EXPECT_EQ("-99", formatv("{0:d}", static_cast<long long>(-99)).str());
+
+  // Ensure that 0 is also prefixed with + (old behaviour from format(), see
+  // above).
+  EXPECT_EQ("+0", formatv("{0:+d}", 0).str());
+  EXPECT_EQ("0", formatv("{0:d}", 0).str());
+
+  // Ensure that an empty or otherwise empty format string is also working as
+  // expected
+  EXPECT_EQ("+333", formatv("{0:+}", 333).str());
+  EXPECT_EQ("444", formatv("{0:}", 444).str());
+}
 TEST(FormatVariadicTest, PointerFormatting) {
   // 1. Trivial cases.  Hex is default.  Default Precision is pointer width.
   if (sizeof(void *) == 4) {

>From 9beaf151de9dd4849458fa7f2d31fbadc12ff731 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 12:33:13 +0000
Subject: [PATCH 2/8] typo: negativ -> negative and full stop

---
 llvm/include/llvm/Support/FormatProviders.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h
index 64b9347214447..38d273b311b49 100644
--- a/llvm/include/llvm/Support/FormatProviders.h
+++ b/llvm/include/llvm/Support/FormatProviders.h
@@ -133,7 +133,7 @@ struct format_provider<
     }
 
     // A + prefix indicates that a plus sign shall be
-    // prefixed to non-negativ numbers
+    // prefixed to non-negative numbers.
     bool NonNegativePlus = Style.consume_front('+');
 
     IntegerStyle IS = IntegerStyle::Integer;

>From 297b954b47cc1f2ef276f83057746b9fd226abc1 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 14:54:43 +0000
Subject: [PATCH 3/8] Fix left-over space

---
 llvm/include/llvm/Support/FormatProviders.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h
index 38d273b311b49..238c04a4fd16b 100644
--- a/llvm/include/llvm/Support/FormatProviders.h
+++ b/llvm/include/llvm/Support/FormatProviders.h
@@ -258,7 +258,7 @@ struct format_provider<
 ///   ==================================
 ///   |    Y    |       YES / NO       |
 ///   |    y    |       yes / no       |
-///   |  D /  d |    Integer 0 or 1    |
+///   |  D / d  |    Integer 0 or 1    |
 ///   |    T    |     TRUE / FALSE     |
 ///   |    t    |     true / false     |
 ///   | (empty) |   Equivalent to 't'  |

>From 2a1a2a9f21d7dab2715c9b109a3781543a4b1e7b Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 14:55:46 +0000
Subject: [PATCH 4/8] Remove header comments

---
 llvm/unittests/Support/FormatVariadicTest.cpp | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index 71a8881ef54e2..590c425b4ff0d 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -402,15 +402,11 @@ TEST(FormatAndFormatvTest, EquivalentHexFormatting) {
   uint8_t HexDigits = 10;
   uint64_t N = 255;
 
-  // with format()
-  // -------------
   // Here's the old format() way of printing a hex number with
   // dynamic width and precision, both being the same.
   EXPECT_EQ("0x00000000ff",
             printToString(format("0x%*.*" PRIx64, HexDigits, HexDigits, N)));
 
-  // with formatv()
-  // --------------
   // Now, do the same with formatv()
   EXPECT_EQ("0x00000000ff",
             formatv("0x{0:x-}", fmt_align(N, AlignStyle::Right, HexDigits, '0'))
@@ -418,15 +414,11 @@ TEST(FormatAndFormatvTest, EquivalentHexFormatting) {
 }
 
 TEST(FormatAndFormatvTest, NonNegativePlusInteger) {
-  // with format()
-  // -------------
   EXPECT_EQ("-255", printToString(format("%+d", -255)));
   EXPECT_EQ("+255", printToString(format("%+d", 255)));
   EXPECT_EQ("+0", printToString(format("%+d", 0)));
   EXPECT_EQ("-7", printToString(format("%+d", -7)));
 
-  // with formatv()
-  // --------------
   // Check that +d works for signed and unsigned integral values.
   // Ensure the default is not changes (a + is not added without requesting it).
   EXPECT_EQ("+1", formatv("{0:+d}", static_cast<unsigned int>(1)).str());

>From 1e8d30e554ef57595ae5d994171ba3f2d751d875 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 14:57:00 +0000
Subject: [PATCH 5/8] typo: changes -> changed

---
 llvm/unittests/Support/FormatVariadicTest.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index 590c425b4ff0d..be80654e52b20 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -420,7 +420,7 @@ TEST(FormatAndFormatvTest, NonNegativePlusInteger) {
   EXPECT_EQ("-7", printToString(format("%+d", -7)));
 
   // Check that +d works for signed and unsigned integral values.
-  // Ensure the default is not changes (a + is not added without requesting it).
+  // Ensure the default is not changed (a + is not added without requesting it).
   EXPECT_EQ("+1", formatv("{0:+d}", static_cast<unsigned int>(1)).str());
   EXPECT_EQ("+2", formatv("{0:+d}", static_cast<int>(2)).str());
   EXPECT_EQ("+3", formatv("{0:+d}", static_cast<unsigned long>(3)).str());

>From a8bada1ba52e4525522ceb440bee22d476f385e9 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 15:10:30 +0000
Subject: [PATCH 6/8] Try with width modifier

---
 llvm/unittests/Support/FormatVariadicTest.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/unittests/Support/FormatVariadicTest.cpp b/llvm/unittests/Support/FormatVariadicTest.cpp
index be80654e52b20..914b5f022e251 100644
--- a/llvm/unittests/Support/FormatVariadicTest.cpp
+++ b/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -450,6 +450,11 @@ TEST(FormatAndFormatvTest, NonNegativePlusInteger) {
   // expected
   EXPECT_EQ("+333", formatv("{0:+}", 333).str());
   EXPECT_EQ("444", formatv("{0:}", 444).str());
+
+  // Try with width modifier as well, to ensure that the + is still present and
+  // that the width is correct.
+  EXPECT_EQ("  -1", formatv("{0,4:+d}", -1).str());
+  EXPECT_EQ("  +1", formatv("{0,4:+d}", 1).str());
 }
 TEST(FormatVariadicTest, PointerFormatting) {
   // 1. Trivial cases.  Hex is default.  Default Precision is pointer width.

>From f415820a56d0c8f54f76fe24dbf900cd691ddb46 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 15:11:54 +0000
Subject: [PATCH 7/8] typo: NoneNegativePlus -> NonNegativePlus

---
 llvm/lib/Support/NativeFormatting.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp
index d3bb5db4c6728..97e6a681480f0 100644
--- a/llvm/lib/Support/NativeFormatting.cpp
+++ b/llvm/lib/Support/NativeFormatting.cpp
@@ -127,8 +127,8 @@ void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
 }
 
 void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
-                         IntegerStyle Style, bool NoneNegativePlus) {
-  write_unsigned(S, N, MinDigits, Style, false, NoneNegativePlus);
+                         IntegerStyle Style, bool NonNegativePlus) {
+  write_unsigned(S, N, MinDigits, Style, false, NonNegativePlus);
 }
 
 void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,

>From 17ba2b16060c42b26775cb503a6db1e86d1e3c56 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Wed, 11 Mar 2026 15:23:17 +0000
Subject: [PATCH 8/8] Fix table

---
 llvm/include/llvm/Support/FormatProviders.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h
index 238c04a4fd16b..9fb1a04007582 100644
--- a/llvm/include/llvm/Support/FormatProviders.h
+++ b/llvm/include/llvm/Support/FormatProviders.h
@@ -112,7 +112,8 @@ class HelperFunctions {
 ///   | X+ / X  | Hex + prefix, upper  |   42   |   0x2A  | Minimum # digits   |
 ///   | N / n   | Digit grouped number | 123456 | 123,456 | Ignored            |
 ///   | D / d   | Integer              | 100000 | 100000  | Ignored            |
-///   |+D /+d   | Integer w/ + for >=0 | 100000 | +100000 | Ignored            |
+///   |+D / +d  | Integer with + prefix| 100000 | +100000 | Ignored            |
+///   |         | for numbers => 0     |        |         |                    |
 ///   |   +     | Same as +D / +d      |        |         |                    |
 ///   | (empty) | Same as D / d        |        |         |                    |
 ///   ==========================================================================



More information about the llvm-commits mailing list