[PATCH] libstdc++: implement constexpr std::format

Tomasz Kaminski tkaminsk@redhat.com
Tue Jun 2 07:25:49 GMT 2026


Hi Ivan,

A revised version  this patch was just merged for the GCC-17.
Thank you for your contributions.


On Wed, Feb 25, 2026 at 10:00 AM Ivan Lazaric <ivan.lazaric1@gmail.com>
wrote:

> This patch partially implements constexpr formatting from P3391R2,
> and defines the feature test macro__cpp_lib_constexpr_format to 202511L,
> provided only in <format>.
>
> This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.
>
> Add `__format::__{toupper,memcpy}` functions that work in constexpr.
>
> Due to constexpr limitations, previous implementation of
> `_Arg_value::_M_set` via `_S_get` wouldn't work.
> Instead of adding a `_S_set` function duplicating most of the
> `_S_get` logic, generalize `_S_get` to `_S_get_set` by
> folding over assignment, update `_M_set` to go through it.
>
> Avoid using `_Ptr_sink` in constexpr, in `__do_vformat_to`
> and `formatted_size`.
>
> Update some formatting tests to test constexpr as well.
>
> This patch is missing:
> * wide constexpr formatting
> * more constexpr tests
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/version.def (constexpr_format): Define.
>         * include/bits/version.h: Regenerate.
>         * include/std/format:
>         (__format::__toupper, __format::memcpy): Define.
>         (_Arg_value::_S_get): Generalize to _S_get_set.
>         (__format::_Counting_constexpr_sink): Define.
>         (__format::__do_vformat_to, formatted_size):
>         Avoid using _Ptr_sink in constexpr.
>         * testsuite/std/format/functions/format.cc: Constexpr testing.
>         * testsuite/std/format/functions/format_to.cc: Constexpr testing.
>         * testsuite/std/format/ranges/format_kind.cc: Constexpr testing.
>         * testsuite/std/format/ranges/formatter.cc: Constexpr testing.
>         * testsuite/std/format/ranges/sequence.cc: Constexpr testing.
>         * testsuite/std/format/string.cc: Constexpr testing.
>         * testsuite/std/format/tuple.cc: Constexpr testing.
>
> Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> ---
> This patch is based on top of the 2 following not-yet-merged patches:
> libstdc++: Store basic_format_arg::handle in __format::_Arg_value
> libstdc++: Introduce __format::_Ptr_sink for contingous iterators
>
>
>
>  libstdc++-v3/include/bits/version.def         |  10 +
>  libstdc++-v3/include/bits/version.h           |  10 +
>  libstdc++-v3/include/std/format               | 367 ++++++++++++++----
>  .../testsuite/std/format/functions/format.cc  | 191 +++++----
>  .../std/format/functions/format_to.cc         |  58 ++-
>  .../std/format/ranges/format_kind.cc          |  11 +-
>  .../testsuite/std/format/ranges/formatter.cc  |  40 +-
>  .../testsuite/std/format/ranges/sequence.cc   |  73 +++-
>  libstdc++-v3/testsuite/std/format/string.cc   | 222 ++++++-----
>  libstdc++-v3/testsuite/std/format/tuple.cc    |  72 +++-
>  10 files changed, 742 insertions(+), 312 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> index c7709ba3a07..827498732c6 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1330,6 +1330,16 @@ ftms = {
>    };
>  };
>
> +ftms = {
> +  name = constexpr_format;
> +  // 202511 P3391R2 constexpr std::format
> +  values = {
> +    v = 202511;
> +    cxxmin = 26;
> +    hosted = yes;
> +  };
> +};
> +
>  ftms = {
>    name = format_uchar;
>    values = {
> diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> index c72cda506f1..4911b741bb1 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -1476,6 +1476,16 @@
>  #endif /* !defined(__cpp_lib_format) */
>  #undef __glibcxx_want_format
>
> +#if !defined(__cpp_lib_constexpr_format)
> +# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
> +#  define __glibcxx_constexpr_format 202511L
> +#  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_constexpr_format)
> +#   define __cpp_lib_constexpr_format 202511L
> +#  endif
> +# endif
> +#endif /* !defined(__cpp_lib_constexpr_format) */
> +#undef __glibcxx_want_constexpr_format
> +
>  #if !defined(__cpp_lib_format_uchar)
>  # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
>  #  define __glibcxx_format_uchar 202311L
> diff --git a/libstdc++-v3/include/std/format
> b/libstdc++-v3/include/std/format
> index 245ea964675..1ecfabb2590 100644
> --- a/libstdc++-v3/include/std/format
> +++ b/libstdc++-v3/include/std/format
> @@ -39,6 +39,7 @@
>  #define __glibcxx_want_format_ranges
>  #define __glibcxx_want_format_uchar
>  #define __glibcxx_want_constexpr_exceptions
> +#define __glibcxx_want_constexpr_format
>  #include <bits/version.h>
>
>  #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
> @@ -98,6 +99,34 @@ namespace __format
>  #define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
>  #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
>
> +  [[__gnu__::__always_inline__]]
> +  constexpr char
> +  __toupper(char __c)
> +  {
> +    if consteval {
> +      if (__c < 'a' || __c > 'z') return __c;
> +      return __c - 'a' + 'A';
> +    } else {
> +#if __has_builtin(__builtin_toupper)
> +      return __builtin_toupper(__c);
> +#else
> +      return std::toupper(__c);
> +#endif
> +    }
> +  }
> +
> +  [[__gnu__::__always_inline__]]
> +  constexpr void
> +  __memcpy(char* __dest, const char* __src, size_t __n)
> +  {
> +    if consteval {
> +      for (size_t __i = 0; __i < __n; ++__i)
> +       __dest[__i] = __src[__i];
> +    } else {
> +      __builtin_memcpy(__dest, __src, __n);
> +    }
> +  }
> +
>    // Size for stack located buffer
>    template<typename _CharT>
>      constexpr size_t __stackbuf_size = 32 * sizeof(void*) /
> sizeof(_CharT);
> @@ -128,6 +157,7 @@ namespace __format
>      struct _Runtime_format_string
>      {
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        _Runtime_format_string(basic_string_view<_CharT> __s) noexcept
>        : _M_str(__s) { }
>
> @@ -173,6 +203,7 @@ namespace __format
>         basic_format_string(const _Tp& __s);
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_string(__format::_Runtime_format_string<_CharT> __s)
> noexcept
>        : _M_str(__s._M_str)
>        { }
> @@ -197,12 +228,14 @@ namespace __format
>
>  #if __cpp_lib_format >= 202311L // >= C++26
>    [[__gnu__::__always_inline__]]
> +  _GLIBCXX26_CONSTEXPR
>    inline __format::_Runtime_format_string<char>
>    runtime_format(string_view __fmt) noexcept
>    { return __fmt; }
>
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    [[__gnu__::__always_inline__]]
> +  _GLIBCXX26_CONSTEXPR
>    inline __format::_Runtime_format_string<wchar_t>
>    runtime_format(wstring_view __fmt) noexcept
>    { return __fmt; }
> @@ -238,6 +271,7 @@ namespace __format
>
>    /// @cond undocumented
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __throw_format_error(const char* __what)
>    { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
> @@ -249,26 +283,31 @@ namespace __format
>    // XXX use named functions for each constexpr error?
>
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __unmatched_left_brace_in_format_string()
>    { __throw_format_error("format error: unmatched '{' in format string");
> }
>
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __unmatched_right_brace_in_format_string()
>    { __throw_format_error("format error: unmatched '}' in format string");
> }
>
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __conflicting_indexing_in_format_string()
>    { __throw_format_error("format error: conflicting indexing style in
> format string"); }
>
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __invalid_arg_id_in_format_string()
>    { __throw_format_error("format error: invalid arg-id in format
> string"); }
>
>    [[noreturn]]
> +  _GLIBCXX26_CONSTEXPR
>    inline void
>    __failed_to_parse_format_spec()
>    { __throw_format_error("format error: failed to parse format-spec"); }
> @@ -517,6 +556,7 @@ namespace __format
>    using enum _WidthPrec;
>
>    template<typename _Context>
> +    _GLIBCXX26_CONSTEXPR
>      size_t
>      __int_from_arg(const basic_format_arg<_Context>& __arg);
>
> @@ -750,6 +790,7 @@ namespace __format
>        }
>
>        template<typename _Context>
> +       _GLIBCXX26_CONSTEXPR
>         size_t
>         _M_get_width(_Context& __ctx) const
>         {
> @@ -762,6 +803,7 @@ namespace __format
>         }
>
>        template<typename _Context>
> +       _GLIBCXX26_CONSTEXPR
>         size_t
>         _M_get_precision(_Context& __ctx) const
>         {
> @@ -775,6 +817,7 @@ namespace __format
>      };
>
>    template<typename _Int>
> +    _GLIBCXX26_CONSTEXPR
>      inline char*
>      __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
>      {
> @@ -792,6 +835,7 @@ namespace __format
>    // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter).
>    template<typename _Out, typename _CharT>
>      requires output_iterator<_Out, const _CharT&>
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      __write(_Out __out, basic_string_view<_CharT> __str)
>      {
> @@ -809,6 +853,7 @@ namespace __format
>    // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN.
>    // pre: __align != _Align_default
>    template<typename _Out, typename _CharT>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_padded(_Out __out, basic_string_view<_CharT> __str,
>                    _Align __align, size_t __nfill, char32_t __fill_char)
> @@ -883,6 +928,7 @@ namespace __format
>    // Write STR to OUT, with alignment and padding as determined by SPEC.
>    // pre: __spec._M_align != _Align_default || __align != _Align_default
>    template<typename _CharT, typename _Out>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>>
> __str,
>                            size_t __estimated_width,
> @@ -905,6 +951,7 @@ namespace __format
>      }
>
>     template<typename _CharT>
> +     _GLIBCXX26_CONSTEXPR
>       size_t
>       __truncate(basic_string_view<_CharT>& __s, size_t __prec)
>       {
> @@ -1049,6 +1096,7 @@ namespace __format
>
>    using uint_least32_t = __UINT_LEAST32_TYPE__;
>    template<typename _Out, typename _CharT>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escape_seq(_Out __out, uint_least32_t __val,
>                        basic_string_view<_CharT> __prefix)
> @@ -1079,6 +1127,7 @@ namespace __format
>      }
>
>    template<typename _Out, typename _CharT>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
>      {
> @@ -1090,6 +1139,7 @@ namespace __format
>      }
>
>    template<typename _Out, typename _CharT>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escaped_char(_Out __out, _CharT __c)
>      {
> @@ -1116,6 +1166,7 @@ namespace __format
>      }
>
>    template<typename _CharT, typename _Out>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escaped_ascii(_Out __out,
>                           basic_string_view<_CharT> __str,
> @@ -1146,6 +1197,7 @@ namespace __format
>      }
>
>    template<typename _CharT, typename _Out>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escaped_unicode_part(_Out __out, basic_string_view<_CharT>&
> __str,
>                                  bool& __prev_esc, _Term_char __term)
> @@ -1224,6 +1276,7 @@ namespace __format
>      }
>
>    template<typename _CharT, typename _Out>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str,
>                             _Term_char __term)
> @@ -1236,6 +1289,7 @@ namespace __format
>      }
>
>    template<typename _CharT, typename _Out>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __write_escaped(_Out __out,  basic_string_view<_CharT> __str,
> _Term_char __term)
>      {
> @@ -1257,12 +1311,14 @@ namespace __format
>    struct _Optional_locale
>    {
>      [[__gnu__::__always_inline__]]
> +    _GLIBCXX26_CONSTEXPR
>      _Optional_locale() : _M_dummy(), _M_hasval(false) { }
>
>      _Optional_locale(const locale& __loc) noexcept
>      : _M_loc(__loc), _M_hasval(true)
>      { }
>
> +    _GLIBCXX26_CONSTEXPR
>      _Optional_locale(const _Optional_locale& __l) noexcept
>      : _M_dummy(), _M_hasval(__l._M_hasval)
>      {
> @@ -1270,6 +1326,7 @@ namespace __format
>         std::construct_at(&_M_loc, __l._M_loc);
>      }
>
> +    _GLIBCXX26_CONSTEXPR
>      _Optional_locale&
>      operator=(const _Optional_locale& __l) noexcept
>      {
> @@ -1291,6 +1348,7 @@ namespace __format
>        return *this;
>      }
>
> +    _GLIBCXX26_CONSTEXPR
>      ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
>
>      _Optional_locale&
> @@ -1317,6 +1375,7 @@ namespace __format
>        return _M_loc;
>      }
>
> +    _GLIBCXX26_CONSTEXPR
>      bool has_value() const noexcept { return _M_hasval; }
>
>      union {
> @@ -1391,6 +1450,7 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         _Out
>         format(basic_string_view<_CharT> __s,
>                basic_format_context<_Out, _CharT>& __fc) const
> @@ -1408,6 +1468,7 @@ namespace __format
>         }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         _Out
>         _M_format_escaped(basic_string_view<_CharT> __s,
>                           basic_format_context<_Out, _CharT>& __fc) const
> @@ -1433,6 +1494,7 @@ namespace __format
>  #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
>        template<ranges::input_range _Rg, typename _Out>
>         requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
> _CharT>
> +       _GLIBCXX26_CONSTEXPR
>         _Out
>         _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>&
> __fc) const
>         {
> @@ -1641,6 +1703,7 @@ namespace __format
>         }
>
>        template<typename _Int, typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
>         {
> @@ -1689,11 +1752,7 @@ namespace __format
>               __res = to_chars(__start, __end, __u, 16);
>               if (_M_spec._M_type == _Pres_X)
>                 for (auto __p = __start; __p != __res.ptr; ++__p)
> -#if __has_builtin(__builtin_toupper)
> -                 *__p = __builtin_toupper(*__p);
> -#else
> -                 *__p = std::toupper(*__p);
> -#endif
> +                 *__p = __format::__toupper(*__p);
>               break;
>             default:
>               __builtin_unreachable();
> @@ -1702,8 +1761,8 @@ namespace __format
>           if (_M_spec._M_alt && __base_prefix.size())
>             {
>               __start -= __base_prefix.size();
> -             __builtin_memcpy(__start, __base_prefix.data(),
> -                              __base_prefix.size());
> +             __format::__memcpy(__start, __base_prefix.data(),
> +                                __base_prefix.size());
>             }
>           __start = __format::__put_sign(__i, _M_spec._M_sign, __start -
> 1);
>
> @@ -1712,6 +1771,7 @@ namespace __format
>         }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
>         {
> @@ -1742,6 +1802,7 @@ namespace __format
>         }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format_character(_CharT __c,
>                             basic_format_context<_Out, _CharT>& __fc) const
> @@ -1773,6 +1834,7 @@ namespace __format
>         }
>
>        template<typename _Int>
> +       _GLIBCXX26_CONSTEXPR
>         static _CharT
>         _S_to_character(_Int __i)
>         {
> @@ -1794,6 +1856,7 @@ namespace __format
>         }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format_int(string_view __narrow_str, size_t __prefix_len,
>                       basic_format_context<_Out, _CharT>& __fc) const
> @@ -2068,6 +2131,7 @@ namespace __format
>        }
>
>        template<typename _Fp, typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_Fp __v, basic_format_context<_Out, _CharT>& __fc) const
>         {
> @@ -2197,7 +2261,7 @@ namespace __format
>           if (__upper)
>             {
>               for (char* __p = __start; __p != __res.ptr; ++__p)
> -               *__p = std::toupper(*__p);
> +               *__p = __format::__toupper(*__p);
>             }
>
>           bool __have_sign = true;
> @@ -2502,10 +2566,15 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(const void* __v, basic_format_context<_Out, _CharT>& __fc)
> const
>         {
> -         auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
> +         // Treating nullptr specially
> +         // to enable constexpr formatting of nullptr_t.
> +         auto __u = __v
> +           ? reinterpret_cast<__UINTPTR_TYPE__>(__v)
> +           : (__UINTPTR_TYPE__)0;
>           char __buf[2 + sizeof(__v) * 2];
>           auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
>                                              __u, 16);
> @@ -2517,11 +2586,7 @@ namespace __format
>             {
>               __buf[1] = 'X';
>               for (auto __p = __buf + 2; __p != __ptr; ++__p)
> -#if __has_builtin(__builtin_toupper)
> -               *__p = __builtin_toupper(*__p);
> -#else
> -               *__p = std::toupper(*__p);
> -#endif
> +               *__p = __format::__toupper(*__p);
>             }
>  #endif
>
> @@ -2590,6 +2655,7 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
>         {
> @@ -2628,6 +2694,7 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, wchar_t>::iterator
>         format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
>         {
> @@ -2663,6 +2730,7 @@ namespace __format
>
>        template<typename _Out>
>         [[__gnu__::__nonnull__]]
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
>         { return _M_f.format(__u, __fc); }
> @@ -2692,6 +2760,7 @@ namespace __format
>
>        template<typename _Out>
>         [[__gnu__::__nonnull__]]
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(const _CharT* __u,
>                basic_format_context<_Out, _CharT>& __fc) const
> @@ -2722,6 +2791,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(const _CharT (&__u)[_Nm],
>                basic_format_context<_Out, _CharT>& __fc) const
> @@ -2751,6 +2821,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, char>::iterator
>         format(const basic_string<char, _Traits, _Alloc>& __u,
>                basic_format_context<_Out, char>& __fc) const
> @@ -2783,6 +2854,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, wchar_t>::iterator
>         format(const basic_string<wchar_t, _Traits, _Alloc>& __u,
>                basic_format_context<_Out, wchar_t>& __fc) const
> @@ -2816,6 +2888,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, char>::iterator
>         format(basic_string_view<char, _Traits> __u,
>                basic_format_context<_Out, char>& __fc) const
> @@ -2848,6 +2921,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, wchar_t>::iterator
>         format(basic_string_view<wchar_t, _Traits> __u,
>                basic_format_context<_Out, wchar_t>& __fc) const
> @@ -2911,6 +2985,7 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
>         { return _M_f.format(__u, __fc); }
> @@ -3122,6 +3197,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(const void* __v, basic_format_context<_Out, _CharT>& __fc)
> const
>         { return _M_f.format(__v, __fc); }
> @@ -3147,6 +3223,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
>         { return _M_f.format(__v, __fc); }
> @@ -3172,6 +3249,7 @@ namespace __format
>        { return _M_f.parse(__pc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
>         { return _M_f.format(nullptr, __fc); }
> @@ -3316,10 +3394,12 @@ namespace __format
>        constexpr _Sink_iter
>        operator++(int) { return *this; }
>
> +      _GLIBCXX26_CONSTEXPR
>        auto
>        _M_reserve(size_t __n) const
>        { return _M_sink->_M_reserve(__n); }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_discarding() const
>        { return _M_sink->_M_discarding(); }
> @@ -3352,6 +3432,7 @@ namespace __format
>
>        // The portion of the span that has been written to.
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        span<_CharT>
>        _M_used() const noexcept
>        { return _M_span.first(_M_next - _M_span.begin()); }
> @@ -3369,6 +3450,7 @@ namespace __format
>        { _M_next = _M_span.begin(); }
>
>        // Replace the current output range.
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
>        {
> @@ -3409,10 +3491,13 @@ namespace __format
>        struct _Reservation
>        {
>         // True if the reservation was successful, false otherwise.
> +       _GLIBCXX26_CONSTEXPR
>         explicit operator bool() const noexcept { return _M_sink; }
>         // A pointer to write directly to the sink.
> +       _GLIBCXX26_CONSTEXPR
>         _CharT* get() const noexcept { return
> _M_sink->_M_next.operator->(); }
>         // Add n to the _M_next iterator for the sink.
> +       _GLIBCXX26_CONSTEXPR
>         void _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
>         _Sink* _M_sink;
>        };
> @@ -3421,6 +3506,7 @@ namespace __format
>        // If anything is written to the reservation then there must be a
> call
>        // to _M_bump(N2) before any call to another member function of
> *this,
>        // where N2 is the number of characters written.
> +      _GLIBCXX26_CONSTEXPR
>        virtual _Reservation
>        _M_reserve(size_t __n)
>        {
> @@ -3438,11 +3524,13 @@ namespace __format
>
>        // Update the next output position after writing directly to the
> sink.
>        // pre: no calls to _M_write or _M_overflow since _M_reserve.
> +      _GLIBCXX26_CONSTEXPR
>        virtual void
>        _M_bump(size_t __n)
>        { _M_next += __n; }
>
>        // Returns true if the _Sink is discarding incoming characters.
> +      _GLIBCXX26_CONSTEXPR
>        virtual bool
>        _M_discarding() const
>        { return false; }
> @@ -3461,6 +3549,7 @@ namespace __format
>    template<typename _CharT>
>      class _Fixedbuf_sink final : public _Sink<_CharT>
>      {
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_overflow() override
>        {
> @@ -3509,6 +3598,7 @@ namespace __format
>        _Seq _M_seq;
>      protected:
>        // Transfer buffer contents to the sequence, so buffer can be
> refilled.
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_overflow() override
>        {
> @@ -3528,6 +3618,7 @@ namespace __format
>         this->_M_rewind();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        typename _Sink<_CharT>::_Reservation
>        _M_reserve(size_t __n) override
>        {
> @@ -3564,6 +3655,7 @@ namespace __format
>           return _Sink<_CharT>::_M_reserve(__n);
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_bump(size_t __n) override
>        {
> @@ -3579,6 +3671,7 @@ namespace __format
>           }
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void _M_trim(span<const _CharT> __s)
>         requires __is_specialization_of<_Seq, basic_string>
>        {
> @@ -3595,15 +3688,18 @@ namespace __format
>        // to _M_buf if it overflows? Or even do that for all unused
> capacity?
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
>        { }
>
> +      _GLIBCXX26_CONSTEXPR
>        _Seq_sink(_Seq&& __s)
> noexcept(is_nothrow_move_constructible_v<_Seq>)
>        : _M_seq(std::move(__s))
>        { }
>
>        using _Sink<_CharT>::out;
>
> +      _GLIBCXX26_CONSTEXPR
>        _Seq
>        get() &&
>        {
> @@ -3614,6 +3710,7 @@ namespace __format
>
>        // A writable span that views everything written to the sink.
>        // Will be either a view over _M_seq or the used part of _M_buf.
> +      _GLIBCXX26_CONSTEXPR
>        span<_CharT>
>        _M_span()
>        {
> @@ -3627,6 +3724,7 @@ namespace __format
>         return __s;
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        basic_string_view<_CharT>
>        view()
>        {
> @@ -3652,6 +3750,7 @@ namespace __format
>      protected:
>        size_t _M_count = 0;
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_overflow() override
>        {
> @@ -3672,6 +3771,7 @@ namespace __format
>         _M_count += __s.size();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_discarding() const override
>        {
> @@ -3682,6 +3782,7 @@ namespace __format
>
>      public:
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        explicit
>        _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1)
>        : _M_out(std::move(__out)), _M_max(__max)
> @@ -3689,6 +3790,7 @@ namespace __format
>
>        using _Sink<_CharT>::out;
>
> +      _GLIBCXX26_CONSTEXPR
>        format_to_n_result<_OutIter>
>        _M_finish() &&
>        {
> @@ -3861,11 +3963,13 @@ namespace __format
>        size_t _M_printwidth;
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_ignoring() const
>        { return _M_printwidth >= _M_maxwidth; }
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_buffering() const
>        {
> @@ -3876,6 +3980,7 @@ namespace __format
>         return false;
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_sync_discarding()
>        {
> @@ -3884,6 +3989,7 @@ namespace __format
>             _M_maxwidth = _M_printwidth;
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_flush()
>        {
> @@ -3894,6 +4000,7 @@ namespace __format
>         this->_M_rewind();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_force_update()
>        {
> @@ -3922,6 +4029,7 @@ namespace __format
>         return false;
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_update(size_t __new)
>        {
> @@ -3932,6 +4040,7 @@ namespace __format
>         return true;
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_overflow() override
>        {
> @@ -3947,10 +4056,12 @@ namespace __format
>           _Str_sink<_CharT>::_M_overflow();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_discarding() const override
>        { return _M_ignoring(); }
>
> +      _GLIBCXX26_CONSTEXPR
>        typename _Sink<_CharT>::_Reservation
>        _M_reserve(size_t __n) override
>        {
> @@ -3970,6 +4081,7 @@ namespace __format
>         return _Sink<_CharT>::_M_reserve(__n);
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_bump(size_t __n) override
>        {
> @@ -3985,6 +4097,7 @@ namespace __format
>
>      public:
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        explicit
>        _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth)
>        : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
> @@ -3992,11 +4105,13 @@ namespace __format
>        { _M_sync_discarding(); }
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        explicit
>        _Padding_sink(_Out __out, size_t __padwidth)
>        : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
>        { }
>
> +      _GLIBCXX26_CONSTEXPR
>        _Out
>        _M_finish(_Align __align, char32_t __fill_char)
>        {
> @@ -4036,6 +4151,7 @@ namespace __format
>        unsigned _M_prev_escape : 1;
>        unsigned _M_out_discards : 1;
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_sync_discarding()
>        {
> @@ -4043,6 +4159,7 @@ namespace __format
>           _M_out_discards = _M_out._M_discarding();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_write()
>        {
> @@ -4069,6 +4186,7 @@ namespace __format
>         _M_sync_discarding();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_overflow() override
>        {
> @@ -4078,12 +4196,14 @@ namespace __format
>           _M_write();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        _M_discarding() const override
>        { return _M_out_discards; }
>
>      public:
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        explicit
>        _Escaping_sink(_Out __out, _Term_char __term)
>        : _M_out(std::move(__out)), _M_term(__term),
> @@ -4093,6 +4213,7 @@ namespace __format
>         _M_sync_discarding();
>        }
>
> +      _GLIBCXX26_CONSTEXPR
>        _Out
>        _M_finish()
>        {
> @@ -4141,6 +4262,7 @@ namespace __format
>                             const _Tp, _Tp>;
>
>        template<typename _Tq>
> +       _GLIBCXX26_CONSTEXPR
>         static void
>         _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
>                   _Context& __format_ctx, const void* __ptr)
> @@ -4154,6 +4276,7 @@ namespace __format
>
>        template<typename _Tp>
>         requires (!is_same_v<remove_cv_t<_Tp>, _Handle>)
> +       _GLIBCXX26_CONSTEXPR
>         explicit
>         _Handle(_Tp& __val) noexcept
>         : _M_ptr(__builtin_addressof(__val))
> @@ -4169,6 +4292,7 @@ namespace __format
>        _Handle& operator=(const _Handle&) = default;
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        void
>        format(basic_format_parse_context<_CharT>& __pc, _Context& __fc)
> const
>        { _M_func(__pc, __fc, this->_M_ptr); }
> @@ -4226,102 +4350,111 @@ namespace __format
>        };
>
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        _Arg_value() : _M_none() { }
>
>  #if 0
>        template<typename _Tp>
> +       _GLIBCXX26_CONSTEXPR
>         _Arg_value(in_place_type_t<_Tp>, _Tp __val)
>         { _S_get<_Tp>() = __val; }
>  #endif
>
>        template<typename _Tp, typename _Self>
>         [[__gnu__::__always_inline__]]
> +       _GLIBCXX26_CONSTEXPR
>         static auto&
> -       _S_get(_Self& __u) noexcept
> +       _S_get_set(_Self& __u, auto... __value) noexcept
>         {
>           if constexpr (is_same_v<_Tp, bool>)
> -           return __u._M_bool;
> +           return (__u._M_bool = ... = __value);
>           else if constexpr (is_same_v<_Tp, _CharT>)
> -           return __u._M_c;
> +           return (__u._M_c = ... = __value);
>           else if constexpr (is_same_v<_Tp, int>)
> -           return __u._M_i;
> +           return (__u._M_i = ... = __value);
>           else if constexpr (is_same_v<_Tp, unsigned>)
> -           return __u._M_u;
> +           return (__u._M_u = ... = __value);
>           else if constexpr (is_same_v<_Tp, long long>)
> -           return __u._M_ll;
> +           return (__u._M_ll = ... = __value);
>           else if constexpr (is_same_v<_Tp, unsigned long long>)
> -           return __u._M_ull;
> +           return (__u._M_ull = ... = __value);
>           else if constexpr (is_same_v<_Tp, float>)
> -           return __u._M_flt;
> +           return (__u._M_flt = ... = __value);
>           else if constexpr (is_same_v<_Tp, double>)
> -           return __u._M_dbl;
> +           return (__u._M_dbl = ... = __value);
>  #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
>           else if constexpr (is_same_v<_Tp, long double>)
> -           return __u._M_ldbl;
> +           return (__u._M_ldbl = ... = __value);
>  #else
>           else if constexpr (is_same_v<_Tp, __ibm128>)
> -           return __u._M_ibm128;
> +           return (__u._M_ibm128 = ... = __value);
>           else if constexpr (is_same_v<_Tp, __ieee128>)
> -           return __u._M_ieee128;
> +           return (__u._M_ieee128 = ... = __value);
>  #endif
>  #ifdef __SIZEOF_FLOAT128__
>           else if constexpr (is_same_v<_Tp, __float128>)
> -           return __u._M_float128;
> +           return (__u._M_float128 = ... = __value);
>  #endif
>           else if constexpr (is_same_v<_Tp, const _CharT*>)
> -           return __u._M_str;
> +           return (__u._M_str = ... = __value);
>           else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
> -           return __u._M_sv;
> +           return (__u._M_sv = ... = __value);
>           else if constexpr (is_same_v<_Tp, const void*>)
> -           return __u._M_ptr;
> +           return (__u._M_ptr = ... = __value);
>  #ifdef __SIZEOF_INT128__
>           else if constexpr (is_same_v<_Tp, __int128>)
> -           return __u._M_i128;
> +           return (__u._M_i128 = ... = __value);
>           else if constexpr (is_same_v<_Tp, unsigned __int128>)
> -           return __u._M_u128;
> +           return (__u._M_u128 = ... = __value);
>  #endif
>  #ifdef __BFLT16_DIG__
>           else if constexpr (is_same_v<_Tp, __bflt16_t>)
> -           return __u._M_bf16;
> +           return (__u._M_bf16 = ... = __value);
>  #endif
>  #ifdef __FLT16_DIG__
>           else if constexpr (is_same_v<_Tp, _Float16>)
> -           return __u._M_f16;
> +           return (__u._M_f16 = ... = __value);
>  #endif
>  #ifdef __FLT32_DIG__
>           else if constexpr (is_same_v<_Tp, _Float32>)
> -           return __u._M_f32;
> +           return (__u._M_f32 = ... = __value);
>  #endif
>  #ifdef __FLT64_DIG__
>           else if constexpr (is_same_v<_Tp, _Float64>)
> -           return __u._M_f64;
> +           return (__u._M_f64 = ... = __value);
>  #endif
>           else if constexpr (is_same_v<_Tp, _Handle<_Context>>)
> -           return __u._M_handle;
> +           return (__u._M_handle = ... = __value);
>           // Otherwise, ill-formed.
> +         __builtin_unreachable();
>         }
>
>        template<typename _Tp>
>         [[__gnu__::__always_inline__]]
> +       _GLIBCXX26_CONSTEXPR
>         auto&
>         _M_get() noexcept
> -       { return _S_get<_Tp>(*this); }
> +       { return _S_get_set<_Tp>(*this); }
>
>        template<typename _Tp>
>         [[__gnu__::__always_inline__]]
> +       _GLIBCXX26_CONSTEXPR
>         const auto&
>         _M_get() const noexcept
> -       { return _S_get<_Tp>(*this); }
> +       { return _S_get_set<_Tp>(*this); }
>
>        template<typename _Tp>
>         [[__gnu__::__always_inline__]]
> +       _GLIBCXX26_CONSTEXPR
>         void
>         _M_set(_Tp __v) noexcept
>         {
>           if constexpr (is_same_v<_Tp, _Handle<_Context>>)
>             std::construct_at(&_M_handle, __v);
> +         else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
> +           std::construct_at(&_M_sv, __v);
>           else
> -           _S_get<_Tp>(*this) = __v;
> +           _S_get_set<_Tp>(*this, __v);
>         }
>        };
>
> @@ -4330,6 +4463,7 @@ namespace __format
>      class _Arg_store;
>
>    template<typename _Visitor, typename _Ctx>
> +    _GLIBCXX26_CONSTEXPR
>      decltype(auto) __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>
>    template<typename _Ch, typename _Tp>
> @@ -4346,19 +4480,23 @@ namespace __format
>      public:
>        using handle = __format::_Handle<_Context>;
>        [[__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
>
>        [[nodiscard,__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        explicit operator bool() const noexcept
>        { return _M_type != __format::_Arg_none; }
>
>  #if __cpp_lib_format >= 202306L // >= C++26
>        template<typename _Visitor>
> +       _GLIBCXX26_CONSTEXPR
>         decltype(auto)
>         visit(this basic_format_arg __arg, _Visitor&& __vis)
>         { return __arg._M_visit_user(std::forward<_Visitor>(__vis),
> __arg._M_type); }
>
>        template<typename _Res, typename _Visitor>
> +       _GLIBCXX26_CONSTEXPR
>         _Res
>         visit(this basic_format_arg __arg, _Visitor&& __vis)
>         { return __arg._M_visit_user(std::forward<_Visitor>(__vis),
> __arg._M_type); }
> @@ -4536,6 +4674,7 @@ namespace __format
>         }
>
>        template<typename _Tp>
> +       _GLIBCXX26_CONSTEXPR
>         void
>         _M_set(_Tp __v) noexcept
>         {
> @@ -4545,6 +4684,7 @@ namespace __format
>
>        template<typename _Tp>
>         requires __format::__formattable_with<_Tp, _Context>
> +       _GLIBCXX26_CONSTEXPR
>         explicit
>         basic_format_arg(_Tp& __v) noexcept
>         {
> @@ -4559,14 +4699,17 @@ namespace __format
>         }
>
>        template<typename _Ctx, typename... _Argz>
> +       _GLIBCXX26_CONSTEXPR
>         friend auto
>         make_format_args(_Argz&...) noexcept;
>
>        template<typename _Visitor, typename _Ctx>
> +       _GLIBCXX26_CONSTEXPR
>         friend decltype(auto)
>         visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
>
>        template<typename _Visitor, typename _Ctx>
> +       _GLIBCXX26_CONSTEXPR
>         friend decltype(auto)
>         __format::__visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>
> @@ -4575,6 +4718,7 @@ namespace __format
>         __format::__to_arg_t_enum() noexcept;
>
>        template<typename _Visitor>
> +       _GLIBCXX26_CONSTEXPR
>         decltype(auto)
>         _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
>         {
> @@ -4650,6 +4794,7 @@ namespace __format
>         }
>
>        template<typename _Visitor>
> +       _GLIBCXX26_CONSTEXPR
>         decltype(auto)
>         _M_visit_user(_Visitor&& __vis, __format::_Arg_t __type)
>         {
> @@ -4674,6 +4819,7 @@ namespace __format
>
>    template<typename _Visitor, typename _Context>
>      _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
> +    _GLIBCXX26_CONSTEXPR
>      inline decltype(auto)
>      visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
>      {
> @@ -4684,6 +4830,7 @@ namespace __format
>  namespace __format
>  {
>    template<typename _Visitor, typename _Ctx>
> +    _GLIBCXX26_CONSTEXPR
>      inline decltype(auto)
>      __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg)
>      {
> @@ -4693,6 +4840,7 @@ namespace __format
>    struct _WidthPrecVisitor
>    {
>      template<typename _Tp>
> +      _GLIBCXX26_CONSTEXPR
>        size_t
>        operator()(_Tp& __arg) const
>        {
> @@ -4719,6 +4867,7 @@ namespace __format
>  #pragma GCC diagnostic push
>  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
>    template<typename _Context>
> +    _GLIBCXX26_CONSTEXPR
>      inline size_t
>      __int_from_arg(const basic_format_arg<_Context>& __arg)
>      { return __format::__visit_format_arg(_WidthPrecVisitor(), __arg); }
> @@ -4767,10 +4916,12 @@ namespace __format
>         const _Format_arg* _M_args;       // Active when _M_packed_size ==
> 0
>        };
>
> +      _GLIBCXX26_CONSTEXPR
>        size_t
>        _M_size() const noexcept
>        { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
>
> +      _GLIBCXX26_CONSTEXPR
>        typename __format::_Arg_t
>        _M_type(size_t __i) const noexcept
>        {
> @@ -4779,6 +4930,7 @@ namespace __format
>        }
>
>        template<typename _Ctx, typename... _Args>
> +       _GLIBCXX26_CONSTEXPR
>         friend auto
>         make_format_args(_Args&...) noexcept;
>
> @@ -4790,9 +4942,11 @@ namespace __format
>
>      public:
>        template<typename... _Args>
> +       _GLIBCXX26_CONSTEXPR
>         basic_format_args(const _Store<_Args...>& __store) noexcept;
>
>        [[nodiscard,__gnu__::__always_inline__]]
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_arg<_Context>
>        get(size_t __i) const noexcept
>        {
> @@ -4815,6 +4969,7 @@ namespace __format
>        -> basic_format_args<_Context>;
>
>    template<typename _Context, typename... _Args>
> +    _GLIBCXX26_CONSTEXPR
>      auto
>      make_format_args(_Args&... __fmt_args) noexcept;
>
> @@ -4825,6 +4980,7 @@ namespace __format
>        friend std::basic_format_args<_Context>;
>
>        template<typename _Ctx, typename... _Argz>
> +       _GLIBCXX26_CONSTEXPR
>         friend auto std::
>  #if _GLIBCXX_INLINE_VERSION
>         __8:: // Needed for PR c++/59256
> @@ -4844,6 +5000,7 @@ namespace __format
>        _Element_t _M_args[sizeof...(_Args)];
>
>        template<typename _Tp>
> +       _GLIBCXX26_CONSTEXPR
>         static _Element_t
>         _S_make_elt(_Tp& __v)
>         {
> @@ -4870,6 +5027,7 @@ namespace __format
>        template<typename... _Tp>
>         requires (sizeof...(_Tp) == sizeof...(_Args))
>         [[__gnu__::__always_inline__]]
> +       _GLIBCXX26_CONSTEXPR
>         _Arg_store(_Tp&... __a) noexcept
>         : _M_args{_S_make_elt(__a)...}
>         { }
> @@ -4881,6 +5039,7 @@ namespace __format
>
>    template<typename _Context>
>      template<typename... _Args>
> +      _GLIBCXX26_CONSTEXPR
>        inline
>        basic_format_args<_Context>::
>        basic_format_args(const _Store<_Args...>& __store) noexcept
> @@ -4915,6 +5074,7 @@ namespace __format
>    /// Capture formatting arguments for use by `std::vformat`.
>    template<typename _Context = format_context, typename... _Args>
>      [[nodiscard,__gnu__::__always_inline__]]
> +    _GLIBCXX26_CONSTEXPR
>      inline auto
>      make_format_args(_Args&... __fmt_args) noexcept
>      {
> @@ -4928,6 +5088,7 @@ namespace __format
>    /// Capture formatting arguments for use by `std::vformat` (for wide
> output).
>    template<typename... _Args>
>      [[nodiscard,__gnu__::__always_inline__]]
> +    _GLIBCXX26_CONSTEXPR
>      inline auto
>      make_wformat_args(_Args&... __args) noexcept
>      { return std::make_format_args<wformat_context>(__args...); }
> @@ -4937,6 +5098,7 @@ namespace __format
>  namespace __format
>  {
>    template<typename _Out, typename _CharT, typename _Context>
> +    _GLIBCXX26_CONSTEXPR
>      _Out
>      __do_vformat_to(_Out, basic_string_view<_CharT>,
>                     const basic_format_args<_Context>&,
> @@ -4977,11 +5139,13 @@ namespace __format
>        _Out _M_out;
>        __format::_Optional_locale _M_loc;
>
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_context(basic_format_args<basic_format_context> __args,
>                            _Out __out)
>        : _M_args(__args), _M_out(std::move(__out))
>        { }
>
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_context(basic_format_args<basic_format_context> __args,
>                            _Out __out, const std::locale& __loc)
>        : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
> @@ -4994,6 +5158,7 @@ namespace __format
>        basic_format_context& operator=(const basic_format_context&) =
> delete;
>
>        template<typename _Out2, typename _CharT2, typename _Context2>
> +       _GLIBCXX26_CONSTEXPR
>         friend _Out2
>         __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
>                                   const basic_format_args<_Context2>&,
> @@ -5010,6 +5175,7 @@ namespace __format
>         using formatter_type = formatter<_Tp, _CharT>;
>
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        basic_format_arg<basic_format_context>
>        arg(size_t __id) const noexcept
>        { return _M_args.get(__id); }
> @@ -5018,8 +5184,10 @@ namespace __format
>        std::locale locale() { return _M_loc.value(); }
>
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        iterator out() { return std::move(_M_out); }
>
> +      _GLIBCXX26_CONSTEXPR
>        void advance_to(iterator __it) { _M_out = std::move(__it); }
>      };
>
> @@ -5159,6 +5327,7 @@ namespace __format
>      class _Formatting_scanner : public _Scanner<_CharT>
>      {
>      public:
> +      _GLIBCXX26_CONSTEXPR
>        _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
>                           basic_string_view<_CharT> __str)
>        : _Scanner<_CharT>(__str), _M_fc(__fc)
> @@ -5266,6 +5435,7 @@ namespace __format
>      };
>
>    template<typename _Out, typename _CharT, typename _Context>
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>                     const basic_format_args<_Context>& __args,
> @@ -5286,7 +5456,8 @@ namespace __format
>                       const char* __chars[] = { "false", "true" };
>                       if (auto __res = __out._M_reserve(__len))
>                         {
> -                         __builtin_memcpy(__res.get(), __chars[__arg],
> __len);
> +                         __format::__memcpy(__res.get(), __chars[__arg],
> +                                            __len);
>                           __res._M_bump(__len);
>                           __done = true;
>                         }
> @@ -5324,7 +5495,8 @@ namespace __format
>                       string_view __sv = __arg;
>                       if (auto __res = __out._M_reserve(__sv.size()))
>                         {
> -                         __builtin_memcpy(__res.get(), __sv.data(),
> __sv.size());
> +                         __format::__memcpy(__res.get(), __sv.data(),
> +                                            __sv.size());
>                           __res._M_bump(__sv.size());
>                           __done = true;
>                         }
> @@ -5342,18 +5514,18 @@ namespace __format
>           __scanner._M_scan();
>           return __out;
>         }
> -      else if constexpr (__contiguous_char_iter<_CharT, _Out>)
> -       {
> -         _Ptr_sink<_CharT> __sink(__out);
> -         __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> -         return std::move(__sink)._M_finish(__out).out;
> -       }
> -      else
> -       {
> -         _Iter_sink<_CharT, _Out> __sink(std::move(__out));
> -         __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> -         return std::move(__sink)._M_finish().out;
> -       }
> +      else if not consteval {
> +       if constexpr (__contiguous_char_iter<_CharT, _Out>)
> +         {
> +           _Ptr_sink<_CharT> __sink(__out);
> +           __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> +           return std::move(__sink)._M_finish(__out).out;
> +         }
> +      }
> +
> +      _Iter_sink<_CharT, _Out> __sink(std::move(__out));
> +      __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> +      return std::move(__sink)._M_finish().out;
>      }
>
>    template<typename _Out, typename _CharT>
> @@ -5397,7 +5569,9 @@ namespace __format
>         if constexpr (sizeof...(_Ts) != 0)
>           {
>             using _Parse_ctx = __format::_Scanner<_CharT>::_Parse_context;
> -           auto __arg = static_cast<_Parse_ctx*>(this)->_M_types[__id];
> +           auto* __ptr = static_cast<_Parse_ctx*>(this)->_M_types;
> +           if (!__ptr) return; // formatting scanner
> +           auto __arg = __ptr[__id];
>             __format::_Arg_t __types[] = {
>               __format::__to_arg_t_enum<_CharT, _Ts>()...
>             };
> @@ -5427,6 +5601,7 @@ namespace __format
>
>    template<typename _Out> requires output_iterator<_Out, const char&>
>      [[__gnu__::__always_inline__]]
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      vformat_to(_Out __out, string_view __fmt, format_args __args)
>      { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
> @@ -5434,6 +5609,7 @@ namespace __format
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    template<typename _Out> requires output_iterator<_Out, const wchar_t&>
>      [[__gnu__::__always_inline__]]
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
>      { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
> @@ -5460,6 +5636,7 @@ namespace __format
>  #endif
>
>    [[nodiscard]]
> +  _GLIBCXX26_CONSTEXPR
>    inline string
>    vformat(string_view __fmt, format_args __args)
>    {
> @@ -5470,6 +5647,7 @@ namespace __format
>
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    [[nodiscard]]
> +  _GLIBCXX26_CONSTEXPR
>    inline wstring
>    vformat(wstring_view __fmt, wformat_args __args)
>    {
> @@ -5501,6 +5679,7 @@ namespace __format
>
>    template<typename... _Args>
>      [[nodiscard]]
> +    _GLIBCXX26_CONSTEXPR
>      inline string
>      format(format_string<_Args...> __fmt, _Args&&... __args)
>      { return std::vformat(__fmt.get(), std::make_format_args(__args...));
> }
> @@ -5508,6 +5687,7 @@ namespace __format
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    template<typename... _Args>
>      [[nodiscard]]
> +    _GLIBCXX26_CONSTEXPR
>      inline wstring
>      format(wformat_string<_Args...> __fmt, _Args&&... __args)
>      { return std::vformat(__fmt.get(),
> std::make_wformat_args(__args...)); }
> @@ -5537,6 +5717,7 @@ namespace __format
>
>    template<typename _Out, typename... _Args>
>      requires output_iterator<_Out, const char&>
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      format_to(_Out __out, format_string<_Args...> __fmt, _Args&&...
> __args)
>      {
> @@ -5547,6 +5728,7 @@ namespace __format
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    template<typename _Out, typename... _Args>
>      requires output_iterator<_Out, const wchar_t&>
> +    _GLIBCXX26_CONSTEXPR
>      inline _Out
>      format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&...
> __args)
>      {
> @@ -5579,6 +5761,7 @@ namespace __format
>
>    template<typename _Out, typename... _Args>
>      requires output_iterator<_Out, const char&>
> +    _GLIBCXX26_CONSTEXPR
>      inline format_to_n_result<_Out>
>      format_to_n(_Out __out, iter_difference_t<_Out> __n,
>                 format_string<_Args...> __fmt, _Args&&... __args)
> @@ -5591,6 +5774,7 @@ namespace __format
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    template<typename _Out, typename... _Args>
>      requires output_iterator<_Out, const wchar_t&>
> +    _GLIBCXX26_CONSTEXPR
>      inline format_to_n_result<_Out>
>      format_to_n(_Out __out, iter_difference_t<_Out> __n,
>                 wformat_string<_Args...> __fmt, _Args&&... __args)
> @@ -5628,7 +5812,6 @@ namespace __format
>  /// @cond undocumented
>  namespace __format
>  {
> -#if 1
>    template<typename _CharT>
>      class _Counting_sink final : public _Ptr_sink<_CharT>
>      {
> @@ -5640,28 +5823,28 @@ namespace __format
>        count() const
>        { return this->_M_count + this->_M_used().size(); }
>      };
> -#else
> +
> +#ifdef __cpp_lib_constexpr_format // C++ >= 26
>    template<typename _CharT>
> -    class _Counting_sink : public _Buf_sink<_CharT>
> +    class _Counting_constexpr_sink : public _Buf_sink<_CharT>
>      {
>        size_t _M_count = 0;
>
> -      void
> +      constexpr void
>        _M_overflow() override
>        {
> -       if (!std::is_constant_evaluated())
> -         _M_count += this->_M_used().size();
> +       _M_count += this->_M_used().size();
>         this->_M_rewind();
>        }
>
>      public:
> -      _Counting_sink() = default;
> +      _Counting_constexpr_sink() = default;
>
>        [[__gnu__::__always_inline__]]
> -      size_t
> +      constexpr size_t
>        count() noexcept
>        {
> -       _Counting_sink::_M_overflow();
> +       _Counting_constexpr_sink::_M_overflow();
>         return _M_count;
>        }
>      };
> @@ -5671,25 +5854,50 @@ namespace __format
>
>    template<typename... _Args>
>      [[nodiscard]]
> +    _GLIBCXX26_CONSTEXPR
>      inline size_t
>      formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
>      {
> -      __format::_Counting_sink<char> __buf;
> -      std::vformat_to(__buf.out(), __fmt.get(),
> -                     std::make_format_args(__args...));
> -      return __buf.count();
> +#ifdef __cpp_lib_constexpr_format // C++ >= 26
> +      if consteval
> +       {
> +         __format::_Counting_constexpr_sink<char> __buf;
> +         std::vformat_to(__buf.out(), __fmt.get(),
> +                         std::make_format_args(__args...));
> +         return __buf.count();
> +      } else
> +#endif
> +       {
> +         __format::_Counting_sink<char> __buf;
> +         std::vformat_to(__buf.out(), __fmt.get(),
> +                         std::make_format_args(__args...));
> +         return __buf.count();
> +       }
>      }
>
>  #ifdef _GLIBCXX_USE_WCHAR_T
>    template<typename... _Args>
>      [[nodiscard]]
> +    _GLIBCXX26_CONSTEXPR
>      inline size_t
>      formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
>      {
> -      __format::_Counting_sink<wchar_t> __buf;
> -      std::vformat_to(__buf.out(), __fmt.get(),
> -                     std::make_wformat_args(__args...));
> -      return __buf.count();
> +#ifdef __cpp_lib_constexpr_format // C++ >= 26
> +      if consteval
> +       {
> +         __format::_Counting_constexpr_sink<wchar_t> __buf;
> +         std::vformat_to(__buf.out(), __fmt.get(),
> +                         std::make_wformat_args(__args...));
> +         return __buf.count();
> +       }
> +      else
> +#endif
> +       {
> +         __format::_Counting_sink<wchar_t> __buf;
> +         std::vformat_to(__buf.out(), __fmt.get(),
> +                         std::make_wformat_args(__args...));
> +         return __buf.count();
> +       }
>      }
>  #endif
>
> @@ -5754,6 +5962,7 @@ namespace __format
>  namespace __format
>  {
>    template<typename _CharT, typename _Out, typename _Callback>
> +    _GLIBCXX26_CONSTEXPR
>      typename basic_format_context<_Out, _CharT>::iterator
>      __format_padded(basic_format_context<_Out, _CharT>& __fc,
>                     const _Spec<_CharT>& __spec,
> @@ -5773,14 +5982,17 @@ namespace __format
>
>           struct _Restore_out
>           {
> +          _GLIBCXX26_CONSTEXPR
>            _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>&
> __fc)
>            : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
>           { }
>
> +          _GLIBCXX26_CONSTEXPR
>           void
>           _M_disarm()
>           { _M_ctx = nullptr; }
>
> +          _GLIBCXX26_CONSTEXPR
>           ~_Restore_out()
>           {
>             if (_M_ctx)
> @@ -5814,6 +6026,7 @@ namespace __format
>        }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         void
>         _M_format(__maybe_const<_Tp, _CharT>& __elem,
>                   basic_format_context<_Out, _CharT>& __fc,
> @@ -5912,12 +6125,14 @@ namespace __format
>
>      protected:
>        template<typename _Tuple, typename _Out, size_t... _Ids>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format(_Tuple& __tuple, index_sequence<_Ids...>,
>                   basic_format_context<_Out, _CharT>& __fc) const
>         { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); }
>
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems,
>                         basic_format_context<_Out, _CharT>& __fc) const
> @@ -5947,6 +6162,7 @@ namespace __format
>           }
>
>           template<typename _Out>
> +           _GLIBCXX26_CONSTEXPR
>             void
>             _M_format(__maybe_const<_Tps, _CharT>&... __elems,
>                       basic_format_context<_Out, _CharT>& __fc,
> @@ -5963,6 +6179,7 @@ namespace __format
>         };
>
>        template<size_t... _Ids>
> +       _GLIBCXX26_CONSTEXPR
>         static auto
>         _S_create_storage(index_sequence<_Ids...>)
>           -> __formatters_storage<_Ids...>;
> @@ -5999,6 +6216,7 @@ namespace __format
>        // We deviate from standard, that declares this as template
> accepting
>        // unconstrained FormatContext type, which seems unimplementable.
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(__maybe_const_pair& __p,
>                basic_format_context<_Out, _CharT>& __fc) const
> @@ -6026,6 +6244,7 @@ namespace __format
>        // We deviate from standard, that declares this as template
> accepting
>        // unconstrained FormatContext type, which seems unimplementable.
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(__maybe_const_tuple& __t,
>                basic_format_context<_Out, _CharT>& __fc) const
> @@ -6189,6 +6408,7 @@ namespace __format
>        template<ranges::input_range _Rg, typename _Out>
>         requires formattable<ranges::range_reference_t<_Rg>, _CharT> &&
>                  same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
> _Tp>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
>         {
> @@ -6201,6 +6421,7 @@ namespace __format
>
>      private:
>        template<ranges::input_range _Rg, typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc)
> const
>         {
> @@ -6218,6 +6439,7 @@ namespace __format
>
>
>        template<ranges::input_range _Rg, typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         _M_format_elems(_Rg& __rg,
>                         basic_format_context<_Out, _CharT>& __fc) const
> @@ -6317,6 +6539,7 @@ namespace __format
>        // We deviate from standard, that declares this as template
> accepting
>        // unconstrained FormatContext type, which seems unimplementable.
>        template<typename _Out>
> +       _GLIBCXX26_CONSTEXPR
>         typename basic_format_context<_Out, _CharT>::iterator
>         format(__format::__maybe_const_range<_Rg, _CharT>& __rg,
>                basic_format_context<_Out, _CharT>& __fc) const
> diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc
> b/libstdc++-v3/testsuite/std/format/functions/format.cc
> index d342114083e..20171279764 100644
> --- a/libstdc++-v3/testsuite/std/format/functions/format.cc
> +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
> @@ -1,5 +1,5 @@
>  // { dg-options "-fexec-charset=UTF-8" }
> -// { dg-do run { target c++20 } }
> +// { dg-do run { target c++26 } }
>  // { dg-add-options no_pch }
>  // { dg-additional-options "-DUNICODE" { target 4byte_wchar_t } }
>
> @@ -41,7 +41,7 @@
>  #include <cstdio>
>  #include <testsuite_hooks.h>
>
> -void
> +constexpr void
>  test_no_args()
>  {
>    std::string s;
> @@ -55,6 +55,7 @@ test_no_args()
>    VERIFY( s == "128bpm }" );
>  }
>
> +// not constexpr because of PR124145
>  void
>  test_unescaped()
>  {
> @@ -78,7 +79,7 @@ struct brit_punc : std::numpunct<char>
>    std::string do_falsename() const override { return "nah bruv"; }
>  };
>
> -void
> +constexpr void
>  test_std_examples()
>  {
>    using namespace std;
> @@ -125,10 +126,12 @@ test_std_examples()
>      VERIFY(s0 == "1,+1,1, 1");
>      string s1 = format("{0:},{0:+},{0:-},{0: }", -1);
>      VERIFY(s1 == "-1,-1,-1,-1");
> -    string s2 = format("{0:},{0:+},{0:-},{0: }", inf);
> -    VERIFY(s2 == "inf,+inf,inf, inf");
> -    string s3 = format("{0:},{0:+},{0:-},{0: }", nan);
> -    VERIFY(s3 == "nan,+nan,nan, nan");
> +    if not consteval {
> +      string s2 = format("{0:},{0:+},{0:-},{0: }", inf);
> +      VERIFY(s2 == "inf,+inf,inf, inf");
> +      string s3 = format("{0:},{0:+},{0:-},{0: }", nan);
> +      VERIFY(s3 == "nan,+nan,nan, nan");
> +    }
>    }
>
>    // alternate form and zero fill
> @@ -143,7 +146,7 @@ test_std_examples()
>    }
>
>    // integer presentation types
> -  {
> +  if not consteval {
>      // Change global locale so "{:L}" adds digit separators.
>      std::locale::global(std::locale({}, new brit_punc));
>
> @@ -170,7 +173,7 @@ test_std_examples()
>    }
>  }
>
> -void
> +constexpr void
>  test_alternate_forms()
>  {
>    std::string s;
> @@ -180,23 +183,25 @@ test_alternate_forms()
>    s = std::format("{0:#b} {0:+#B} {0:#o} {0:#x} {0:+#X} {0: #d}", 0);
>    VERIFY( s == "0b0 +0B0 0 0x0 +0X0  0" );
>
> -  s = std::format("{0:+#012g} {0:+#014g} {0:+#014g}", 1234.0);
> -  VERIFY( s == "+00001234.00 +0000001234.00 +0000001234.00" );
> -  s = std::format("{0:+#0{1}g} {0:+#0{2}g} {0:+#0{2}g}", 1234.5, 12, 14);
> -  VERIFY( s == "+00001234.50 +0000001234.50 +0000001234.50" );
> +  if not consteval {
> +    s = std::format("{0:+#012g} {0:+#014g} {0:+#014g}", 1234.0);
> +    VERIFY( s == "+00001234.00 +0000001234.00 +0000001234.00" );
> +    s = std::format("{0:+#0{1}g} {0:+#0{2}g} {0:+#0{2}g}", 1234.5, 12,
> 14);
> +    VERIFY( s == "+00001234.50 +0000001234.50 +0000001234.50" );
>
> -  s = std::format("{:#.2g}", -0.0);
> -  VERIFY( s == "-0.0" );
> +    s = std::format("{:#.2g}", -0.0);
> +    VERIFY( s == "-0.0" );
>
> -  // PR libstdc++/108046
> -  s = std::format("{0:#.0} {0:#.1} {0:#.0g}", 10.0);
> -  VERIFY( s == "1.e+01 1.e+01 1.e+01" );
> +    // PR libstdc++/108046
> +    s = std::format("{0:#.0} {0:#.1} {0:#.0g}", 10.0);
> +    VERIFY( s == "1.e+01 1.e+01 1.e+01" );
>
> -  // PR libstdc++/113512
> -  s = std::format("{:#.3g}", 0.025);
> -  VERIFY( s == "0.0250" );
> -  s = std::format("{:#07.3g}", 0.02);
> -  VERIFY( s == "00.0200" );
> +    // PR libstdc++/113512
> +    s = std::format("{:#.3g}", 0.025);
> +    VERIFY( s == "0.0250" );
> +    s = std::format("{:#07.3g}", 0.02);
> +    VERIFY( s == "00.0200" );
> +  }
>  }
>
>  void
> @@ -275,7 +280,7 @@ test_locale()
>    std::locale::global(cloc);
>  }
>
> -void
> +constexpr void
>  test_width()
>  {
>    std::string s;
> @@ -294,30 +299,33 @@ test_width()
>    s = std::format("DR {0:{1}}: allow width {1} from arg-id", 3721, 0);
>    VERIFY( s == "DR 3721: allow width 0 from arg-id" );
>
> -  try {
> -    s = std::format("Negative width is an error: {0:{1}}", 123, -1);
> -    VERIFY(false);
> -  } catch (const std::format_error&) {
> -  }
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    try {
> +      s = std::format("Negative width is an error: {0:{1}}", 123, -1);
> +      VERIFY(false);
> +    } catch (const std::format_error&) {
> +    }
>
> -  try {
> -    bool no = false, yes = true;
> -    auto args = std::make_format_args(no, yes);
> -    s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}",
> args);
> -    VERIFY(false);
> -  } catch (const std::format_error&) {
> -  }
> +    try {
> +      bool no = false, yes = true;
> +      auto args = std::make_format_args(no, yes);
> +      s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}",
> args);
> +      VERIFY(false);
> +    } catch (const std::format_error&) {
> +    }
>
> -  try {
> -    char wat = '?', bang = '!';
> -    auto args = std::make_format_args(wat, bang);
> -    s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}",
> args);
> -    VERIFY(false);
> -  } catch (const std::format_error&) {
> +    try {
> +      char wat = '?', bang = '!';
> +      auto args = std::make_format_args(wat, bang);
> +      s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}",
> args);
> +      VERIFY(false);
> +    } catch (const std::format_error&) {
> +    }
>    }
>  }
>
> -void
> +constexpr void
>  test_char()
>  {
>    std::string s;
> @@ -347,6 +355,7 @@ test_char()
>    VERIFY( s == "11110000 11110000 240 360 f0 F0" );
>  }
>
> +// constexpr wide formatting not yet implemented
>  void
>  test_wchar()
>  {
> @@ -395,7 +404,7 @@ test_wchar()
>    VERIFY( ws == L"0.5" );
>  }
>
> -void
> +constexpr void
>  test_minmax()
>  {
>    auto check = []<typename T, typename U = std::make_unsigned_t<T>>(T, U
> = 0) {
> @@ -422,7 +431,7 @@ test_minmax()
>  #endif
>  }
>
> -void
> +constexpr void
>  test_p1652r1() // printf corner cases in std::format
>  {
>    std::string s;
> @@ -436,27 +445,31 @@ test_p1652r1() // printf corner cases in std::format
>    s = std::format("{:c}", c);
>    VERIFY( s == "A" );
>
> -  // Problem 3: "-000nan" is not a floating point value
> -  double nan = std::numeric_limits<double>::quiet_NaN();
> -  try {
> -    s = std::vformat("{:0=6}", std::make_format_args(nan));
> -    VERIFY( false );
> -  } catch (const std::format_error&) {
> +  if not consteval {
> +    // Problem 3: "-000nan" is not a floating point value
> +    double nan = std::numeric_limits<double>::quiet_NaN();
> +    try {
> +      s = std::vformat("{:0=6}", std::make_format_args(nan));
> +      VERIFY( false );
> +    } catch (const std::format_error&) {
> +    }
> +
> +    s = std::format("{:06}", nan);
> +    VERIFY( s == "   nan" );
>    }
>
> -  s = std::format("{:06}", nan);
> -  VERIFY( s == "   nan" );
> -
>    // Problem 4: bool needs a type format specifier
>    s = std::format("{:s}", true);
>    VERIFY( s == "true" );
>
> -  // Problem 5: double does not roundtrip float
> -  s = std::format("{}", 3.31f);
> -  VERIFY( s == "3.31" );
> +  if not consteval {
> +    // Problem 5: double does not roundtrip float
> +    s = std::format("{}", 3.31f);
> +    VERIFY( s == "3.31" );
> +  }
>  }
>
> -void
> +constexpr void
>  test_pointer()
>  {
>    void* p = nullptr;
> @@ -477,28 +490,30 @@ test_pointer()
>    s = std::format("{:o<4},{:o>5},{:o^7}", p, pc, nullptr); //
> fill+align+width
>    VERIFY( s == "0x0o,oo0x0,oo0x0oo" );
>
> -  pc = p = &s;
> -  str_int = std::format("{:#x}", reinterpret_cast<std::uintptr_t>(p));
> -  s = std::format("{} {} {}", p, pc, nullptr);
> -  VERIFY( s == (str_int + ' ' + str_int + " 0x0") );
> -  str_int = std::format("{:#20x}", reinterpret_cast<std::uintptr_t>(p));
> -  s = std::format("{:20} {:20p}", p, pc);
> -  VERIFY( s == (str_int + ' ' + str_int) );
> +  if not consteval {
> +    pc = p = &s;
> +    str_int = std::format("{:#x}", reinterpret_cast<std::uintptr_t>(p));
> +    s = std::format("{} {} {}", p, pc, nullptr);
> +    VERIFY( s == (str_int + ' ' + str_int + " 0x0") );
> +    str_int = std::format("{:#20x}", reinterpret_cast<std::uintptr_t>(p));
> +    s = std::format("{:20} {:20p}", p, pc);
> +    VERIFY( s == (str_int + ' ' + str_int) );
>
>  #if __cpp_lib_format >= 202304L
> -  // P2510R3 Formatting pointers
> -  s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0,
> nullptr);
> -  VERIFY( s == "0x0000 0X00000 0x000000" );
> -  str_int = std::format("{:#016x}", reinterpret_cast<std::uintptr_t>(p));
> -  s = std::format("{:016} {:016}", p, pc);
> -  VERIFY( s == (str_int + ' ' + str_int) );
> -  str_int = std::format("{:#016X}", reinterpret_cast<std::uintptr_t>(p));
> -  s = std::format("{:016P} {:016P}", p, pc);
> -  VERIFY( s == (str_int + ' ' + str_int) );
> +    // P2510R3 Formatting pointers
> +    s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0,
> nullptr);
> +    VERIFY( s == "0x0000 0X00000 0x000000" );
> +    str_int = std::format("{:#016x}",
> reinterpret_cast<std::uintptr_t>(p));
> +    s = std::format("{:016} {:016}", p, pc);
> +    VERIFY( s == (str_int + ' ' + str_int) );
> +    str_int = std::format("{:#016X}",
> reinterpret_cast<std::uintptr_t>(p));
> +    s = std::format("{:016P} {:016P}", p, pc);
> +    VERIFY( s == (str_int + ' ' + str_int) );
>  #endif
> +  }
>  }
>
> -void
> +constexpr void
>  test_bool()
>  {
>    std::string s;
> @@ -519,7 +534,7 @@ test_bool()
>    VERIFY( s == "0 0x1 0X0" );
>  }
>
> -void
> +constexpr void
>  test_unicode()
>  {
>  #ifdef UNICODE
> @@ -579,19 +594,35 @@ test_unicode()
>  #endif
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
>    test_no_args();
> -  test_unescaped();
>    test_std_examples();
>    test_alternate_forms();
> -  test_locale();
>    test_width();
>    test_char();
> -  test_wchar();
>    test_minmax();
>    test_p1652r1();
>    test_pointer();
>    test_bool();
>    test_unicode();
> +
> +  if not consteval {
> +    test_unescaped();
> +    test_infnan();
> +    test_locale();
> +    test_wchar();
> +  }
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> diff --git a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> index 94e6262bc66..df277e59be1 100644
> --- a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> +++ b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> @@ -1,4 +1,4 @@
> -// { dg-do run { target c++20 } }
> +// { dg-do run { target c++26 } }
>
>  #include <format>
>  #include <locale>
> @@ -11,17 +11,19 @@ struct punct : std::numpunct<char>
>    std::string do_grouping() const override { return "\2"; }
>  };
>
> -void
> +constexpr void
>  test()
>  {
>    char buf[32] = { };
>    auto out = std::format_to(buf, "test");
>    VERIFY( out == buf+4 );
>
> -  std::locale loc({}, new punct);
> -  auto out2 = std::format_to(buf, loc, "{:Ld}", 12345);
> -  VERIFY( out2 == buf+7 );
> -  VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" );
> +  if not consteval {
> +    std::locale loc({}, new punct);
> +    auto out2 = std::format_to(buf, loc, "{:Ld}", 12345);
> +    VERIFY( out2 == buf+7 );
> +    VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" );
> +  }
>  }
>
>  struct wpunct : std::numpunct<wchar_t>
> @@ -29,6 +31,7 @@ struct wpunct : std::numpunct<wchar_t>
>    std::string do_grouping() const override { return "\2"; }
>  };
>
> +// constexpr wide formatting not yet implemented
>  void
>  test_wchar()
>  {
> @@ -50,20 +53,20 @@ struct move_only_iterator
>    using difference_type = iterator::difference_type;
>    using iterator_category = std::output_iterator_tag;
>
> -  move_only_iterator(iterator b) : base_(b) { }
> +  constexpr move_only_iterator(iterator b) : base_(b) { }
>    move_only_iterator(move_only_iterator&&) = default;
>    move_only_iterator& operator=(move_only_iterator&&) = default;
>
> -  move_only_iterator& operator++() { ++base_; return *this; }
> -  move_only_iterator operator++(int) { auto tmp = *this; ++base_; return
> tmp; }
> +  constexpr move_only_iterator& operator++() { ++base_; return *this; }
> +  constexpr move_only_iterator operator++(int) { auto tmp = *this;
> ++base_; return tmp; }
>
> -  decltype(auto) operator*() { return *base_; }
> +  constexpr decltype(auto) operator*() { return *base_; }
>
>  private:
>    iterator base_;
>  };
>
> -void
> +constexpr void
>  test_move_only()
>  {
>    std::string str;
> @@ -72,14 +75,16 @@ test_move_only()
>      = std::format_to(std::move(mo), "for{:.3} that{:c}", "matte",
> (int)'!');
>    VERIFY( str == "format that!" );
>
> -  std::vector<wchar_t> vec;
> -  move_only_iterator wmo(std::back_inserter(vec));
> -  [[maybe_unused]] auto wres
> -    = std::format_to(std::move(wmo), L"for{:.3} hat{:c}", L"matte",
> (long)L'!');
> -  VERIFY( std::wstring_view(vec.data(), vec.size()) == L"format hat!" );
> +  if not consteval {
> +    std::vector<wchar_t> vec;
> +    move_only_iterator wmo(std::back_inserter(vec));
> +    [[maybe_unused]] auto wres
> +      = std::format_to(std::move(wmo), L"for{:.3} hat{:c}", L"matte",
> (long)L'!');
> +    VERIFY( std::wstring_view(vec.data(), vec.size()) == L"format hat!" );
> +  }
>  }
>
> -void
> +constexpr void
>  test_pr110917()
>  {
>    // PR libstdc++/110917
> @@ -90,10 +95,25 @@ test_pr110917()
>    VERIFY( ! std::memcmp(buf, "abc 123", 7) );
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
>    test();
> -  test_wchar();
>    test_move_only();
>    test_pr110917();
> +
> +  if not consteval {
> +    test_wchar();
> +  }
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> index 1450fbaebc5..0f717fb025e 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> @@ -1,4 +1,4 @@
> -// { dg-do run { target c++23 } }
> +// { dg-do run { target c++26 } }
>
>  #include <deque>
>  #include <flat_map>
> @@ -64,7 +64,8 @@ struct CustFormat : std::vector<T>
>  template<typename T, std::range_format rf>
>  constexpr auto std::format_kind<CustFormat<T, rf>> = rf;
>
> -void test_override()
> +constexpr bool
> +test_override()
>  {
>    CustFormat<int, std::range_format::disabled> disabledf;
>    static_assert( !std::formattable<decltype(disabledf), char> );
> @@ -88,8 +89,14 @@ void test_override()
>    VERIFY( std::format("{}", debugf) == R"("abcd")" );
>    // Support precision as string do
>    VERIFY( std::format("{:.3}", debugf) == R"("ab)" );
> +
> +  return true;
>  }
>
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(test_override());
> +#endif
> +
>  int main()
>  {
>    test_override();
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> index a50c5b1033f..d4ada07194d 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> @@ -1,4 +1,4 @@
> -// { dg-do run { target c++23 } }
> +// { dg-do run { target c++26 } }
>
>  #include <flat_map>
>  #include <format>
> @@ -32,7 +32,7 @@ struct std::formatter<MyVector<T, Formatter>, CharT>
>    { return _formatter.parse(pc);  }
>
>    template<typename Out>
> -  typename std::basic_format_context<Out, CharT>::iterator
> +  constexpr std::basic_format_context<Out, CharT>::iterator
>    format(const MyVector<T, Formatter>& mv,
>          std::basic_format_context<Out, CharT>& fc) const
>    { return _formatter.format(mv, fc); }
> @@ -42,7 +42,7 @@ private:
>  };
>
>  template<typename CharT, template<typename, typename> class Formatter>
> -void
> +constexpr void
>  test_default()
>  {
>    MyVector<int, Formatter> vec{1, 2, 3};
> @@ -94,7 +94,7 @@ test_default()
>  }
>
>  template<typename CharT, template<typename, typename> class Formatter>
> -void
> +constexpr void
>  test_override()
>  {
>    MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
> @@ -115,15 +115,19 @@ test_override()
>  }
>
>  template<template<typename, typename> class Formatter>
> -void test_outputs()
> +constexpr void
> +test_outputs()
>  {
>    test_default<char, Formatter>();
> -  test_default<wchar_t, Formatter>();
>    test_override<char, Formatter>();
> -  test_override<wchar_t, Formatter>();
> +  // constexpr wide formatting not yet implemented
> +  if not consteval {
> +    test_default<wchar_t, Formatter>();
> +    test_override<wchar_t, Formatter>();
> +  }
>  }
>
> -void
> +constexpr void
>  test_nested()
>  {
>    MyVector<MyVector<int>> v
> @@ -152,7 +156,8 @@ struct std::formatter<MyFlatMap, CharT>
>    : std::range_formatter<MyFlatMap::reference>
>  {};
>
> -void test_const_ref_type_mismatch()
> +constexpr void
> +test_const_ref_type_mismatch()
>  {
>    MyFlatMap m{{1, 11}, {2, 22}};
>    std::string res = std::format("{:m}", m);
> @@ -163,13 +168,15 @@ template<typename T, typename CharT>
>  using VectorFormatter = std::formatter<std::vector<T>, CharT>;
>
>  template<template<typename> typename Range>
> -void test_nonblocking()
> +constexpr void
> +test_nonblocking()
>  {
>    static_assert(!std::enable_nonlocking_formatter_optimization<
>                   Range<int>>);
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
>    test_outputs<std::range_formatter>();
>    test_outputs<VectorFormatter>();
> @@ -179,4 +186,15 @@ int main()
>    test_nonblocking<std::span>();
>    test_nonblocking<std::vector>();
>    test_nonblocking<MyVector>();
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> index 7fb65f9c551..18228d14b5f 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> @@ -1,5 +1,5 @@
> -// { dg-do run { target c++23 } }
> -// { dg-options "-fexec-charset=UTF-8" }
> +// { dg-do run { target c++26 } }
> +// { dg-options "-fexec-charset=UTF-8 -fconstexpr-ops-limit=5000000000" }
>  // { dg-timeout-factor 2 }
>
>  #include <array>
> @@ -19,7 +19,7 @@
> static_assert(!std::formattable<std::vector<NotFormattable>, char>);
>  static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>);
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const char* str, Args&&... args)
>  {
>    try {
> @@ -31,7 +31,7 @@ is_format_string_for(const char* str, Args&&... args)
>  }
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const wchar_t* str, Args&&... args)
>  {
>    try {
> @@ -43,7 +43,8 @@ is_format_string_for(const wchar_t* str, Args&&... args)
>  }
>
>  template<typename Rg, typename CharT>
> -bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
> +constexpr bool
> +is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
>  {
>    using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
>    std::range_formatter<V, CharT> fmt;
> @@ -56,6 +57,7 @@ bool is_range_formatter_spec_for(CharT const* spec, Rg&&
> rg)
>    }
>  }
>
> +// not constexpr because of PR124145
>  void
>  test_format_string()
>  {
> @@ -79,7 +81,8 @@ test_format_string()
>  #define WIDEN(S) WIDEN_(CharT, S)
>
>  template<typename CharT, typename Range, typename Storage>
> -void test_output()
> +constexpr void
> +test_output()
>  {
>    using Sv = std::basic_string_view<CharT>;
>    using T = std::ranges::range_value_t<Range>;
> @@ -153,25 +156,35 @@ void test_output()
>  }
>
>  template<typename Cont>
> -void test_output_cont()
> +constexpr void
> +test_output_cont()
>  {
>    test_output<char, Cont&, Cont>();
> -  test_output<wchar_t, Cont const&, Cont>();
> +  if not consteval {
> +    test_output<wchar_t, Cont const&, Cont>();
> +  }
>  }
>
>  template<typename View>
> -void test_output_view()
> +constexpr void
> +test_output_view()
>  {
>    test_output<char, View, int[3]>();
> -  test_output<wchar_t, View, int[3]>();
> +  if not consteval {
> +    test_output<wchar_t, View, int[3]>();
> +  }
>  }
>
> -void
> +constexpr void
>  test_outputs()
>  {
>    using namespace __gnu_test;
>    test_output_cont<std::vector<int>>();
> -  test_output_cont<std::list<int>>();
> +
> +  if not consteval {
> +    test_output_cont<std::list<int>>();
> +  }
> +
>    test_output_cont<std::array<int, 3>>();
>
>    test_output_view<std::span<int>>();
> @@ -185,7 +198,7 @@ test_outputs()
>    test_output_view<test_forward_range<const int>>();
>  }
>
> -void
> +constexpr void
>  test_nested()
>  {
>    std::vector<std::vector<int>> v
> @@ -201,7 +214,8 @@ test_nested()
>    VERIFY( res == "+[01, 02, 11, 12]+" );
>  }
>
> -bool strip_quote(std::string_view& v)
> +constexpr bool
> +strip_quote(std::string_view& v)
>  {
>    if (!v.starts_with('"'))
>      return false;
> @@ -209,7 +223,8 @@ bool strip_quote(std::string_view& v)
>    return true;
>  }
>
> -bool strip_prefix(std::string_view& v, std::string_view expected, bool
> quoted = false)
> +constexpr bool
> +strip_prefix(std::string_view& v, std::string_view expected, bool quoted
> = false)
>  {
>    if (quoted && !strip_quote(v))
>      return false;
> @@ -221,7 +236,8 @@ bool strip_prefix(std::string_view& v,
> std::string_view expected, bool quoted =
>    return true;
>  }
>
> -bool strip_squares(std::string_view& v)
> +constexpr bool
> +strip_squares(std::string_view& v)
>  {
>    if (!v.starts_with('[') || !v.ends_with(']'))
>      return false;
> @@ -230,7 +246,8 @@ bool strip_squares(std::string_view& v)
>    return true;
>  }
>
> -bool strip_prefix(std::string_view& v, size_t n, char c)
> +constexpr bool
> +strip_prefix(std::string_view& v, size_t n, char c)
>  {
>    size_t pos = v.find_first_not_of(c);
>    if (pos == std::string_view::npos)
> @@ -241,7 +258,8 @@ bool strip_prefix(std::string_view& v, size_t n, char
> c)
>    return true;
>  }
>
> -void test_padding()
> +constexpr void
> +test_padding()
>  {
>    std::string res;
>    std::string_view resv;
> @@ -323,10 +341,25 @@ void test_padding()
>    VERIFY( check_elems(resv, false) );
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
> -  test_format_string();
>    test_outputs();
>    test_nested();
>    test_padding();
> +
> +  if not consteval {
> +    test_format_string();
> +  }
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> diff --git a/libstdc++-v3/testsuite/std/format/string.cc
> b/libstdc++-v3/testsuite/std/format/string.cc
> index ee987a15ec3..024ed29f584 100644
> --- a/libstdc++-v3/testsuite/std/format/string.cc
> +++ b/libstdc++-v3/testsuite/std/format/string.cc
> @@ -1,10 +1,10 @@
> -// { dg-do run { target c++20 } }
> +// { dg-do run { target c++26 } }
>
>  #include <format>
>  #include <testsuite_hooks.h>
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const char* str, Args&&... args)
>  {
>    try {
> @@ -16,7 +16,7 @@ is_format_string_for(const char* str, Args&&... args)
>  }
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const wchar_t* str, Args&&... args)
>  {
>    try {
> @@ -27,28 +27,35 @@ is_format_string_for(const wchar_t* str, Args&&...
> args)
>    }
>  }
>
> -void
> +constexpr void
>  test_no_args()
>  {
>    VERIFY( is_format_string_for("") );
>    VERIFY( is_format_string_for("chars") );
>    VERIFY( is_format_string_for(" The Great Escape {{}} ") );
>
> -  VERIFY( ! is_format_string_for("{") );
> -  VERIFY( ! is_format_string_for("}") );
> -  VERIFY( ! is_format_string_for("}{") );
> -  VERIFY( ! is_format_string_for("{{}") );
> -  VERIFY( ! is_format_string_for("{{{") );
> -  VERIFY( ! is_format_string_for("{{{{{") );
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    VERIFY( ! is_format_string_for("{") );
> +    VERIFY( ! is_format_string_for("}") );
> +    VERIFY( ! is_format_string_for("}{") );
> +    VERIFY( ! is_format_string_for("{{}") );
> +    VERIFY( ! is_format_string_for("{{{") );
> +    VERIFY( ! is_format_string_for("{{{{{") );
> +  }
>  }
>
> -void
> +constexpr void
>  test_indexing()
>  {
>    VERIFY( is_format_string_for("{} to {}", "a", "b") );   // automatic
> indexing
>    VERIFY( is_format_string_for("{1} to {0}", "a", "b") ); // manual
> indexing
> -  VERIFY( ! is_format_string_for("{0} to {}", "a", "b") );  // mixed
> indexing
> -  VERIFY( ! is_format_string_for("{} to {1}", "a", "b") );  // mixed
> indexing
> +
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    VERIFY( ! is_format_string_for("{0} to {}", "a", "b") );  // mixed
> indexing
> +    VERIFY( ! is_format_string_for("{} to {1}", "a", "b") );  // mixed
> indexing
> +  }
>
>    VERIFY( is_format_string_for("{} {} {}", 1, 2, 3) );
>    VERIFY( is_format_string_for("{} {} {}", 1, 2, 3, 4) );
> @@ -56,10 +63,13 @@ test_indexing()
>    VERIFY( is_format_string_for("{1} {2} {3}", 1, 2, 3, 4) );
>    VERIFY( is_format_string_for("{3} {3} {3}", 1, 2, 3, 4) );
>
> -  VERIFY( ! is_format_string_for("{2}", 1, 2) );
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    VERIFY( ! is_format_string_for("{2}", 1, 2) );
>
> -  VERIFY( ! is_format_string_for("{0} {}", 1) );
> -  VERIFY( ! is_format_string_for("{} {0}", 1) );
> +    VERIFY( ! is_format_string_for("{0} {}", 1) );
> +    VERIFY( ! is_format_string_for("{} {0}", 1) );
> +  }
>  }
>
>  #if __cpp_lib_format_ranges
> @@ -68,7 +78,7 @@ constexpr bool escaped_strings_supported = true;
>  constexpr bool escaped_strings_supported = false;
>  #endif
>
> -void
> +constexpr void
>  test_format_spec()
>  {
>    VERIFY( is_format_string_for("{:}", 1) );
> @@ -78,92 +88,110 @@ test_format_spec()
>    VERIFY( is_format_string_for("{0:} {0:c}", 'c') );
>    VERIFY( is_format_string_for("{0:p} {0:}", nullptr) );
>    VERIFY( is_format_string_for("{:d} {:+d}", true, true) );
> -  VERIFY( is_format_string_for("{:0<-#03Ld}", 1) );
> -  VERIFY( is_format_string_for("{1:0<-#03.4Lf}", 1, 2.3) );
> -  VERIFY( is_format_string_for("{1:3.3f}", 1, 2.3) );
> +
> +  if not consteval {
> +    VERIFY( is_format_string_for("{:0<-#03Ld}", 1) );
> +    VERIFY( is_format_string_for("{1:0<-#03.4Lf}", 1, 2.3) );
> +    VERIFY( is_format_string_for("{1:3.3f}", 1, 2.3) );
> +  }
> +
>    VERIFY( is_format_string_for("{:#d}", 'c') );
>    VERIFY( is_format_string_for("{:#d}", true) );
>    VERIFY( is_format_string_for("{0:s} {0:?}", "str") ==
> escaped_strings_supported );
>    VERIFY( is_format_string_for("{0:} {0:?}", 'c') ==
> escaped_strings_supported );
>
> -  // Invalid sign options.
> -  VERIFY( ! is_format_string_for("{:+}", "str") );
> -  VERIFY( ! is_format_string_for("{:+s}", "str") );
> -  VERIFY( ! is_format_string_for("{:+}", 'c') );
> -  VERIFY( ! is_format_string_for("{:+c}", 'c') );
> -  VERIFY( ! is_format_string_for("{:+p}", nullptr) );
> -  VERIFY( ! is_format_string_for("{:+}", true) );
> -  VERIFY( ! is_format_string_for("{:+s}", true) );
> -  VERIFY( ! is_format_string_for("{:+?}", "str") );
> -  VERIFY( ! is_format_string_for("{:+?}", 'c') );
> -
> -  // Invalid alternate forms.
> -  VERIFY( ! is_format_string_for("{:#}", "str") );
> -  VERIFY( ! is_format_string_for("{:#s}", "str") );
> -  VERIFY( ! is_format_string_for("{:#}", 'c') );
> -  VERIFY( ! is_format_string_for("{:#c}", 'c') );
> -  VERIFY( ! is_format_string_for("{:#}", true) );
> -  VERIFY( ! is_format_string_for("{:#s}", true) );
> -  VERIFY( ! is_format_string_for("{:#}", nullptr) );
> -  VERIFY( ! is_format_string_for("{:#p}", nullptr) );
> -  VERIFY( ! is_format_string_for("{:#?}", "str") );
> -  VERIFY( ! is_format_string_for("{:#?}", 'c') );
> -
> -  // The 0 option is not valid for charT and bool.
> -  VERIFY( ! is_format_string_for("{:0c}", 'c') );
> -  VERIFY( ! is_format_string_for("{:0s}", true) );
> -
> -  // Dynamic width arg must be a standar integer type.
> -  VERIFY( ! is_format_string_for("{:{}d}", 1, 1.5) );
> -  VERIFY( ! is_format_string_for("{:{}d}", 1, true) );
> -  VERIFY( ! is_format_string_for("{:{}d}", 1, "str") );
> -  VERIFY( ! is_format_string_for("{:{}d}", 1, nullptr) );
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    // Invalid sign options.
> +    VERIFY( ! is_format_string_for("{:+}", "str") );
> +    VERIFY( ! is_format_string_for("{:+s}", "str") );
> +    VERIFY( ! is_format_string_for("{:+}", 'c') );
> +    VERIFY( ! is_format_string_for("{:+c}", 'c') );
> +    VERIFY( ! is_format_string_for("{:+p}", nullptr) );
> +    VERIFY( ! is_format_string_for("{:+}", true) );
> +    VERIFY( ! is_format_string_for("{:+s}", true) );
> +    VERIFY( ! is_format_string_for("{:+?}", "str") );
> +    VERIFY( ! is_format_string_for("{:+?}", 'c') );
> +
> +    // Invalid alternate forms.
> +    VERIFY( ! is_format_string_for("{:#}", "str") );
> +    VERIFY( ! is_format_string_for("{:#s}", "str") );
> +    VERIFY( ! is_format_string_for("{:#}", 'c') );
> +    VERIFY( ! is_format_string_for("{:#c}", 'c') );
> +    VERIFY( ! is_format_string_for("{:#}", true) );
> +    VERIFY( ! is_format_string_for("{:#s}", true) );
> +    VERIFY( ! is_format_string_for("{:#}", nullptr) );
> +    VERIFY( ! is_format_string_for("{:#p}", nullptr) );
> +    VERIFY( ! is_format_string_for("{:#?}", "str") );
> +    VERIFY( ! is_format_string_for("{:#?}", 'c') );
> +
> +    // The 0 option is not valid for charT and bool.
> +    VERIFY( ! is_format_string_for("{:0c}", 'c') );
> +    VERIFY( ! is_format_string_for("{:0s}", true) );
> +
> +    // Dynamic width arg must be a standar integer type.
> +    VERIFY( ! is_format_string_for("{:{}d}", 1, 1.5) );
> +    VERIFY( ! is_format_string_for("{:{}d}", 1, true) );
> +    VERIFY( ! is_format_string_for("{:{}d}", 1, "str") );
> +    VERIFY( ! is_format_string_for("{:{}d}", 1, nullptr) );
>  #ifdef __SIZEOF_INT128__
> -  VERIFY( ! is_format_string_for("{:{}d}", 1, static_cast<__int128>(1)) );
> +    VERIFY( ! is_format_string_for("{:{}d}", 1, static_cast<__int128>(1))
> );
>  #endif
>
> -  // Precision only valid for string and floating-point types.
> -  VERIFY( ! is_format_string_for("{:.3d}", 1) );
> -  VERIFY( ! is_format_string_for("{:3.3d}", 1) );
> +    // Precision only valid for string and floating-point types.
> +    VERIFY( ! is_format_string_for("{:.3d}", 1) );
> +    VERIFY( ! is_format_string_for("{:3.3d}", 1) );
> +  }
> +
>    VERIFY( is_format_string_for("{:3.3s}", "str") );
> -  VERIFY( ! is_format_string_for("{:3.3s}", 'c') );
> -  VERIFY( ! is_format_string_for("{:3.3p}", nullptr) );
> -
> -  // Dynamic precision arg must be a standard integer type.
> -  VERIFY( ! is_format_string_for("{:.{}f}", 1.0, 1.5) );
> -  VERIFY( ! is_format_string_for("{:.{}f}", 1.0, true) );
> -  VERIFY( ! is_format_string_for("{:.{}f}", 1.0, "str") );
> -  VERIFY( ! is_format_string_for("{:.{}f}", 1.0, nullptr) );
> -#ifdef __SIZEOF_INT128__
> -  VERIFY( ! is_format_string_for("{:{}f}", 1.0, static_cast<unsigned
> __int128>(1)) );
> -#endif
>
> -  // Invalid presentation types for integers.
> -  VERIFY( ! is_format_string_for("{:f}", 1) );
> -  VERIFY( ! is_format_string_for("{:s}", 1) );
> -  VERIFY( ! is_format_string_for("{:g}", 1) );
> -  VERIFY( ! is_format_string_for("{:E}", 1) );
> -  VERIFY( ! is_format_string_for("{:D}", 1) );
> +  // not constexpr because of PR124145
> +  if not consteval {
> +    VERIFY( ! is_format_string_for("{:3.3s}", 'c') );
> +    VERIFY( ! is_format_string_for("{:3.3p}", nullptr) );
>
> -  // Invalid presentation types for floating-point types.
> -  VERIFY( ! is_format_string_for("{:d}", 1.2) );
> -  VERIFY( ! is_format_string_for("{:b}", 1.2) );
> -  VERIFY( ! is_format_string_for("{:x}", 1.2) );
> -  VERIFY( ! is_format_string_for("{:s}", 1.2) );
> +    // Dynamic precision arg must be a standard integer type.
> +    VERIFY( ! is_format_string_for("{:.{}f}", 1.0, 1.5) );
> +    VERIFY( ! is_format_string_for("{:.{}f}", 1.0, true) );
> +    VERIFY( ! is_format_string_for("{:.{}f}", 1.0, "str") );
> +    VERIFY( ! is_format_string_for("{:.{}f}", 1.0, nullptr) );
> +#ifdef __SIZEOF_INT128__
> +    VERIFY( ! is_format_string_for("{:{}f}", 1.0, static_cast<unsigned
> __int128>(1)) );
> +#endif
>
> -  // Invalid presentation types for strings.
> -  VERIFY( ! is_format_string_for("{:S}", "str") );
> -  VERIFY( ! is_format_string_for("{:d}", "str") );
> +    // Invalid presentation types for integers.
> +    VERIFY( ! is_format_string_for("{:f}", 1) );
> +    VERIFY( ! is_format_string_for("{:s}", 1) );
> +    VERIFY( ! is_format_string_for("{:g}", 1) );
> +    VERIFY( ! is_format_string_for("{:E}", 1) );
> +    VERIFY( ! is_format_string_for("{:D}", 1) );
> +
> +    // Invalid presentation types for floating-point types.
> +    VERIFY( ! is_format_string_for("{:d}", 1.2) );
> +    VERIFY( ! is_format_string_for("{:b}", 1.2) );
> +    VERIFY( ! is_format_string_for("{:x}", 1.2) );
> +    VERIFY( ! is_format_string_for("{:s}", 1.2) );
> +
> +    // Invalid presentation types for strings.
> +    VERIFY( ! is_format_string_for("{:S}", "str") );
> +    VERIFY( ! is_format_string_for("{:d}", "str") );
> +  }
>
>    // Maximum integer value supported for widths and precisions is
> USHRT_MAX.
>    VERIFY( is_format_string_for("{:65535}", 1) );
> -  VERIFY( is_format_string_for(L"{:65535}", 1) );
> -  VERIFY( ! is_format_string_for("{:65536}", 1) );
> -  VERIFY( ! is_format_string_for(L"{:65536}", 1) );
> -  VERIFY( ! is_format_string_for("{:9999999}", 1) );
> -  VERIFY( ! is_format_string_for(L"{:9999999}", 1) );
> +
> +  // constexpr wide formatting not yet implemented
> +  if not consteval {
> +    VERIFY( is_format_string_for(L"{:65535}", 1) );
> +    // PR124145
> +    VERIFY( ! is_format_string_for("{:65536}", 1) );
> +    VERIFY( ! is_format_string_for(L"{:65536}", 1) );
> +    VERIFY( ! is_format_string_for("{:9999999}", 1) );
> +    VERIFY( ! is_format_string_for(L"{:9999999}", 1) );
> +  }
>  }
>
> +// not constexpr because of PR124145
>  void
>  test_pr110862()
>  {
> @@ -178,6 +206,7 @@ test_pr110862()
>    }
>  }
>
> +// not constexpr because of PR124145
>  void
>  test_pr110974()
>  {
> @@ -197,11 +226,26 @@ test_pr110974()
>    }
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
>    test_no_args();
>    test_indexing();
>    test_format_spec();
> -  test_pr110862();
> -  test_pr110974();
> +
> +  if not consteval {
> +    test_pr110862();
> +    test_pr110974();
> +  }
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc
> b/libstdc++-v3/testsuite/std/format/tuple.cc
> index eace82730f0..8a840bc9868 100644
> --- a/libstdc++-v3/testsuite/std/format/tuple.cc
> +++ b/libstdc++-v3/testsuite/std/format/tuple.cc
> @@ -1,4 +1,4 @@
> -// { dg-do run { target c++23 } }
> +// { dg-do run { target c++26 } }
>  // { dg-options "-fexec-charset=UTF-8" }
>  // { dg-timeout-factor 2 }
>
> @@ -15,7 +15,7 @@ static_assert( !std::formattable<std::pair<int,
> NotFormattable>, char> );
>  static_assert( !std::formattable<std::tuple<int, NotFormattable, int>,
> wchar_t> );
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const char* str, Args&&... args)
>  {
>    try {
> @@ -27,7 +27,7 @@ is_format_string_for(const char* str, Args&&... args)
>  }
>
>  template<typename... Args>
> -bool
> +constexpr bool
>  is_format_string_for(const wchar_t* str, Args&&... args)
>  {
>    try {
> @@ -41,6 +41,7 @@ is_format_string_for(const wchar_t* str, Args&&... args)
>  #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
>  #define WIDEN(S) WIDEN_(CharT, S)
>
> +// not constexpr because of PR124145
>  void
>  test_format_string()
>  {
> @@ -123,7 +124,8 @@ void test_multi()
>  }
>
>  template<typename CharT, typename Tuple>
> -void test_empty()
> +constexpr void
> +test_empty()
>  {
>    std::basic_string<CharT> res;
>
> @@ -142,7 +144,8 @@ void test_empty()
>  }
>
>  template<typename CharT, typename Pair>
> -void test_pair()
> +constexpr void
> +test_pair()
>  {
>    using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>;
>    using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>;
> @@ -167,7 +170,8 @@ void test_pair()
>  }
>
>  template<typename CharT, template<typename, typename> class PairT>
> -void test_pair_e()
> +constexpr void
> +test_pair_e()
>  {
>    test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
>    test_pair<CharT, PairT<int, const CharT*>>();
> @@ -196,6 +200,7 @@ struct std::formatter<MyPair<Pair>, CharT>
>    { return _formatter.parse(pc);  }
>
>    template<typename Out>
> +  constexpr
>    typename std::basic_format_context<Out, CharT>::iterator
>    format(const MyPair<Pair>& mp,
>          std::basic_format_context<Out, CharT>& fc) const
> @@ -206,7 +211,8 @@ private:
>  };
>
>  template<typename CharT, template<typename, typename> class PairT>
> -void test_custom()
> +constexpr void
> +test_custom()
>  {
>    std::basic_string<CharT> res;
>    MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc"));
> @@ -228,9 +234,13 @@ void test_custom()
>  }
>
>  template<typename CharT>
> -void test_outputs()
> +constexpr void
> +test_outputs()
>  {
> -  test_multi<CharT>();
> +  if not consteval {
> +    test_multi<CharT>();
> +  }
> +
>    test_empty<CharT, std::tuple<>>();
>    test_pair_e<CharT, std::pair>();
>    test_pair_e<CharT, std::tuple>();
> @@ -238,7 +248,8 @@ void test_outputs()
>    test_custom<CharT, std::tuple>();
>  }
>
> -void test_nested()
> +constexpr void
> +test_nested()
>  {
>    std::string res;
>    std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1,
> "abc"}};
> @@ -251,7 +262,8 @@ void test_nested()
>    VERIFY( res == R"((): (1, "abc"))" );
>  }
>
> -bool strip_quote(std::string_view& v)
> +constexpr bool
> +strip_quote(std::string_view& v)
>  {
>    if (!v.starts_with('"'))
>      return false;
> @@ -259,7 +271,8 @@ bool strip_quote(std::string_view& v)
>    return true;
>  }
>
> -bool strip_prefix(std::string_view& v, std::string_view expected, bool
> quoted = false)
> +constexpr bool
> +strip_prefix(std::string_view& v, std::string_view expected, bool quoted
> = false)
>  {
>    if (quoted && !strip_quote(v))
>      return false;
> @@ -271,7 +284,8 @@ bool strip_prefix(std::string_view& v,
> std::string_view expected, bool quoted =
>    return true;
>  }
>
> -bool strip_parens(std::string_view& v)
> +constexpr bool
> +strip_parens(std::string_view& v)
>  {
>    if (!v.starts_with('(') || !v.ends_with(')'))
>      return false;
> @@ -280,7 +294,8 @@ bool strip_parens(std::string_view& v)
>    return true;
>  }
>
> -bool strip_prefix(std::string_view& v, size_t n, char c)
> +constexpr bool
> +strip_prefix(std::string_view& v, size_t n, char c)
>  {
>    size_t pos = v.find_first_not_of(c);
>    if (pos == std::string_view::npos)
> @@ -291,7 +306,8 @@ bool strip_prefix(std::string_view& v, size_t n, char
> c)
>    return true;
>  }
>
> -void test_padding()
> +constexpr void
> +test_padding()
>  {
>    std::string res;
>    std::string_view resv;
> @@ -351,13 +367,15 @@ struct std::formatter<Custom, CharT>
>    { return pc.begin();  }
>
>    template<typename Out>
> +  constexpr
>    typename std::basic_format_context<Out, CharT>::iterator
>    format(Custom, const std::basic_format_context<Out, CharT>& fc) const
>    { return fc.out(); }
>  };
>
>  template<template<typename...> typename Tuple>
> -void test_nonblocking()
> +constexpr void
> +test_nonblocking()
>  {
>    static_assert(std::enable_nonlocking_formatter_optimization<
>                   Tuple<int, float>>);
> @@ -374,14 +392,30 @@ void test_nonblocking()
>                   Tuple<Custom&, float&>>);
>  }
>
> -int main()
> +constexpr bool
> +all_tests()
>  {
> -  test_format_string();
>    test_outputs<char>();
> -  test_outputs<wchar_t>();
>    test_nested();
>    test_padding();
>
>    test_nonblocking<std::pair>();
>    test_nonblocking<std::tuple>();
> +
> +  if not consteval {
> +    test_format_string();
> +    // constexpr wide formatting not yet implemented
> +    test_outputs<wchar_t>();
> +  }
> +
> +  return true;
> +}
> +
> +#ifdef __cpp_lib_constexpr_format
> +static_assert(all_tests());
> +#endif
> +
> +int main()
> +{
> +  all_tests();
>  }
> --
> 2.43.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260602/a0fc293c/attachment-0001.htm>


More information about the Libstdc++ mailing list