On Tue, May 13, 2025 at 10:04 PM Jonathan Wakely <jwak...@redhat.com> wrote:

> On 30/04/25 13:23 +0200, Tomasz Kamiński wrote:
> >This commits adjust the way how the arguments are stored in the _Arg_value
> >(and thus basic_format_args), by preserving the types of fixed width
> >floating-point types, that were previously converted to float, double,
> >long double.
> >
> >The _Arg_value union now contains alternatives with std::bfloat16_t,
> >std::float16_t, std::float32_t, std::float64_t that use pre-existing
> >_Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f32 argument types.
> >
> >This does not affect formatting, as specialization of formatters for
>
> This sentence seems to be missing one or more words?
> Was it supposed to be "as specialization of formatters for floating
> point types formats them by ..." ?
>
> >formats them by casting to the corresponding standard floating point
> >type.
> >
> >For the 128bit floating we need to handle the ppc64 architecture,
> >(_GLIBCXX_LONG_DOUBLE_ALT128_COMPAT) for which the long double may (per TU
> >basis) designate either __ibm128 and __ieee128 type, we need to store both
> >types in the _Arg_value and have two _Arg_types (_Arg_ibm128,
> _Arg_ieee128).
> >On other architectures we use extra enumerator value to store __float128,
> >that is different from long double and _Float128. This is consistent with
> ppc64,
> >for which __float128 is same type as __ieee128 if present. We use
> _Arg_float128
> >_M_float128 names that deviate from _Arg_fN naming scheme, to emphasize
> that
> >this flag is not used for std::float128_t (_Float128_t) type, that is
> consistenly
>
> The internal name for the type is _Float128 not _Float128_t (which
> reinforces that it would be useful to clearly distinguish __float128_t
> and __float128 :-)
>
> >formatted via handle.
> >
> >The __format::_float128_t type is renamed to __format::__flt128_t, to
> mitigate
>
> This should be a double underscore for __float128_t not _float128_t.
>
> >visual confusion between this type and __float128. We also introduce
> __bflt16_t
> >typedef instead of using of decltype.
> >
> >We add new alternative for the _Arg_value and allow them to be accessed
> via _S_get,
> >when the types are available. However, we produce and handle
> corresponding _Arg_type,
> >only when we can format them. See also r14-3329-g27d0cfcb2b33de.
> >
> >The formatter<_Float128, _CharT> that formats via __flt128_t is always
> >provided, when type is available. It is still correct __flt128_t is
> _Float128_t.
>
> s/_Float128_t/_Float128/ here as well
>
> >We also provide formatter<__float128, _CharT> that formats via __flt128_t.
> >As this type may be disabled (-mno-float128), extra care needs to be
> taken,
> >for situation when __float128 is same as long double. If the formatter
> would be
> >defined in such case, the formatter<long double, charT> would be
> generated from
> >different specializations, and have different mangling:
> >  * formatter<__float128, _CharT> if __float128 is present,
> >  * formatter<_format::__formattable_float, _CharT> otherwise.
>
> s/_format/__format/
>
> >To best of my knowledge this happens only on ppc64 for __ieee128 and
> __float128,
> >so the formatter is not defined in this case. static_assert is added to
> detect
> >other configurations like that. In such case we should replace it with
> constraint.
> >
> >       PR libstdc++/119246
> >
> >libstdc++-v3/ChangeLog:
> >
> >       * include/std/format (__format::__bflt16_t): Define.
> >       (_GLIBCXX_FORMAT_F128): Separate value for cases where _Float128
> is used.
> >       (__format::__float128_t): Renamed to __format::_flt128_t.
>
> s/_flt128_t/__flt128_t/
>
> >       (std::formatter<_Float128, _CharT>): Define always if there is
> formattable
>
> This line looks too long for the Changelog format, which should be
> kept below 80 columns (and ideally below 75). Please break the line
> before "formattable" and check the other long lines in this ChangeLog
> part.
>
> >       128bit float.
> >       (std::formatter<__float128, _CharT>): Define.
> >       (_Arg_type::_Arg_f128): Rename to _Arg_float128 and adjust value.
> >       (_Arg_type::_Arg_ibm128): Change value to _Arg_ldbl.
> >       (_Arg_type::_Arg_ieee128): Define as alias to _Arg_float128.
> >       (_Arg_value::_M_f128): Replaced with _M_ieee128 and _M_float128.
> >       (_Arg_value::_M_ieee128, _Arg_value::_M_float128,
> _Arg_value::_M_bf16)
> >       (_Arg_value::_M_f16, _Arg_value::_M_f32, _Arg_value::_M_f64):
> Define.
> >       (_Arg_value::_S_get, basic_format_arg::_S_to_enum): Handle
> __bflt16,
> >       _Float16, _Float32, _Float64, and __float128 types.
> >       (basic_format_arg::_S_to_arg_type): Preserve _bflt16, _Float16,
> >       _Float32, _Float64 and __float128 types.
> >       (basic_format_arg::_M_visit): Hadndle _Arg_float128, _Arg_ieee128,
>
> s/Hadndle/Handle/
>
> >       _Arg_b16, _Arg_f16, _Arg_f32, _Arg_f64.
> >       * testsuite/std/format/arguments/args.cc: Updated to illustrate
> that
> >       extended floating point types use handles now. Added test for
> __float128.
> >       * testsuite/std/format/parse_ctx.cc: Extended test to cover class
> to
> >       check_dynamic_spec with floating point types and handles.
> >---
> >Tested on x86_64-linux and powerpc64le-unknown-linux-gnu.
> >Running additional test on powerpc64le with
> >unix\{-mabi=ibmlongdouble,-mabi=ieeelongdouble,-mno-float128}.
> >
> >OK for trunk?
>
> The code and tests look good, just a few spelling and grammar
> clarifications needed, as noted above and two more below ...
>
> > libstdc++-v3/include/std/format               | 217 ++++++++++++------
> > .../testsuite/std/format/arguments/args.cc    |  45 ++--
> > .../testsuite/std/format/parse_ctx.cc         |  72 +++++-
> > 3 files changed, 227 insertions(+), 107 deletions(-)
> >
> >diff --git a/libstdc++-v3/include/std/format
> b/libstdc++-v3/include/std/format
> >index 054ce350440..73819f52f50 100644
> >--- a/libstdc++-v3/include/std/format
> >+++ b/libstdc++-v3/include/std/format
> >@@ -1863,20 +1863,24 @@ namespace __format
> >       _Spec<_CharT> _M_spec{};
> >     };
> >
> >+#ifdef __BFLT16_DIG__
> >+   using __bflt16_t = decltype(0.0bf16);
> >+#endif
> >+
> >   // Decide how 128-bit floating-point types should be formatted (or
> not).
> >-  // When supported, the typedef __format::__float128_t is the type that
> >-  // format arguments should be converted to for storage in
> basic_format_arg.
> >+  // When supported, the typedef __format::__flt128_t is the type that
> >+  // format arguments should be converted before formatting code.
>
> I'm not sure what "before formatting code" refers to here.
>
> Maybe "should be converted to before being processed by the formatting
> code"?
>
> Or just "should be converted to before formatting"?
>
We do this conversion inside the formatter for _Float128, so we are already
in the middle of formatting.
I will go for "should be converted to before passing to
__formatter_fp::format".


