[libcxx-commits] [libcxx] Formatting Ranges: Range "m" specifier do not pass through to underlying element (PR #70616)

Yihe Li via libcxx-commits libcxx-commits at lists.llvm.org
Sun Oct 29 22:49:18 PDT 2023


https://github.com/Mick235711 updated https://github.com/llvm/llvm-project/pull/70616

>From d590a6533652e50669accb2260b70ab25788270b Mon Sep 17 00:00:00 2001
From: Yihe Li <winmikedows at hotmail.com>
Date: Mon, 30 Oct 2023 12:19:51 +0800
Subject: [PATCH 1/2] Fix m specifier for range formatting: call
 set_bracket/separator on underlying too

---
 libcxx/include/__format/range_formatter.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h
index d13278009fcf897..25d0f5697c49c7f 100644
--- a/libcxx/include/__format/range_formatter.h
+++ b/libcxx/include/__format/range_formatter.h
@@ -216,6 +216,8 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
       if constexpr (__fmt_pair_like<_Tp>) {
         set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
         set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", "));
+        __underlying_.set_brackets({}, {});
+        __underlying_.set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
         ++__begin;
       } else
         std::__throw_format_error("Type m requires a pair or a tuple with two elements");

>From 5bdf2c2c7961881ece04a1b943d3331c566f2ec4 Mon Sep 17 00:00:00 2001
From: Yihe Li <winmikedows at hotmail.com>
Date: Mon, 30 Oct 2023 13:49:03 +0800
Subject: [PATCH 2/2] Additional bugfix: only add m specifier when there is no
 underlying spec & change test suite

---
 libcxx/include/__format/range_formatter.h        | 16 ++++++++++++----
 .../format.functions.tests.h                     |  4 ++--
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h
index 25d0f5697c49c7f..d58742332d09074 100644
--- a/libcxx/include/__format/range_formatter.h
+++ b/libcxx/include/__format/range_formatter.h
@@ -65,7 +65,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
 
     // The n field overrides a possible m type, therefore delay applying the
     // effect of n until the type has been procesed.
-    __parse_type(__begin, __end);
+    bool __has_m_specifier = __parse_type(__begin, __end);
     if (__parser_.__clear_brackets_)
       set_brackets({}, {});
     if (__begin == __end) [[unlikely]]
@@ -87,6 +87,14 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
     __ctx.advance_to(__begin);
     __begin = __underlying_.parse(__ctx);
 
+    // Add "m" specifier semantics if there are no underlying specifier
+    if (!__has_range_underlying_spec && __has_m_specifier) {
+        if constexpr (__fmt_pair_like<_Tp>) { // should always be true
+            __underlying_.set_brackets({}, {});
+            __underlying_.set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
+        }
+    }
+
     // This test should not be required if __has_range_underlying_spec is false.
     // However this test makes sure the underlying formatter left the parser in
     // a valid state. (Note this is not a full protection against evil parsers.
@@ -210,15 +218,14 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
 
 private:
   template <contiguous_iterator _Iterator>
-  _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin, _Iterator __end) {
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_type(_Iterator& __begin, _Iterator __end) {
     switch (*__begin) {
     case _CharT('m'):
       if constexpr (__fmt_pair_like<_Tp>) {
         set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
         set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", "));
-        __underlying_.set_brackets({}, {});
-        __underlying_.set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
         ++__begin;
+        return true;
       } else
         std::__throw_format_error("Type m requires a pair or a tuple with two elements");
       break;
@@ -241,6 +248,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
       } else
         std::__throw_format_error("Type ?s requires character type as formatting argument");
     }
+    return false;
   }
 
   template <class _ParseContext>
diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h b/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
index 1e6c75cc69fe449..2417efe4afe3d76 100644
--- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
+++ b/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
@@ -983,10 +983,10 @@ void test_pair_tuple(TestFunction check, ExceptionTest check_exception, auto&& i
 
   // *** n
   check(SV("__(1, 'a'), (42, '*')___"), SV("{:_^24n}"), input);
-  check(SV("__(1, 'a'), (42, '*')___"), SV("{:_^24nm}"), input); // m should have no effect
+  check(SV("____1: 'a', 42: '*'_____"), SV("{:_^24nm}"), input);
 
   // *** type ***
-  check(SV("__{(1, 'a'), (42, '*')}___"), SV("{:_^26m}"), input);
+  check(SV("____{1: 'a', 42: '*'}_____"), SV("{:_^26m}"), input);
   check_exception("Type s requires character type as formatting argument", SV("{:s}"), input);
   check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), input);
   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s"))



More information about the libcxx-commits mailing list