[gcc r16-1184] libstdc++: Fix std::format thousands separators when sign present [PR120548]

Jonathan Wakely redi@gcc.gnu.org
Thu Jun 5 13:44:31 GMT 2025


https://gcc.gnu.org/g:2c3559839d70df6311da18fd93237050405580c3

commit r16-1184-g2c3559839d70df6311da18fd93237050405580c3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 4 18:22:28 2025 +0100

    libstdc++: Fix std::format thousands separators when sign present [PR120548]
    
    The leading sign character should be skipped when deciding whether to
    insert thousands separators into a floating-point format.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/120548
            * include/std/format (__formatter_fp::_M_localize): Do not
            include a leading sign character in the string to be grouped.
            * testsuite/std/format/functions/format.cc: Check grouping when
            sign is present in the output.
    
    Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>

Diff:
---
 libstdc++-v3/include/std/format                       | 11 +++++++++--
 libstdc++-v3/testsuite/std/format/functions/format.cc | 10 ++++++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index b4929d5ae59f..ec76ab0682e0 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -2398,9 +2398,16 @@ namespace __format
 	const size_t __r = __str.size() - __e; // Length of remainder.
 	auto __overwrite = [&](_CharT* __p, size_t) {
 	  // Apply grouping to the digits before the radix or exponent.
-	  auto __end = std::__add_grouping(__p, __np.thousands_sep(),
+	  int __off = 0;
+	  if (auto __c = __str.front(); __c == '-' || __c == '+' || __c == ' ')
+	    {
+	      *__p = __c;
+	      __off = 1;
+	    }
+	  auto __end = std::__add_grouping(__p + __off, __np.thousands_sep(),
 					   __grp.data(), __grp.size(),
-					   __str.data(), __str.data() + __e);
+					   __str.data() + __off,
+					   __str.data() + __e);
 	  if (__r) // If there's a fractional part or exponent
 	    {
 	      if (__d != __str.npos)
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index e4adf3aeb706..d342114083e3 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -261,6 +261,16 @@ test_locale()
   s = std::format(eloc, "{0:Le} {0:Lf} {0:Lg}", -nan);
   VERIFY( s == "-nan -nan -nan" );
 
+  // PR libstdc++/120548 format confuses a negative sign for a thousands digit
+  s = std::format(bloc, "{:L}", -123.45);
+  VERIFY( s == "-123.45" );
+  s = std::format(bloc, "{:-L}", -876543.21);
+  VERIFY( s == "-876,543.21" );
+  s = std::format(bloc, "{:+L}", 333.22);
+  VERIFY( s == "+333.22" );
+  s = std::format(bloc, "{: L}", 999.44);
+  VERIFY( s == " 999.44" );
+
   // Restore
   std::locale::global(cloc);
 }


More information about the Libstdc++-cvs mailing list