> >   // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
> >-  // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be
> formatted
> >-  // by converting them to long double (or __ieee128 for powerpc64le).
> >-  // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable
> explicit
> >-  // support for _Float128, rather than formatting it as another type.
> >+  // The __float128, _Float128 will be formatted by converting them to:
> >+  // __ieee128 (same as __float128) _GLIBCXX_FORMAT_F128=1,
>
> Should there be "if" before _GLIBCXX_FORMAT_F128=1 ?
>
> I think it would be slightly better to say "when" rather than "if"
> here, i.e.
>
>    // The __float128, _Float128 will be formatted by converting them to:
>    // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1,
>    // long double when _GLIBCXX_FORMAT_F128=2,
>    // _Float128 when _GLIBCXX_FORMAT_F128=3.
>
> >+  // long double if _GLIBCXX_FORMAT_F128=2,
> >+  // _Float128 if _GLIBCXX_FORMAT_F128=3.
> > #undef _GLIBCXX_FORMAT_F128
> >
> > #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> >
> >   // Format 128-bit floating-point types using __ieee128.
> >-  using __float128_t = __ieee128;
> >+  using __flt128_t = __ieee128;
> > # define _GLIBCXX_FORMAT_F128 1
> >
> > #ifdef __LONG_DOUBLE_IEEE128__
> >@@ -1910,14 +1914,14 @@ namespace __format
> > #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
> >
> >   // Format 128-bit floating-point types using long double.
> >-  using __float128_t = long double;
> >-# define _GLIBCXX_FORMAT_F128 1
> >+  using __flt128_t = long double;
> >+# define _GLIBCXX_FORMAT_F128 2
> >
> > #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
> >
> >   // Format 128-bit floating-point types using _Float128.
> >-  using __float128_t = _Float128;
> >-# define _GLIBCXX_FORMAT_F128 2
> >+  using __flt128_t = _Float128;
> >+# define _GLIBCXX_FORMAT_F128 3
> >
> > # if __cplusplus == 202002L
> >   // These overloads exist in the library, but are not declared for
> C++20.
> >@@ -2947,8 +2951,8 @@ namespace __format
> >     };
> > #endif
> >
> >-#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1
> >-  // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128.
> >+#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128
> >+  // Use __formatter_fp<C>::format<__format::flt128_t, Out> for
> _Float128.
> >   template<__format::__char _CharT>
> >     struct formatter<_Float128, _CharT>
> >     {
> >@@ -2962,17 +2966,45 @@ namespace __format
> >       template<typename _Out>
> >       typename basic_format_context<_Out, _CharT>::iterator
> >       format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc)
> const
> >-      { return _M_f.format((__format::__float128_t)__u, __fc); }
> >+      { return _M_f.format((__format::__flt128_t)__u, __fc); }
> >+
> >+    private:
> >+      __format::__formatter_fp<_CharT> _M_f;
> >+    };
> >+#endif
> >+
> >+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 != 1
> >+  // Reuse __formatter_fp<C>::format<__format::_flt128_t, Out> for
> __float128.
>
> s/_flt128_t/__flt128_t/
>
> >+  // This formatter is not declared if
> _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT is true,
> >+  // as __float128 when present is same type as __ieee128, which may be
> same as
> >+  // long double.
> >+  template<__format::__char _CharT>
> >+    struct formatter<__float128, _CharT>
> >+    {
> >+      formatter() = default;
> >+
> >+      [[__gnu__::__always_inline__]]
> >+      constexpr typename basic_format_parse_context<_CharT>::iterator
> >+      parse(basic_format_parse_context<_CharT>& __pc)
> >+      { return _M_f.parse(__pc); }
> >+
> >+      template<typename _Out>
> >+      typename basic_format_context<_Out, _CharT>::iterator
> >+      format(__float128 __u, basic_format_context<_Out, _CharT>& __fc)
> const
> >+      { return _M_f.format((__format::__flt128_t)__u, __fc); }
> >
> >     private:
> >       __format::__formatter_fp<_CharT> _M_f;
> >+
> >+      static_assert( !is_same_v<__float128, long double>,
> >+                   "This specialization should not be used for long
> double" );
> >     };
> > #endif
> >
> > #if defined(__STDCPP_BFLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >   // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
> >   template<__format::__char _CharT>
> >-    struct formatter<__gnu_cxx::__bfloat16_t, _CharT>
> >+    struct formatter<__format::__bflt16_t, _CharT>
> >     {
> >       formatter() = default;
> >
> >@@ -3795,16 +3827,14 @@ namespace __format
> >   enum _Arg_t : unsigned char {
> >     _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
> >     _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr,
> _Arg_handle,
> >-    _Arg_i128, _Arg_u128,
> >-    _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
> >+    _Arg_i128, _Arg_u128, _Arg_float128,
> >+    _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64,
> >+    _Arg_max_,
> >+
> > #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> >-    _Arg_next_value_,
> >-    _Arg_f128 = _Arg_ldbl,
> >-    _Arg_ibm128 = _Arg_next_value_,
> >-#else
> >-    _Arg_f128,
> >+    _Arg_ibm128 = _Arg_ldbl,
> >+    _Arg_ieee128 = _Arg_float128,
> > #endif
> >-    _Arg_max_
> >   };
> >
> >   template<typename _Context>
> >@@ -3831,6 +3861,12 @@ namespace __format
> >       double _M_dbl;
> > #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's
> ambiguous.
> >       long double _M_ldbl;
> >+#else
> >+      __ibm128  _M_ibm128;
> >+      __ieee128 _M_ieee128;
> >+#endif
> >+#ifdef __SIZEOF_FLOAT128__
> >+      __float128 _M_float128;
> > #endif
> >       const _CharT* _M_str;
> >       basic_string_view<_CharT> _M_sv;
> >@@ -3840,11 +3876,17 @@ namespace __format
> >       __int128 _M_i128;
> >       unsigned __int128 _M_u128;
> > #endif
> >-#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> >-      __ieee128 _M_f128;
> >-      __ibm128  _M_ibm128;
> >-#elif _GLIBCXX_FORMAT_F128 == 2
> >-      __float128_t _M_f128;
> >+#ifdef __BFLT16_DIG__
> >+      __bflt16_t _M_bf16;
> >+#endif
> >+#ifdef __FLT16_DIG__
> >+      _Float16 _M_f16;
> >+#endif
> >+#ifdef __FLT32_DIG__
> >+      _Float32 _M_f32;
> >+#endif
> >+#ifdef __FLT64_DIG__
> >+      _Float64 _M_f64;
> > #endif
> >       };
> >
> >@@ -3882,10 +3924,14 @@ namespace __format
> >         else if constexpr (is_same_v<_Tp, long double>)
> >           return __u._M_ldbl;
> > #else
> >-        else if constexpr (is_same_v<_Tp, __ieee128>)
> >-          return __u._M_f128;
> >         else if constexpr (is_same_v<_Tp, __ibm128>)
> >           return __u._M_ibm128;
> >+        else if constexpr (is_same_v<_Tp, __ieee128>)
> >+          return __u._M_ieee128;
> >+#endif
> >+#ifdef __SIZEOF_FLOAT128__
> >+        else if constexpr (is_same_v<_Tp, __float128>)
> >+          return __u._M_float128;
> > #endif
> >         else if constexpr (is_same_v<_Tp, const _CharT*>)
> >           return __u._M_str;
> >@@ -3899,9 +3945,21 @@ namespace __format
> >         else if constexpr (is_same_v<_Tp, unsigned __int128>)
> >           return __u._M_u128;
> > #endif
> >-#if _GLIBCXX_FORMAT_F128 == 2
> >-        else if constexpr (is_same_v<_Tp, __float128_t>)
> >-          return __u._M_f128;
> >+#ifdef __BFLT16_DIG__
> >+        else if constexpr (is_same_v<_Tp, __bflt16_t>)
> >+          return __u._M_bf16;
> >+#endif
> >+#ifdef __FLT16_DIG__
> >+        else if constexpr (is_same_v<_Tp, _Float16>)
> >+          return __u._M_f16;
> >+#endif
> >+#ifdef __FLT32_DIG__
> >+        else if constexpr (is_same_v<_Tp, _Float32>)
> >+          return __u._M_f32;
> >+#endif
> >+#ifdef __FLT64_DIG__
> >+        else if constexpr (is_same_v<_Tp, _Float64>)
> >+          return __u._M_f64;
> > #endif
> >         else if constexpr (derived_from<_Tp, _HandleBase>)
> >           return static_cast<_Tp&>(__u._M_handle);
> >@@ -4080,36 +4138,25 @@ namespace __format
> >         else if constexpr (is_same_v<_Td, __ieee128>)
> >           return type_identity<__ieee128>();
> > #endif
> >-
> >-#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >-        else if constexpr (is_same_v<_Td, _Float16>)
> >-          return type_identity<float>();
> >+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
> >+        else if constexpr (is_same_v<_Td, __float128>)
> >+          return type_identity<__float128>();
> > #endif
> >-
> >-#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >-        else if constexpr (is_same_v<_Td, decltype(0.0bf16)>)
> >-          return type_identity<float>();
> >+#if defined(__STDCPP_BFLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+        else if constexpr (is_same_v<_Td, __format::__bflt16_t>)
> >+          return type_identity<__format::__bflt16_t>();
> >+#endif
> >+#if defined(__STDCPP_FLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+        else if constexpr (is_same_v<_Td, _Float16>)
> >+          return type_identity<_Float16>();
> > #endif
> >-
> > #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >         else if constexpr (is_same_v<_Td, _Float32>)
> >-          return type_identity<float>();
> >+          return type_identity<_Float32>();
> > #endif
> >-
> > #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
> >         else if constexpr (is_same_v<_Td, _Float64>)
> >-          return type_identity<double>();
> >-#endif
> >-
> >-#if _GLIBCXX_FORMAT_F128
> >-# if __FLT128_DIG__
> >-        else if constexpr (is_same_v<_Td, _Float128>)
> >-          return type_identity<__format::__float128_t>();
> >-# endif
> >-# if __SIZEOF_FLOAT128__
> >-        else if constexpr (is_same_v<_Td, __float128>)
> >-          return type_identity<__format::__float128_t>();
> >-# endif
> >+          return type_identity<_Float64>();
> > #endif
> >         else if constexpr (__is_specialization_of<_Td, basic_string_view>
> >                           || __is_specialization_of<_Td, basic_string>)
> >@@ -4165,7 +4212,27 @@ namespace __format
> >         else if constexpr (is_same_v<_Tp, __ibm128>)
> >           return _Arg_ibm128;
> >         else if constexpr (is_same_v<_Tp, __ieee128>)
> >-          return _Arg_f128;
> >+          return _Arg_ieee128;
> >+#endif
> >+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
> >+        else if constexpr (is_same_v<_Tp, __float128>)
> >+          return _Arg_float128;
> >+#endif
> >+#if defined(__STDCPP_BFLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+        else if constexpr (is_same_v<_Tp, __format::__bflt16_t>)
> >+          return _Arg_bf16;
> >+#endif
> >+#if defined(__STDCPP_FLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+        else if constexpr (is_same_v<_Tp, _Float16>)
> >+          return _Arg_f16;
> >+#endif
> >+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+        else if constexpr (is_same_v<_Tp, _Float32>)
> >+          return _Arg_f32;
> >+#endif
> >+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
> >+        else if constexpr (is_same_v<_Tp, _Float64>)
> >+          return _Arg_f64;
> > #endif
> >         else if constexpr (is_same_v<_Tp, const _CharT*>)
> >           return _Arg_str;
> >@@ -4179,11 +4246,6 @@ namespace __format
> >         else if constexpr (is_same_v<_Tp, unsigned __int128>)
> >           return _Arg_u128;
> > #endif
> >-
> >-#if _GLIBCXX_FORMAT_F128 == 2
> >-        else if constexpr (is_same_v<_Tp, __format::__float128_t>)
> >-          return _Arg_f128;
> >-#endif
> >         else if constexpr (is_same_v<_Tp, handle>)
> >           return _Arg_handle;
> >       }
> >@@ -4256,13 +4318,33 @@ namespace __format
> > #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> >           case _Arg_ldbl:
> >             return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
> >+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
> >+          case _Arg_float128:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_float128);
> >+#endif
> > #else
> >-          case _Arg_f128:
> >-            return std::forward<_Visitor>(__vis)(_M_val._M_f128);
> >           case _Arg_ibm128:
> >             return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
> >+          case _Arg_ieee128:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_ieee128);
> > #endif
> >+#if defined(__STDCPP_BFLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+          case _Arg_bf16:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_bf16);
> >+#endif
> >+#if defined(__STDCPP_FLOAT16_T__) &&
> defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+          case _Arg_f16:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_f16);
> >+#endif
> >+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> >+          case _Arg_f32:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_f32);
> > #endif
> >+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
> >+          case _Arg_f64:
> >+            return std::forward<_Visitor>(__vis)(_M_val._M_f64);
> >+#endif
> >+#endif // __glibcxx_to_chars
> >           case _Arg_str:
> >             return std::forward<_Visitor>(__vis)(_M_val._M_str);
> >           case _Arg_sv:
> >@@ -4280,14 +4362,7 @@ namespace __format
> >           case _Arg_u128:
> >             return std::forward<_Visitor>(__vis)(_M_val._M_u128);
> > #endif
> >-
> >-#if _GLIBCXX_FORMAT_F128 == 2
> >-          case _Arg_f128:
> >-            return std::forward<_Visitor>(__vis)(_M_val._M_f128);
> >-#endif
> >-
> >           default:
> >-            // _Arg_f16 etc.
> >             __builtin_unreachable();
> >         }
> >       }
> >diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc
> b/libstdc++-v3/testsuite/std/format/arguments/args.cc
> >index 4c50bc74319..60296753919 100644
> >--- a/libstdc++-v3/testsuite/std/format/arguments/args.cc
> >+++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc
> >@@ -164,24 +164,6 @@ void test_visited_as_handle()
> > #endif
> > }
> >
> >-template<typename E, typename S>
> >-void test_visited_as()
> >-{
> >-  auto v = static_cast<S>(1.0);
> >-  auto store = std::make_format_args(v);
> >-  std::format_args args = store;
> >-
> >-  auto is_expected_val = [v](auto arg) {
> >-    if constexpr (std::is_same_v<decltype(arg), E>)
> >-      return arg == static_cast<E>(v);
> >-    return false;
> >-  };
> >-  VERIFY( std::visit_format_arg(is_expected_val, args.get(0)) );
> >-#if __cpp_lib_format >= 202306L // C++26 adds
> std::basic_format_arg::visit
> >-  VERIFY( args.get(0).visit(is_expected_val) );
> >-#endif
> >-}
> >-
> > template<typename T>
> > concept can_format = std::is_default_constructible_v<std::formatter<T,
> char>>;
> >
> >@@ -195,30 +177,31 @@ int main()
> >   test_visited_as_handle<__int128>();
> >   test_visited_as_handle<unsigned __int128>();
> > #endif
> >-// TODO: This should be visited as handle.
> >-#ifdef __STDCPP_FLOAT16_T__
> >-  if constexpr (can_format<_Float16>)
> >-    test_visited_as<float, _Float16>();
> >-#endif
> >-#ifdef __STDCPP_BFLOAT16_T__
> >+#ifdef __BFLT16_DIG__
> >   if constexpr (can_format<__gnu_cxx::__bfloat16_t>)
> >-    test_visited_as<float, __gnu_cxx::__bfloat16_t>();
> >+    test_visited_as_handle<__gnu_cxx::__bfloat16_t>();
> >+#endif
> >+#ifdef __FLT16_DIG__
> >+  if constexpr (can_format<_Float16>)
> >+    test_visited_as_handle<_Float16>();
> > #endif
> > #ifdef __FLT32_DIG__
> >   if constexpr (can_format<_Float32>)
> >-    test_visited_as<float, _Float32>();
> >+    test_visited_as_handle<_Float32>();
> > #endif
> > #ifdef __FLT64_DIG__
> >   if constexpr (can_format<_Float64>)
> >-    test_visited_as<double, _Float64>();
> >+    test_visited_as_handle<_Float64>();
> > #endif
> > #ifdef __FLT128_DIG__
> >   if constexpr (can_format<_Float128>)
> >-# ifdef _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
> >-    test_visited_as<long double, _Float128>();
> >-# else
> >     test_visited_as_handle<_Float128>();
> >-# endif
> >+#endif
> >+#ifdef __SIZEOF_FLOAT128__
> >+  //  __ieee128 is same type as __float128, and may be long double
> >+  if constexpr (!std::is_same_v<__float128, long double>)
> >+    if constexpr (can_format<__float128>)
> >+      test_visited_as_handle<__float128>();
> > #endif
> > #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> >   if constexpr (!std::is_same_v<__ieee128, long double>)
> >diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
> b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
> >index b5dd7cdba78..adafc58c183 100644
> >--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
> >+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
> >@@ -443,6 +443,8 @@ test_custom()
> > }
> >
> > #if __cpp_lib_format >= 202305
> >+#include <stdfloat>
> >+
> > struct X { };
> >
> > template<>
> >@@ -458,13 +460,20 @@ struct std::formatter<X, char>
> >     if (spec == "int")
> >     {
> >       pc.check_dynamic_spec_integral(pc.next_arg_id());
> >-      integer = true;
> >+      type = Type::integral;
> >     }
> >     else if (spec == "str")
> >     {
> >       pc.check_dynamic_spec_string(pc.next_arg_id());
> >-      integer = false;
> >+      type = Type::string;
> >+    }
> >+    else if (spec == "float")
> >+    {
> >+      pc.check_dynamic_spec<float, double, long
> double>(pc.next_arg_id());
> >+      type = Type::floating;
> >     }
> >+    else if (spec == "other")
> >+      type = Type::other;
> >     else
> >       throw std::format_error("invalid format-spec");
> >     return pc.begin() + spec.size();
> >@@ -474,13 +483,44 @@ struct std::formatter<X, char>
> >   format(X, std::format_context& c) const
> >   {
> >     std::visit_format_arg([this]<typename T>(T) { // { dg-warning
> "deprecated" "" { target c++26 } }
> >-      if (is_integral_v<T> != this->integer)
> >-      throw std::format_error("invalid argument type");
> >+      constexpr bool is_handle
> >+      =
> std::is_same_v<std::basic_format_arg<std::format_context>::handle, T>;
> >+      constexpr bool is_integral
> >+      = std::is_same_v<int, T> || std::is_same_v<unsigned int, T>
> >+          || is_same_v<long long, T> || std::is_same_v<unsigned long
> long, T>;
> >+      constexpr bool is_string
> >+      = std::is_same_v<const char*, T> ||
> std::is_same_v<std::string_view, T>;
> >+      constexpr bool is_floating
> >+      = std::is_same_v<float, T> || std::is_same_v<double, T>
> >+          || std::is_same_v<long double, T>;
> >+      switch (this->type)
> >+      {
> >+      case Type::other:
> >+        if (is_handle) return;
> >+        break;
> >+      case Type::integral:
> >+        if (is_integral) return;
> >+        break;
> >+      case Type::string:
> >+        if (is_string) return;
> >+        break;
> >+      case Type::floating:
> >+        if (is_floating) return;
> >+        break;
> >+      }
> >+      throw std::format_error("invalid argument type");
> >     }, c.arg(1));
> >     return c.out();
> >   }
> > private:
> >-  bool integer = false;
> >+  enum class Type
> >+  {
> >+    other,
> >+    integral,
> >+    string,
> >+    floating,
> >+  };
> >+  Type type = Type::other;
> > };
> > #endif
> >
> >@@ -497,6 +537,28 @@ test_dynamic_type_check()
> >
> >   (void) std::format("{:int}", X{}, 42L);
> >   (void) std::format("{:str}", X{}, "H2G2");
> >+  (void) std::format("{:float}", X{}, 10.0);
> >+
> >+#ifdef __STDCPP_FLOAT16_T__
> >+  if constexpr (std::formattable<std::bfloat16_t, char>)
> >+    (void) std::format("{:other}", X{}, 10.0bf16);
> >+#endif
> >+#ifdef __STDCPP_FLOAT16_T__
> >+  if constexpr (std::formattable<std::float16_t, char>)
> >+    (void) std::format("{:other}", X{}, 10.0f16);
> >+#endif
> >+#ifdef __STDCPP_FLOAT32_T__
> >+  if constexpr (std::formattable<std::float32_t, char>)
> >+    (void) std::format("{:other}", X{}, 10.0f32);
> >+#endif
> >+#ifdef __STDCPP_FLOAT64_T__
> >+  if constexpr (std::formattable<std::float64_t, char>)
> >+    (void) std::format("{:other}", X{}, 10.0f64);
> >+#endif
> >+#ifdef __STDCPP_FLOAT128_T__
> >+  if constexpr (std::formattable<std::float128_t, char>)
> >+    (void) std::format("{:other}", X{}, 10.0f128);
> >+#endif
> > #endif
> > }
> >
> >--
> >2.49.0
> >
> >
>
>

Reply via email to