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

Tomasz Kaminski tkaminsk@redhat.com
Mon Mar 2 15:06:22 GMT 2026


On Mon, Mar 2, 2026 at 3:43 PM Tomasz Kaminski <tkaminsk@redhat.com> wrote:

>
>
> On Mon, Mar 2, 2026 at 3:34 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
> wrote:
>
>> > However, the standard says that the format_string constructor should be
>> ill-formed, beause it is consteval function, that is not core-constant
>> expression.
>> see this case https://eel.is/c++draft/format#fmt.string-3.
>>
>> Do you think this is worth bringing up as an LWG issue, or otherwise
>> confirming intent with WG21?
>> Both constexpr exceptions and constexpr formatting are recently added
>> features,
>> and I wonder if this clause was just missed.
>>
> I think that this is expected design, you program should not compile if it
> contains errors.
> Call with an invalid format string. Allowing an exception to exit, would
> mean that the
> program would compile unless you actually call the format during
> compile-time calls.
> I.e. I think the intent remain for:
> std::format("{sd}", 10)
> to be ill-formed, and not produce a recoverable error, i.e. exception you
> can catch
> at compile time.
>
What I mean, is that for function like:
consteval void foo(int i)
{
  std::format("{x}", i);
}
There should be compilation error, regardless if foo is called.


>
> On the other topic, we cosntexpr string are not supported for `cow_string`
> (pre-C++11),
> so the constexpr_format need to have depend on constexpr string, we can
> achieve this by
> using extra_cond and defining a feature test macro.
>
I missed the end of the sequence and defining the cosntexpr_format feature
test macro
after constexpr_string in file.


>
> Also, in test we need to guad the constepxr check with constexpr_format
> (__glibcxx_constexpr_format
> for now), contrary to what I previously said.
>
This assume we add the feature test macro with no_stdname option (so we
have __glibcxx_constexpr_format
defined). If we get full implementation (wchar_t is removed for example) we
can use __cpplib_constexpr_format.

>
>
>>
>> On Thu, Feb 26, 2026 at 4:48 PM Tomasz Kaminski <tkaminsk@redhat.com>
>> wrote:
>>
>>>
>>>
>>> On Thu, Feb 26, 2026 at 3:55 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
>>> wrote:
>>>
>>>> libstdc++: partially implement constexpr std::format
>>>>
>>>> This patch partially implements constexpr formatting from P3391R2,
>>>> as such it does not define the __cpp_lib_constexpr_format feature-test
>>>> macro.
>>>>
>>>> This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.
>>>>
>>>> Add `__format::__toupper` function that work in constexpr.
>>>> It is not fully general, but `<format>` doesn't need all uppercasing.
>>>>
>>>> Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
>>>> since it is a bit non-trivial to get it to work, and it is just an
>>>> optimization.
>>>>
>>>> Update some formatting tests to test constexpr as well,
>>>> and introduce a dedicated smoke test for constexpr formatting.
>>>>
>>>> This patch is missing:
>>>> * wide constexpr formatting
>>>> * constexpr to_{,w}string
>>>> * more constexpr tests
>>>>
>>>> libstdc++-v3/ChangeLog:
>>>>
>>>>         * include/std/format:
>>>>         Pepper in _GLIBCXX26_CONSTEXPR, replace memcpy with
>>>> ranges::copy.
>>>>         (__format::__toupper): Define.
>>>>         (__format::__do_vformat_to):
>>>>         Avoid using _Ptr_sink in constexpr.
>>>>         * testsuite/std/format/constexpr.cc: New test.
>>>>         * testsuite/std/format/debug.cc: Constexpr testing.
>>>>         * testsuite/std/format/functions/format.cc: Constexpr testing.
>>>>         * testsuite/std/format/functions/format_to.cc: Constexpr
>>>> testing.
>>>>         * testsuite/std/format/functions/size.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/runtime_format.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>
>>>> ---
>>>>
>>> Only comments on update, will do full review later.
>>>
>>>
>>>> Updates to patch:
>>>> Replaced __memcpy with ranges::copy
>>>> Simplified __toupper as a switch
>>>>
>>> I would rename it to __toupper_numeric, so it will be clear that
>>> it is not general purpose, and add handling of 'x' from prefix,
>>> if we ever use it on prefix value.
>>>
>>>> if (not) consteval replaced with std::is_constant_evaluated()
>>>> Rebased on top of your _M_access patch
>>>> Removed the version.{def,h} since this doesn't implement full paper
>>>>
>>> Please use no_stdname instad, that defines internal
>>> glibcxx_constexxpr_format,
>>> but not __cpp_lib one. That is the preferred approach in such a case.
>>>
>>> Cleaned up tests as suggested
>>>> Added a constexpr.cc test with c++26 target
>>>> Killed Counting_constexpr_sink, just going through _Ptr_sink
>>>>
>>>> Regarding formatting of nullptr:
>>>> basic_format_arg(nullptr) will store a `const void*` ,
>>>> so `format(nullptr)` will actually go through `formatter<const void*>`.
>>>>
>>> Makes sense, thanks.
>>>
>>>>
>>>> I've been testing with GLIBCXX_TESTSUITE_STDS=20,23,26,
>>>> two tests are failing in 26 now, both are testing compilation errors:
>>>> std/format/arguments/args_neg.cc
>>>>
>>> Haven't looked at this one yet.
>>>
>>>> std/time/format/data_not_present_neg.cc
>>>>
>>> The second one is something we need to find way to address, as now
>>> we can evaluate following at compile time:
>>>   std::format("{:bad}", 10);
>>> And in the test we use global variables:
>>> auto ym1 = std::format("{:%d}", 2024y/March); // { dg-error "call to
>>> consteval function" }
>>> For global variables we have try constexpr evaluation, so
>>> try to evaluate whole format call at compile time, and because
>>> it is constexpr now we try to do it. And that exception end up being
>>> propagated.
>>>
>>> However, the standard says that the format_string constructor should be
>>> ill-formed, beause it is consteval function, that is not core-constant
>>> expression.
>>> see this case https://eel.is/c++draft/format#fmt.string-3. Ie.
>>> following should
>>> not be able to work;
>>>
>>> consteval foo() {
>>>   try {
>>>     // should be ill-formed and not emit exception
>>>     std::format("{:bad}", 10);
>>>   }
>>>   catch (std::format_error)
>>>   { }
>>> }
>>>
>>> We could do try-catch inside cosntructor, but that way we will miss the
>>> actual
>>> content of the error. I was wondering about making the cosntructor
>>> simply noexcept
>>> so we will hit noexcept boundary at compile time. That should still
>>> print content
>>> of the error.
>>>
>>> Haven't yet investigated.
>>>>
>>>>
>>>>  libstdc++-v3/include/std/format               | 388 +++++++++++-------
>>>>  .../testsuite/std/format/constexpr.cc         | 126 ++++++
>>>>  libstdc++-v3/testsuite/std/format/debug.cc    | 105 +++--
>>>>  .../testsuite/std/format/functions/format.cc  | 265 +++++++-----
>>>>  .../std/format/functions/format_to.cc         |  63 ++-
>>>>  .../testsuite/std/format/functions/size.cc    |  24 +-
>>>>  .../std/format/ranges/format_kind.cc          |  15 +-
>>>>  .../testsuite/std/format/ranges/formatter.cc  |  45 +-
>>>>  .../testsuite/std/format/ranges/sequence.cc   |  73 +++-
>>>>  .../testsuite/std/format/runtime_format.cc    |  18 +-
>>>>  libstdc++-v3/testsuite/std/format/string.cc   | 230 +++++++----
>>>>  libstdc++-v3/testsuite/std/format/tuple.cc    |  78 +++-
>>>>  12 files changed, 967 insertions(+), 463 deletions(-)
>>>>  create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc
>>>>
>>>> diff --git a/libstdc++-v3/include/std/format
>>>> b/libstdc++-v3/include/std/format
>>>> index 4f0b0f377c6..b5670d0ec32 100644
>>>> --- a/libstdc++-v3/include/std/format
>>>> +++ b/libstdc++-v3/include/std/format
>>>> @@ -128,6 +128,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 +174,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,13 +199,13 @@ namespace __format
>>>>
>>>>  #if __cpp_lib_format >= 202311L // >= C++26
>>>>    [[__gnu__::__always_inline__]]
>>>> -  inline __format::_Runtime_format_string<char>
>>>> +  inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string<char>
>>>>    runtime_format(string_view __fmt) noexcept
>>>>    { return __fmt; }
>>>>
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    [[__gnu__::__always_inline__]]
>>>> -  inline __format::_Runtime_format_string<wchar_t>
>>>> +  inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string<wchar_t>
>>>>    runtime_format(wstring_view __fmt) noexcept
>>>>    { return __fmt; }
>>>>  #endif
>>>> @@ -238,7 +240,7 @@ namespace __format
>>>>
>>>>    /// @cond undocumented
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __throw_format_error(const char* __what)
>>>>    { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
>>>>
>>>> @@ -249,27 +251,27 @@ namespace __format
>>>>    // XXX use named functions for each constexpr error?
>>>>
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __unmatched_left_brace_in_format_string()
>>>>    { __throw_format_error("format error: unmatched '{' in format
>>>> string"); }
>>>>
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __unmatched_right_brace_in_format_string()
>>>>    { __throw_format_error("format error: unmatched '}' in format
>>>> string"); }
>>>>
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __conflicting_indexing_in_format_string()
>>>>    { __throw_format_error("format error: conflicting indexing style in
>>>> format string"); }
>>>>
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __invalid_arg_id_in_format_string()
>>>>    { __throw_format_error("format error: invalid arg-id in format
>>>> string"); }
>>>>
>>>>    [[noreturn]]
>>>> -  inline void
>>>> +  inline _GLIBCXX26_CONSTEXPR void
>>>>    __failed_to_parse_format_spec()
>>>>    { __throw_format_error("format error: failed to parse format-spec");
>>>> }
>>>>
>>>> @@ -517,7 +519,7 @@ namespace __format
>>>>    using enum _WidthPrec;
>>>>
>>>>    template<typename _Context>
>>>> -    size_t
>>>> +    _GLIBCXX26_CONSTEXPR size_t
>>>>      __int_from_arg(const basic_format_arg<_Context>& __arg);
>>>>
>>>>    constexpr bool __is_digit(char __c)
>>>> @@ -750,7 +752,7 @@ namespace __format
>>>>        }
>>>>
>>>>        template<typename _Context>
>>>> -       size_t
>>>> +       _GLIBCXX26_CONSTEXPR size_t
>>>>         _M_get_width(_Context& __ctx) const
>>>>         {
>>>>           size_t __width = 0;
>>>> @@ -762,7 +764,7 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Context>
>>>> -       size_t
>>>> +       _GLIBCXX26_CONSTEXPR size_t
>>>>         _M_get_precision(_Context& __ctx) const
>>>>         {
>>>>           size_t __prec = -1;
>>>> @@ -775,7 +777,7 @@ namespace __format
>>>>      };
>>>>
>>>>    template<typename _Int>
>>>> -    inline char*
>>>> +    inline _GLIBCXX26_CONSTEXPR char*
>>>>      __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
>>>>      {
>>>>        if (__i < 0)
>>>> @@ -792,7 +794,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&>
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      __write(_Out __out, basic_string_view<_CharT> __str)
>>>>      {
>>>>        if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>>>> @@ -809,7 +811,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>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_padded(_Out __out, basic_string_view<_CharT> __str,
>>>>                    _Align __align, size_t __nfill, char32_t __fill_char)
>>>>      {
>>>> @@ -883,7 +885,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>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>>
>>>> __str,
>>>>                            size_t __estimated_width,
>>>>                            basic_format_context<_Out, _CharT>& __fc,
>>>> @@ -905,7 +907,7 @@ namespace __format
>>>>      }
>>>>
>>>>     template<typename _CharT>
>>>> -     size_t
>>>> +     _GLIBCXX26_CONSTEXPR size_t
>>>>       __truncate(basic_string_view<_CharT>& __s, size_t __prec)
>>>>       {
>>>>         if constexpr
>>>> (__unicode::__literal_encoding_is_unicode<_CharT>())
>>>> @@ -1049,7 +1051,7 @@ namespace __format
>>>>
>>>>    using uint_least32_t = __UINT_LEAST32_TYPE__;
>>>>    template<typename _Out, typename _CharT>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escape_seq(_Out __out, uint_least32_t __val,
>>>>                        basic_string_view<_CharT> __prefix)
>>>>      {
>>>> @@ -1079,7 +1081,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _Out, typename _CharT>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
>>>>      {
>>>>        using _UChar = make_unsigned_t<_CharT>;
>>>> @@ -1090,7 +1092,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _Out, typename _CharT>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escaped_char(_Out __out, _CharT __c)
>>>>      {
>>>>        using _UChar = make_unsigned_t<_CharT>;
>>>> @@ -1116,7 +1118,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _CharT, typename _Out>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escaped_ascii(_Out __out,
>>>>                           basic_string_view<_CharT> __str,
>>>>                           _Term_char __term)
>>>> @@ -1146,7 +1148,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _CharT, typename _Out>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escaped_unicode_part(_Out __out,
>>>> basic_string_view<_CharT>& __str,
>>>>                                  bool& __prev_esc, _Term_char __term)
>>>>      {
>>>> @@ -1224,7 +1226,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _CharT, typename _Out>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escaped_unicode(_Out __out, basic_string_view<_CharT>
>>>> __str,
>>>>                             _Term_char __term)
>>>>      {
>>>> @@ -1236,7 +1238,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _CharT, typename _Out>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __write_escaped(_Out __out,  basic_string_view<_CharT> __str,
>>>> _Term_char __term)
>>>>      {
>>>>        __out = __format::__write(__out,
>>>> _Escapes<_CharT>::_S_term(__term));
>>>> @@ -1257,12 +1259,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 +1274,7 @@ namespace __format
>>>>         std::construct_at(&_M_loc, __l._M_loc);
>>>>      }
>>>>
>>>> +    _GLIBCXX26_CONSTEXPR
>>>>      _Optional_locale&
>>>>      operator=(const _Optional_locale& __l) noexcept
>>>>      {
>>>> @@ -1291,6 +1296,7 @@ namespace __format
>>>>        return *this;
>>>>      }
>>>>
>>>> +    _GLIBCXX26_CONSTEXPR
>>>>      ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
>>>>
>>>>      _Optional_locale&
>>>> @@ -1317,7 +1323,8 @@ namespace __format
>>>>        return _M_loc;
>>>>      }
>>>>
>>>> -    bool has_value() const noexcept { return _M_hasval; }
>>>> +    _GLIBCXX26_CONSTEXPR bool
>>>> +    has_value() const noexcept { return _M_hasval; }
>>>>
>>>>      union {
>>>>        char _M_dummy = '\0';
>>>> @@ -1391,7 +1398,7 @@ namespace __format
>>>>        }
>>>>
>>>>        template<typename _Out>
>>>> -       _Out
>>>> +       _GLIBCXX26_CONSTEXPR _Out
>>>>         format(basic_string_view<_CharT> __s,
>>>>                basic_format_context<_Out, _CharT>& __fc) const
>>>>         {
>>>> @@ -1408,7 +1415,7 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Out>
>>>> -       _Out
>>>> +       _GLIBCXX26_CONSTEXPR _Out
>>>>         _M_format_escaped(basic_string_view<_CharT> __s,
>>>>                           basic_format_context<_Out, _CharT>& __fc)
>>>> const
>>>>         {
>>>> @@ -1433,7 +1440,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>
>>>> -       _Out
>>>> +       _GLIBCXX26_CONSTEXPR _Out
>>>>         _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>&
>>>> __fc) const
>>>>         {
>>>>           using _Range = remove_reference_t<_Rg>;
>>>> @@ -1482,6 +1489,25 @@ namespace __format
>>>>        _Spec<_CharT> _M_spec{};
>>>>      };
>>>>
>>>> +  [[__gnu__::__always_inline__]]
>>>> +  constexpr char
>>>> +  __toupper(char __c)
>>>> +  {
>>>> +    switch (__c)
>>>> +    {
>>>> +      case 'a': return 'A';
>>>> +      case 'b': return 'B';
>>>> +      case 'c': return 'C';
>>>> +      case 'd': return 'D';
>>>> +      case 'e': return 'E';
>>>> +      case 'f': return 'F';
>>>> +      case 'i': return 'I';
>>>> +      case 'n': return 'N';
>>>> +      case 'p': return 'P';
>>>> +      default: return __c;
>>>> +    }
>>>> +  }
>>>> +
>>>>    template<__char _CharT>
>>>>      struct __formatter_int
>>>>      {
>>>> @@ -1641,6 +1667,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 +1716,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 +1725,7 @@ namespace __format
>>>>           if (_M_spec._M_alt && __base_prefix.size())
>>>>             {
>>>>               __start -= __base_prefix.size();
>>>> -             __builtin_memcpy(__start, __base_prefix.data(),
>>>> -                              __base_prefix.size());
>>>> +             ranges::copy(__base_prefix, __start);
>>>>             }
>>>>           __start = __format::__put_sign(__i, _M_spec._M_sign, __start
>>>> - 1);
>>>>
>>>> @@ -1712,6 +1734,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 +1765,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,7 +1797,7 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Int>
>>>> -       static _CharT
>>>> +       static _GLIBCXX26_CONSTEXPR _CharT
>>>>         _S_to_character(_Int __i)
>>>>         {
>>>>           using _Traits = __gnu_cxx::__int_traits<_CharT>;
>>>> @@ -1794,6 +1818,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 +2093,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 +2223,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 +2528,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 +2548,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 +2617,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 +2656,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 +2692,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 +2722,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 +2753,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 +2783,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 +2816,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 +2850,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 +2883,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 +2947,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 +3159,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 +3185,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 +3211,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,11 +3356,11 @@ namespace __format
>>>>        constexpr _Sink_iter
>>>>        operator++(int) { return *this; }
>>>>
>>>> -      auto
>>>> +      _GLIBCXX26_CONSTEXPR auto
>>>>        _M_reserve(size_t __n) const
>>>>        { return _M_sink->_M_reserve(__n); }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_discarding() const
>>>>        { return _M_sink->_M_discarding(); }
>>>>      };
>>>> @@ -3352,7 +3392,7 @@ namespace __format
>>>>
>>>>        // The portion of the span that has been written to.
>>>>        [[__gnu__::__always_inline__]]
>>>> -      span<_CharT>
>>>> +      _GLIBCXX26_CONSTEXPR span<_CharT>
>>>>        _M_used() const noexcept
>>>>        { return _M_span.first(_M_next - _M_span.begin()); }
>>>>
>>>> @@ -3369,7 +3409,7 @@ namespace __format
>>>>        { _M_next = _M_span.begin(); }
>>>>
>>>>        // Replace the current output range.
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
>>>>        {
>>>>         _M_span = __s;
>>>> @@ -3409,11 +3449,14 @@ 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.
>>>> -       _CharT* get() const noexcept { return
>>>> _M_sink->_M_next.operator->(); }
>>>> +       _GLIBCXX26_CONSTEXPR _CharT*
>>>> +       get() const noexcept { return _M_sink->_M_next.operator->(); }
>>>>         // Add n to the _M_next iterator for the sink.
>>>> -       void _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
>>>> +       _GLIBCXX26_CONSTEXPR void
>>>> +       _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
>>>>         _Sink* _M_sink;
>>>>        };
>>>>
>>>> @@ -3421,7 +3464,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.
>>>> -      virtual _Reservation
>>>> +      _GLIBCXX26_CONSTEXPR virtual _Reservation
>>>>        _M_reserve(size_t __n)
>>>>        {
>>>>         if (__n <= _M_unused().size())
>>>> @@ -3438,12 +3481,12 @@ 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.
>>>> -      virtual void
>>>> +      _GLIBCXX26_CONSTEXPR virtual void
>>>>        _M_bump(size_t __n)
>>>>        { _M_next += __n; }
>>>>
>>>>        // Returns true if the _Sink is discarding incoming characters.
>>>> -      virtual bool
>>>> +      _GLIBCXX26_CONSTEXPR virtual bool
>>>>        _M_discarding() const
>>>>        { return false; }
>>>>
>>>> @@ -3461,7 +3504,7 @@ namespace __format
>>>>    template<typename _CharT>
>>>>      class _Fixedbuf_sink final : public _Sink<_CharT>
>>>>      {
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         __glibcxx_assert(false);
>>>> @@ -3509,7 +3552,7 @@ namespace __format
>>>>        _Seq _M_seq;
>>>>      protected:
>>>>        // Transfer buffer contents to the sequence, so buffer can be
>>>> refilled.
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         auto __s = this->_M_used();
>>>> @@ -3528,7 +3571,7 @@ namespace __format
>>>>         this->_M_rewind();
>>>>        }
>>>>
>>>> -      typename _Sink<_CharT>::_Reservation
>>>> +      _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
>>>>        _M_reserve(size_t __n) override
>>>>        {
>>>>         // We might already have n characters available in
>>>> this->_M_unused(),
>>>> @@ -3564,7 +3607,7 @@ namespace __format
>>>>           return _Sink<_CharT>::_M_reserve(__n);
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_bump(size_t __n) override
>>>>        {
>>>>         if constexpr (__is_specialization_of<_Seq, basic_string>
>>>> @@ -3579,7 +3622,8 @@ namespace __format
>>>>           }
>>>>        }
>>>>
>>>> -      void _M_trim(span<const _CharT> __s)
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>> +      _M_trim(span<const _CharT> __s)
>>>>         requires __is_specialization_of<_Seq, basic_string>
>>>>        {
>>>>         _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf
>>>> @@ -3595,16 +3639,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;
>>>>
>>>> -      _Seq
>>>> +      _GLIBCXX26_CONSTEXPR _Seq
>>>>        get() &&
>>>>        {
>>>>         if (this->_M_used().size() != 0)
>>>> @@ -3614,7 +3660,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.
>>>> -      span<_CharT>
>>>> +      _GLIBCXX26_CONSTEXPR span<_CharT>
>>>>        _M_span()
>>>>        {
>>>>         auto __s = this->_M_used();
>>>> @@ -3627,7 +3673,7 @@ namespace __format
>>>>         return __s;
>>>>        }
>>>>
>>>> -      basic_string_view<_CharT>
>>>> +      _GLIBCXX26_CONSTEXPR basic_string_view<_CharT>
>>>>        view()
>>>>        {
>>>>         auto __span = _M_span();
>>>> @@ -3652,7 +3698,7 @@ namespace __format
>>>>      protected:
>>>>        size_t _M_count = 0;
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         auto __s = this->_M_used();
>>>> @@ -3672,7 +3718,7 @@ namespace __format
>>>>         _M_count += __s.size();
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_discarding() const override
>>>>        {
>>>>         // format_to_n return total number of characters, that would be
>>>> written,
>>>> @@ -3682,14 +3728,14 @@ namespace __format
>>>>
>>>>      public:
>>>>        [[__gnu__::__always_inline__]]
>>>> -      explicit
>>>> +      _GLIBCXX26_CONSTEXPR explicit
>>>>        _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max =
>>>> -1)
>>>>        : _M_out(std::move(__out)), _M_max(__max)
>>>>        { }
>>>>
>>>>        using _Sink<_CharT>::out;
>>>>
>>>> -      format_to_n_result<_OutIter>
>>>> +      _GLIBCXX26_CONSTEXPR format_to_n_result<_OutIter>
>>>>        _M_finish() &&
>>>>        {
>>>>         if (this->_M_used().size() != 0)
>>>> @@ -3718,7 +3764,7 @@ namespace __format
>>>>        _CharT _M_buf[64]; // Write here after outputting _M_max
>>>> characters.
>>>>
>>>>      protected:
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         if (this->_M_unused().size() != 0)
>>>> @@ -3742,7 +3788,7 @@ namespace __format
>>>>           }
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_discarding() const override
>>>>        {
>>>>         // format_to_n return total number of characters, that would be
>>>> written,
>>>> @@ -3750,7 +3796,7 @@ namespace __format
>>>>         return false;
>>>>        }
>>>>
>>>> -      typename _Sink<_CharT>::_Reservation
>>>> +      _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
>>>>        _M_reserve(size_t __n) final
>>>>        {
>>>>         auto __avail = this->_M_unused();
>>>> @@ -3767,7 +3813,7 @@ namespace __format
>>>>
>>>>      private:
>>>>        template<typename _IterDifference>
>>>> -       static size_t
>>>> +       static _GLIBCXX26_CONSTEXPR size_t
>>>>         _S_trim_max(_IterDifference __max)
>>>>         {
>>>>           if (__max < 0)
>>>> @@ -3780,7 +3826,7 @@ namespace __format
>>>>         }
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_rebuf(_CharT* __ptr, size_t __total, size_t __inuse = 0)
>>>>        {
>>>>         std::span<_CharT> __span(__ptr, __total);
>>>> @@ -3788,7 +3834,7 @@ namespace __format
>>>>        }
>>>>
>>>>      public:
>>>> -      explicit
>>>> +      _GLIBCXX26_CONSTEXPR explicit
>>>>        _Ptr_sink(_CharT* __ptr, size_t __n = _S_no_limit) noexcept
>>>>        : _Sink<_CharT>(_M_buf), _M_max(__n)
>>>>        {
>>>> @@ -3813,13 +3859,13 @@ namespace __format
>>>>        }
>>>>
>>>>        template<contiguous_iterator _OutIter>
>>>> -       explicit
>>>> +       _GLIBCXX26_CONSTEXPR explicit
>>>>         _Ptr_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1)
>>>>         : _Ptr_sink(std::to_address(__out), _S_trim_max(__n))
>>>>         { }
>>>>
>>>>        template<contiguous_iterator _OutIter>
>>>> -       format_to_n_result<_OutIter>
>>>> +       _GLIBCXX26_CONSTEXPR format_to_n_result<_OutIter>
>>>>         _M_finish(_OutIter __first) const
>>>>         {
>>>>           auto __s = this->_M_used();
>>>> @@ -3861,12 +3907,12 @@ namespace __format
>>>>        size_t _M_printwidth;
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_ignoring() const
>>>>        { return _M_printwidth >= _M_maxwidth; }
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_buffering() const
>>>>        {
>>>>         if (_M_printwidth < _M_padwidth)
>>>> @@ -3876,7 +3922,7 @@ namespace __format
>>>>         return false;
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_sync_discarding()
>>>>        {
>>>>         if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>>>> @@ -3884,7 +3930,7 @@ namespace __format
>>>>             _M_maxwidth = _M_printwidth;
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_flush()
>>>>        {
>>>>         span<_CharT> __new = this->_M_used();
>>>> @@ -3894,7 +3940,7 @@ namespace __format
>>>>         this->_M_rewind();
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_force_update()
>>>>        {
>>>>         auto __str = this->view();
>>>> @@ -3922,7 +3968,7 @@ namespace __format
>>>>         return false;
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_update(size_t __new)
>>>>        {
>>>>         _M_printwidth += __new;
>>>> @@ -3932,7 +3978,7 @@ namespace __format
>>>>         return true;
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         // Ignore characters in buffer, and override it.
>>>> @@ -3947,11 +3993,11 @@ namespace __format
>>>>           _Str_sink<_CharT>::_M_overflow();
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_discarding() const override
>>>>        { return _M_ignoring(); }
>>>>
>>>> -      typename _Sink<_CharT>::_Reservation
>>>> +      _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
>>>>        _M_reserve(size_t __n) override
>>>>        {
>>>>         // Ignore characters in buffer, if any.
>>>> @@ -3970,7 +4016,7 @@ namespace __format
>>>>         return _Sink<_CharT>::_M_reserve(__n);
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_bump(size_t __n) override
>>>>        {
>>>>         // Ignore the written characters.
>>>> @@ -3985,19 +4031,19 @@ namespace __format
>>>>
>>>>      public:
>>>>        [[__gnu__::__always_inline__]]
>>>> -      explicit
>>>> +      _GLIBCXX26_CONSTEXPR explicit
>>>>        _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth)
>>>>        : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
>>>>         _M_out(std::move(__out)), _M_printwidth(0)
>>>>        { _M_sync_discarding(); }
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      explicit
>>>> +      _GLIBCXX26_CONSTEXPR explicit
>>>>        _Padding_sink(_Out __out, size_t __padwidth)
>>>>        : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
>>>>        { }
>>>>
>>>> -      _Out
>>>> +      _GLIBCXX26_CONSTEXPR _Out
>>>>        _M_finish(_Align __align, char32_t __fill_char)
>>>>        {
>>>>         // Handle any characters in the buffer.
>>>> @@ -4036,14 +4082,14 @@ namespace __format
>>>>        unsigned _M_prev_escape : 1;
>>>>        unsigned _M_out_discards : 1;
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_sync_discarding()
>>>>        {
>>>>         if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>>>>           _M_out_discards = _M_out._M_discarding();
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_write()
>>>>        {
>>>>         span<_CharT> __bytes = this->_M_used();
>>>> @@ -4069,7 +4115,7 @@ namespace __format
>>>>         _M_sync_discarding();
>>>>        }
>>>>
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        _M_overflow() override
>>>>        {
>>>>         if (_M_out_discards)
>>>> @@ -4078,13 +4124,13 @@ namespace __format
>>>>           _M_write();
>>>>        }
>>>>
>>>> -      bool
>>>> +      _GLIBCXX26_CONSTEXPR bool
>>>>        _M_discarding() const override
>>>>        { return _M_out_discards; }
>>>>
>>>>      public:
>>>>        [[__gnu__::__always_inline__]]
>>>> -      explicit
>>>> +      _GLIBCXX26_CONSTEXPR explicit
>>>>        _Escaping_sink(_Out __out, _Term_char __term)
>>>>        : _M_out(std::move(__out)), _M_term(__term),
>>>>         _M_prev_escape(true), _M_out_discards(false)
>>>> @@ -4093,7 +4139,7 @@ namespace __format
>>>>         _M_sync_discarding();
>>>>        }
>>>>
>>>> -      _Out
>>>> +      _GLIBCXX26_CONSTEXPR _Out
>>>>        _M_finish()
>>>>        {
>>>>         if (_M_out_discards)
>>>> @@ -4141,7 +4187,7 @@ namespace __format
>>>>                             const _Tp, _Tp>;
>>>>
>>>>        template<typename _Tq>
>>>> -       static void
>>>> +       static _GLIBCXX26_CONSTEXPR void
>>>>         _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
>>>>                   _Context& __format_ctx, const void* __ptr)
>>>>         {
>>>> @@ -4154,7 +4200,7 @@ namespace __format
>>>>
>>>>        template<typename _Tp>
>>>>         requires (!is_same_v<remove_cv_t<_Tp>, _Handle>)
>>>> -       explicit
>>>> +       _GLIBCXX26_CONSTEXPR explicit
>>>>         _Handle(_Tp& __val) noexcept
>>>>         : _M_ptr(__builtin_addressof(__val))
>>>>         , _M_func(&_S_format<__maybe_const_t<_Tp>>)
>>>> @@ -4169,7 +4215,7 @@ namespace __format
>>>>        _Handle& operator=(const _Handle&) = default;
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      void
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>>        format(basic_format_parse_context<_CharT>& __pc, _Context& __fc)
>>>> const
>>>>        { _M_func(__pc, __fc, this->_M_ptr); }
>>>>
>>>> @@ -4226,10 +4272,12 @@ 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
>>>> @@ -4238,7 +4286,7 @@ namespace __format
>>>>        // Value of second argument (if provided), is assigned to that
>>>> member.
>>>>        template<typename _Tp, typename _Self, typename... _Value>
>>>>         [[__gnu__::__always_inline__]]
>>>> -       static auto&
>>>> +       static _GLIBCXX26_CONSTEXPR auto&
>>>>         _S_access(_Self& __u, _Value... __value) noexcept
>>>>         {
>>>>           static_assert(sizeof...(_Value) <= 1);
>>>> @@ -4302,23 +4350,24 @@ namespace __format
>>>>           else if constexpr (is_same_v<_Tp, _Handle<_Context>>)
>>>>             return (__u._M_handle = ... = __value);
>>>>           // Otherwise, ill-formed.
>>>> +         __builtin_unreachable();
>>>>         }
>>>>
>>>>        template<typename _Tp>
>>>>         [[__gnu__::__always_inline__]]
>>>> -       auto&
>>>> +       _GLIBCXX26_CONSTEXPR auto&
>>>>         _M_get() noexcept
>>>>         { return _S_access<_Tp>(*this); }
>>>>
>>>>        template<typename _Tp>
>>>>         [[__gnu__::__always_inline__]]
>>>> -       const auto&
>>>> +       _GLIBCXX26_CONSTEXPR const auto&
>>>>         _M_get() const noexcept
>>>>         { return _S_access<_Tp>(*this); }
>>>>
>>>>        template<typename _Tp>
>>>>         [[__gnu__::__always_inline__]]
>>>> -       void
>>>> +       _GLIBCXX26_CONSTEXPR void
>>>>         _M_set(_Tp __v) noexcept
>>>>         {
>>>>           if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
>>>> @@ -4335,7 +4384,8 @@ namespace __format
>>>>      class _Arg_store;
>>>>
>>>>    template<typename _Visitor, typename _Ctx>
>>>> -    decltype(auto) __visit_format_arg(_Visitor&&,
>>>> basic_format_arg<_Ctx>);
>>>> +    _GLIBCXX26_CONSTEXPR decltype(auto)
>>>> +    __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>>>>
>>>>    template<typename _Ch, typename _Tp>
>>>>      consteval _Arg_t
>>>> @@ -4351,20 +4401,21 @@ 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__]]
>>>> -      explicit operator bool() const noexcept
>>>> +      explicit _GLIBCXX26_CONSTEXPR operator bool() const noexcept
>>>>        { return _M_type != __format::_Arg_none; }
>>>>
>>>>  #if __cpp_lib_format >= 202306L // >= C++26
>>>>        template<typename _Visitor>
>>>> -       decltype(auto)
>>>> +       _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>
>>>> -       _Res
>>>> +       _GLIBCXX26_CONSTEXPR _Res
>>>>         visit(this basic_format_arg __arg, _Visitor&& __vis)
>>>>         { return __arg._M_visit_user(std::forward<_Visitor>(__vis),
>>>> __arg._M_type); }
>>>>  #endif
>>>> @@ -4541,7 +4592,7 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Tp>
>>>> -       void
>>>> +       _GLIBCXX26_CONSTEXPR void
>>>>         _M_set(_Tp __v) noexcept
>>>>         {
>>>>           _M_type = _S_to_enum<_Tp>();
>>>> @@ -4550,7 +4601,7 @@ namespace __format
>>>>
>>>>        template<typename _Tp>
>>>>         requires __format::__formattable_with<_Tp, _Context>
>>>> -       explicit
>>>> +       _GLIBCXX26_CONSTEXPR explicit
>>>>         basic_format_arg(_Tp& __v) noexcept
>>>>         {
>>>>           using _Td = _Normalize<_Tp>;
>>>> @@ -4564,15 +4615,15 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Ctx, typename... _Argz>
>>>> -       friend auto
>>>> +       friend _GLIBCXX26_CONSTEXPR auto
>>>>         make_format_args(_Argz&...) noexcept;
>>>>
>>>>        template<typename _Visitor, typename _Ctx>
>>>> -       friend decltype(auto)
>>>> +       friend _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>         visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
>>>>
>>>>        template<typename _Visitor, typename _Ctx>
>>>> -       friend decltype(auto)
>>>> +       friend _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>         __format::__visit_format_arg(_Visitor&&,
>>>> basic_format_arg<_Ctx>);
>>>>
>>>>        template<typename _Ch, typename _Tp>
>>>> @@ -4580,7 +4631,7 @@ namespace __format
>>>>         __format::__to_arg_t_enum() noexcept;
>>>>
>>>>        template<typename _Visitor>
>>>> -       decltype(auto)
>>>> +       _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>         _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
>>>>         {
>>>>           using namespace __format;
>>>> @@ -4655,7 +4706,7 @@ namespace __format
>>>>         }
>>>>
>>>>        template<typename _Visitor>
>>>> -       decltype(auto)
>>>> +       _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>         _M_visit_user(_Visitor&& __vis, __format::_Arg_t __type)
>>>>         {
>>>>           return _M_visit([&__vis]<typename _Tp>(_Tp& __val) ->
>>>> decltype(auto)
>>>> @@ -4679,7 +4730,7 @@ namespace __format
>>>>
>>>>    template<typename _Visitor, typename _Context>
>>>>      _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
>>>> -    inline decltype(auto)
>>>> +    inline _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>      visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context>
>>>> __arg)
>>>>      {
>>>>        return __arg._M_visit_user(std::forward<_Visitor>(__vis),
>>>> __arg._M_type);
>>>> @@ -4689,7 +4740,7 @@ namespace __format
>>>>  namespace __format
>>>>  {
>>>>    template<typename _Visitor, typename _Ctx>
>>>> -    inline decltype(auto)
>>>> +    inline _GLIBCXX26_CONSTEXPR decltype(auto)
>>>>      __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg)
>>>>      {
>>>>        return __arg._M_visit(std::forward<_Visitor>(__vis),
>>>> __arg._M_type);
>>>> @@ -4698,7 +4749,7 @@ namespace __format
>>>>    struct _WidthPrecVisitor
>>>>    {
>>>>      template<typename _Tp>
>>>> -      size_t
>>>> +      _GLIBCXX26_CONSTEXPR size_t
>>>>        operator()(_Tp& __arg) const
>>>>        {
>>>>         if constexpr (is_same_v<_Tp, monostate>)
>>>> @@ -4724,7 +4775,7 @@ namespace __format
>>>>  #pragma GCC diagnostic push
>>>>  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
>>>>    template<typename _Context>
>>>> -    inline size_t
>>>> +    inline _GLIBCXX26_CONSTEXPR size_t
>>>>      __int_from_arg(const basic_format_arg<_Context>& __arg)
>>>>      { return __format::__visit_format_arg(_WidthPrecVisitor(), __arg);
>>>> }
>>>>
>>>> @@ -4772,11 +4823,11 @@ namespace __format
>>>>         const _Format_arg* _M_args;       // Active when _M_packed_size
>>>> == 0
>>>>        };
>>>>
>>>> -      size_t
>>>> +      _GLIBCXX26_CONSTEXPR size_t
>>>>        _M_size() const noexcept
>>>>        { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
>>>>
>>>> -      typename __format::_Arg_t
>>>> +      _GLIBCXX26_CONSTEXPR typename __format::_Arg_t
>>>>        _M_type(size_t __i) const noexcept
>>>>        {
>>>>         uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
>>>> @@ -4784,7 +4835,7 @@ namespace __format
>>>>        }
>>>>
>>>>        template<typename _Ctx, typename... _Args>
>>>> -       friend auto
>>>> +       friend _GLIBCXX26_CONSTEXPR auto
>>>>         make_format_args(_Args&...) noexcept;
>>>>
>>>>        // An array of _Arg_t enums corresponding to _Args...
>>>> @@ -4795,10 +4846,11 @@ namespace __format
>>>>
>>>>      public:
>>>>        template<typename... _Args>
>>>> +       _GLIBCXX26_CONSTEXPR
>>>>         basic_format_args(const _Store<_Args...>& __store) noexcept;
>>>>
>>>>        [[nodiscard,__gnu__::__always_inline__]]
>>>> -      basic_format_arg<_Context>
>>>> +      _GLIBCXX26_CONSTEXPR basic_format_arg<_Context>
>>>>        get(size_t __i) const noexcept
>>>>        {
>>>>         basic_format_arg<_Context> __arg;
>>>> @@ -4820,7 +4872,7 @@ namespace __format
>>>>        -> basic_format_args<_Context>;
>>>>
>>>>    template<typename _Context, typename... _Args>
>>>> -    auto
>>>> +    _GLIBCXX26_CONSTEXPR auto
>>>>      make_format_args(_Args&... __fmt_args) noexcept;
>>>>
>>>>    // An array of type-erased formatting arguments.
>>>> @@ -4830,7 +4882,7 @@ namespace __format
>>>>        friend std::basic_format_args<_Context>;
>>>>
>>>>        template<typename _Ctx, typename... _Argz>
>>>> -       friend auto std::
>>>> +       friend _GLIBCXX26_CONSTEXPR auto std::
>>>>  #if _GLIBCXX_INLINE_VERSION
>>>>         __8:: // Needed for PR c++/59256
>>>>  #endif
>>>> @@ -4849,7 +4901,7 @@ namespace __format
>>>>        _Element_t _M_args[sizeof...(_Args)];
>>>>
>>>>        template<typename _Tp>
>>>> -       static _Element_t
>>>> +       static _GLIBCXX26_CONSTEXPR _Element_t
>>>>         _S_make_elt(_Tp& __v)
>>>>         {
>>>>           using _Tq = remove_const_t<_Tp>;
>>>> @@ -4875,6 +4927,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)...}
>>>>         { }
>>>> @@ -4886,7 +4939,7 @@ namespace __format
>>>>
>>>>    template<typename _Context>
>>>>      template<typename... _Args>
>>>> -      inline
>>>> +      inline _GLIBCXX26_CONSTEXPR
>>>>        basic_format_args<_Context>::
>>>>        basic_format_args(const _Store<_Args...>& __store) noexcept
>>>>        {
>>>> @@ -4920,7 +4973,7 @@ namespace __format
>>>>    /// Capture formatting arguments for use by `std::vformat`.
>>>>    template<typename _Context = format_context, typename... _Args>
>>>>      [[nodiscard,__gnu__::__always_inline__]]
>>>> -    inline auto
>>>> +    inline _GLIBCXX26_CONSTEXPR auto
>>>>      make_format_args(_Args&... __fmt_args) noexcept
>>>>      {
>>>>        using _Fmt_arg = basic_format_arg<_Context>;
>>>> @@ -4933,7 +4986,7 @@ namespace __format
>>>>    /// Capture formatting arguments for use by `std::vformat` (for wide
>>>> output).
>>>>    template<typename... _Args>
>>>>      [[nodiscard,__gnu__::__always_inline__]]
>>>> -    inline auto
>>>> +    inline _GLIBCXX26_CONSTEXPR auto
>>>>      make_wformat_args(_Args&... __args) noexcept
>>>>      { return std::make_format_args<wformat_context>(__args...); }
>>>>  #endif
>>>> @@ -4942,13 +4995,13 @@ namespace __format
>>>>  namespace __format
>>>>  {
>>>>    template<typename _Out, typename _CharT, typename _Context>
>>>> -    _Out
>>>> +    _GLIBCXX26_CONSTEXPR _Out
>>>>      __do_vformat_to(_Out, basic_string_view<_CharT>,
>>>>                     const basic_format_args<_Context>&,
>>>>                     const locale* = nullptr);
>>>>
>>>>    template<typename _Out, typename _CharT>
>>>> -    format_to_n_result<_Out>
>>>> +    _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
>>>>      __do_vformat_to_n(_Out, iter_difference_t<_Out>,
>>>>                       basic_string_view<_CharT>,
>>>>                       const type_identity_t<
>>>> @@ -4982,11 +5035,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)
>>>> @@ -4999,7 +5054,7 @@ namespace __format
>>>>        basic_format_context& operator=(const basic_format_context&) =
>>>> delete;
>>>>
>>>>        template<typename _Out2, typename _CharT2, typename _Context2>
>>>> -       friend _Out2
>>>> +       friend _GLIBCXX26_CONSTEXPR _Out2
>>>>         __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
>>>>                                   const basic_format_args<_Context2>&,
>>>>                                   const locale*);
>>>> @@ -5015,7 +5070,7 @@ namespace __format
>>>>         using formatter_type = formatter<_Tp, _CharT>;
>>>>
>>>>        [[nodiscard]]
>>>> -      basic_format_arg<basic_format_context>
>>>> +      _GLIBCXX26_CONSTEXPR basic_format_arg<basic_format_context>
>>>>        arg(size_t __id) const noexcept
>>>>        { return _M_args.get(__id); }
>>>>
>>>> @@ -5023,9 +5078,11 @@ namespace __format
>>>>        std::locale locale() { return _M_loc.value(); }
>>>>
>>>>        [[nodiscard]]
>>>> -      iterator out() { return std::move(_M_out); }
>>>> +      _GLIBCXX26_CONSTEXPR iterator
>>>> +      out() { return std::move(_M_out); }
>>>>
>>>> -      void advance_to(iterator __it) { _M_out = std::move(__it); }
>>>> +      _GLIBCXX26_CONSTEXPR void
>>>> +      advance_to(iterator __it) { _M_out = std::move(__it); }
>>>>      };
>>>>
>>>>
>>>> @@ -5164,6 +5221,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)
>>>> @@ -5271,7 +5329,7 @@ namespace __format
>>>>      };
>>>>
>>>>    template<typename _Out, typename _CharT, typename _Context>
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>>>>                     const basic_format_args<_Context>& __args,
>>>>                     const locale* __loc)
>>>> @@ -5291,7 +5349,7 @@ namespace __format
>>>>                       const char* __chars[] = { "false", "true" };
>>>>                       if (auto __res = __out._M_reserve(__len))
>>>>                         {
>>>> -                         __builtin_memcpy(__res.get(), __chars[__arg],
>>>> __len);
>>>> +                         ranges::copy_n(__chars[__arg], __len,
>>>> __res.get());
>>>>                           __res._M_bump(__len);
>>>>                           __done = true;
>>>>                         }
>>>> @@ -5329,7 +5387,7 @@ namespace __format
>>>>                       string_view __sv = __arg;
>>>>                       if (auto __res = __out._M_reserve(__sv.size()))
>>>>                         {
>>>> -                         __builtin_memcpy(__res.get(), __sv.data(),
>>>> __sv.size());
>>>> +                         ranges::copy(__sv, __res.get());
>>>>                           __res._M_bump(__sv.size());
>>>>                           __done = true;
>>>>                         }
>>>> @@ -5347,14 +5405,16 @@ 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
>>>>         {
>>>> +         if constexpr (__contiguous_char_iter<_CharT, _Out>)
>>>> +           if (!std::is_constant_evaluated())
>>>> +             {
>>>> +               _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;
>>>> @@ -5362,7 +5422,7 @@ namespace __format
>>>>      }
>>>>
>>>>    template<typename _Out, typename _CharT>
>>>> -    format_to_n_result<_Out>
>>>> +    _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
>>>>      __do_vformat_to_n(_Out __out, iter_difference_t<_Out> __n,
>>>>                       basic_string_view<_CharT> __fmt,
>>>>                       const type_identity_t<
>>>> @@ -5402,7 +5462,11 @@ 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* __args = static_cast<_Parse_ctx*>(this)->_M_types;
>>>> +           // formatting scanner
>>>> +           if (!__args)
>>>> +             return;
>>>> +           auto __arg = __args[__id];
>>>>             __format::_Arg_t __types[] = {
>>>>               __format::__to_arg_t_enum<_CharT, _Ts>()...
>>>>             };
>>>> @@ -5432,14 +5496,14 @@ namespace __format
>>>>
>>>>    template<typename _Out> requires output_iterator<_Out, const char&>
>>>>      [[__gnu__::__always_inline__]]
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      vformat_to(_Out __out, string_view __fmt, format_args __args)
>>>>      { return __format::__do_vformat_to(std::move(__out), __fmt,
>>>> __args); }
>>>>
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    template<typename _Out> requires output_iterator<_Out, const
>>>> wchar_t&>
>>>>      [[__gnu__::__always_inline__]]
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
>>>>      { return __format::__do_vformat_to(std::move(__out), __fmt,
>>>> __args); }
>>>>  #endif
>>>> @@ -5465,7 +5529,7 @@ namespace __format
>>>>  #endif
>>>>
>>>>    [[nodiscard]]
>>>> -  inline string
>>>> +  inline _GLIBCXX26_CONSTEXPR string
>>>>    vformat(string_view __fmt, format_args __args)
>>>>    {
>>>>      __format::_Str_sink<char> __buf;
>>>> @@ -5475,7 +5539,7 @@ namespace __format
>>>>
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    [[nodiscard]]
>>>> -  inline wstring
>>>> +  inline _GLIBCXX26_CONSTEXPR wstring
>>>>    vformat(wstring_view __fmt, wformat_args __args)
>>>>    {
>>>>      __format::_Str_sink<wchar_t> __buf;
>>>> @@ -5506,14 +5570,14 @@ namespace __format
>>>>
>>>>    template<typename... _Args>
>>>>      [[nodiscard]]
>>>> -    inline string
>>>> +    inline _GLIBCXX26_CONSTEXPR string
>>>>      format(format_string<_Args...> __fmt, _Args&&... __args)
>>>>      { return std::vformat(__fmt.get(),
>>>> std::make_format_args(__args...)); }
>>>>
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    template<typename... _Args>
>>>>      [[nodiscard]]
>>>> -    inline wstring
>>>> +    inline _GLIBCXX26_CONSTEXPR wstring
>>>>      format(wformat_string<_Args...> __fmt, _Args&&... __args)
>>>>      { return std::vformat(__fmt.get(),
>>>> std::make_wformat_args(__args...)); }
>>>>  #endif
>>>> @@ -5542,7 +5606,7 @@ namespace __format
>>>>
>>>>    template<typename _Out, typename... _Args>
>>>>      requires output_iterator<_Out, const char&>
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      format_to(_Out __out, format_string<_Args...> __fmt, _Args&&...
>>>> __args)
>>>>      {
>>>>        return std::vformat_to(std::move(__out), __fmt.get(),
>>>> @@ -5552,7 +5616,7 @@ namespace __format
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    template<typename _Out, typename... _Args>
>>>>      requires output_iterator<_Out, const wchar_t&>
>>>> -    inline _Out
>>>> +    inline _GLIBCXX26_CONSTEXPR _Out
>>>>      format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&...
>>>> __args)
>>>>      {
>>>>        return std::vformat_to(std::move(__out), __fmt.get(),
>>>> @@ -5584,7 +5648,7 @@ namespace __format
>>>>
>>>>    template<typename _Out, typename... _Args>
>>>>      requires output_iterator<_Out, const char&>
>>>> -    inline format_to_n_result<_Out>
>>>> +    inline _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
>>>>      format_to_n(_Out __out, iter_difference_t<_Out> __n,
>>>>                 format_string<_Args...> __fmt, _Args&&... __args)
>>>>      {
>>>> @@ -5596,7 +5660,7 @@ namespace __format
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    template<typename _Out, typename... _Args>
>>>>      requires output_iterator<_Out, const wchar_t&>
>>>> -    inline format_to_n_result<_Out>
>>>> +    inline _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
>>>>      format_to_n(_Out __out, iter_difference_t<_Out> __n,
>>>>                 wformat_string<_Args...> __fmt, _Args&&... __args)
>>>>      {
>>>> @@ -5638,10 +5702,11 @@ namespace __format
>>>>      class _Counting_sink final : public _Ptr_sink<_CharT>
>>>>      {
>>>>      public:
>>>> +      _GLIBCXX26_CONSTEXPR
>>>>        _Counting_sink() : _Ptr_sink<_CharT>(nullptr, 0) { }
>>>>
>>>>        [[__gnu__::__always_inline__]]
>>>> -      size_t
>>>> +      _GLIBCXX26_CONSTEXPR size_t
>>>>        count() const
>>>>        { return this->_M_count + this->_M_used().size(); }
>>>>      };
>>>> @@ -5676,7 +5741,7 @@ namespace __format
>>>>
>>>>    template<typename... _Args>
>>>>      [[nodiscard]]
>>>> -    inline size_t
>>>> +    inline _GLIBCXX26_CONSTEXPR size_t
>>>>      formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
>>>>      {
>>>>        __format::_Counting_sink<char> __buf;
>>>> @@ -5688,7 +5753,7 @@ namespace __format
>>>>  #ifdef _GLIBCXX_USE_WCHAR_T
>>>>    template<typename... _Args>
>>>>      [[nodiscard]]
>>>> -    inline size_t
>>>> +    inline _GLIBCXX26_CONSTEXPR size_t
>>>>      formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
>>>>      {
>>>>        __format::_Counting_sink<wchar_t> __buf;
>>>> @@ -5759,6 +5824,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,
>>>> @@ -5778,14 +5844,16 @@ 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())
>>>>           { }
>>>>
>>>> -         void
>>>> +         _GLIBCXX26_CONSTEXPR void
>>>>           _M_disarm()
>>>>           { _M_ctx = nullptr; }
>>>>
>>>> +         _GLIBCXX26_CONSTEXPR
>>>>           ~_Restore_out()
>>>>           {
>>>>             if (_M_ctx)
>>>> @@ -5819,7 +5887,7 @@ namespace __format
>>>>        }
>>>>
>>>>        template<typename _Out>
>>>> -       void
>>>> +       _GLIBCXX26_CONSTEXPR void
>>>>         _M_format(__maybe_const<_Tp, _CharT>& __elem,
>>>>                   basic_format_context<_Out, _CharT>& __fc,
>>>>                   basic_string_view<_CharT> __sep) const
>>>> @@ -5917,12 +5985,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
>>>> @@ -5952,7 +6022,7 @@ namespace __format
>>>>           }
>>>>
>>>>           template<typename _Out>
>>>> -           void
>>>> +           _GLIBCXX26_CONSTEXPR void
>>>>             _M_format(__maybe_const<_Tps, _CharT>&... __elems,
>>>>                       basic_format_context<_Out, _CharT>& __fc,
>>>>                       _String_view __sep) const
>>>> @@ -5968,7 +6038,7 @@ namespace __format
>>>>         };
>>>>
>>>>        template<size_t... _Ids>
>>>> -       static auto
>>>> +       static _GLIBCXX26_CONSTEXPR auto
>>>>         _S_create_storage(index_sequence<_Ids...>)
>>>>           -> __formatters_storage<_Ids...>;
>>>>        using _Formatters
>>>> @@ -6004,6 +6074,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
>>>> @@ -6031,6 +6102,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
>>>> @@ -6194,6 +6266,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
>>>>         {
>>>> @@ -6206,6 +6279,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
>>>>         {
>>>> @@ -6223,6 +6297,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
>>>> @@ -6322,6 +6397,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/constexpr.cc
>>>> b/libstdc++-v3/testsuite/std/format/constexpr.cc
>>>> new file mode 100644
>>>> index 00000000000..675641cdbcb
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/std/format/constexpr.cc
>>>> @@ -0,0 +1,126 @@
>>>> +// { dg-do compile { target c++26 } }
>>>> +
>>>> +#include <format>
>>>> +#include <string>
>>>> +#include <string_view>
>>>> +#include <tuple>
>>>> +#include <vector>
>>>> +#include <testsuite_hooks.h>
>>>> +
>>>> +constexpr void
>>>> +test_format()
>>>> +{
>>>> +  using namespace std;
>>>> +  string res;
>>>> +
>>>> +  res = format("{}", 'c');
>>>> +  VERIFY( res == "c" );
>>>> +  res = format("{1} {0} {0}", 'a', 'b');
>>>> +  VERIFY( res == "b a a" );
>>>> +  res = format("{:?}", '\n');
>>>> +  VERIFY( res == "'\\n'" );
>>>> +  res = format("{:.^10}", "hello");
>>>> +  VERIFY( res == "..hello..." );
>>>> +  res = format("{:.>{}}", "world", 8);
>>>> +  VERIFY( res == "...world" );
>>>> +  res = format("{:+#06X}", 0xa);
>>>> +  VERIFY( res == "+0X00A" );
>>>> +  res = format("{:p}", nullptr);
>>>> +  VERIFY( res == "0x0" );
>>>> +  res = format("{:07P}", nullptr);
>>>> +  VERIFY( res == "0X00000" );
>>>> +  res = format("{} {}", true, false);
>>>> +  VERIFY( res == "true false" );
>>>> +  res = format("{:+#06b}", true);
>>>> +  VERIFY( res == "+0b001" );
>>>> +  res = format("{} {} {} {}", "abc", +"def", string_view("ghi"),
>>>> string("jkl"));
>>>> +  VERIFY( res == "abc def ghi jkl" );
>>>> +  res = format("{:?}", "hello\nworld");
>>>> +  VERIFY( res == "\"hello\\nworld\"" );
>>>> +  res = format("{}", tuple(1, true));
>>>> +  VERIFY( res == "(1, true)" );
>>>> +  res = format("{:t<12m}", tuple('a', "bc"));
>>>> +  VERIFY( res == "'a': \"bc\"ttt" );
>>>> +  res = format("{:n}", tuple(nullptr, -1, 1));
>>>> +  VERIFY( res == "0x0, -1, 1" );
>>>> +  res = format("{}", vector{1, 2, 3, 4});
>>>> +  VERIFY( res == "[1, 2, 3, 4]" );
>>>> +  res = format("{:?s}", vector{'a', '\n', 'b'});
>>>> +  VERIFY( res == "\"a\\nb\"" );
>>>> +  res = format("{:n:+}", vector{1, 2, 3});
>>>> +  VERIFY( res == "+1, +2, +3" );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_format_to()
>>>> +{
>>>> +  using namespace std;
>>>> +  char buf[100];
>>>> +  char* out;
>>>> +
>>>> +  out = format_to(buf, "{:.^5}", "foo");
>>>> +  VERIFY( string_view(buf, out) == ".foo." );
>>>> +  out = format_to(buf, "{} {}", nullptr, true);
>>>> +  VERIFY( string_view(buf, out) == "0x0 true" );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_vformat()
>>>> +{
>>>> +  using namespace std;
>>>> +  string res;
>>>> +
>>>> +  int arg1 = 1;
>>>> +  char arg2 = 'a';
>>>> +  bool arg3 = true;
>>>> +  res = vformat("{} {:?} {}", make_format_args(arg1, arg2, arg3));
>>>> +  VERIFY( res == "1 'a' true" );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_vformat_to()
>>>> +{
>>>> +  using namespace std;
>>>> +  char buf[100];
>>>> +  char* out;
>>>> +
>>>> +  nullptr_t arg1 = nullptr;
>>>> +  string arg2 = "foo";
>>>> +  tuple<int, int> arg3{-3, 5};
>>>> +  out = vformat_to(buf, "{} {:?} {}", make_format_args(arg1, arg2,
>>>> arg3));
>>>> +  VERIFY( string_view(buf, out) == "0x0 \"foo\" (-3, 5)" );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_format_to_n()
>>>> +{
>>>> +  using namespace std;
>>>> +  char buf[100];
>>>> +  format_to_n_result<char*> out;
>>>> +  int n;
>>>> +
>>>> +  n = 100;
>>>> +  out = format_to_n(buf, n, "{:+} {:?} {}", 1, "\n\n", vector{1, 2,
>>>> 3});
>>>> +  VERIFY( out.size <= n );
>>>> +  VERIFY( out.out - buf == out.size );
>>>> +  VERIFY( string_view(buf, out.size) == "+1 \"\\n\\n\" [1, 2, 3]" );
>>>> +  n = 12;
>>>> +  out = format_to_n(buf, n, "{} {} {}", true, nullptr, "long string");
>>>> +  VERIFY( out.size > n );
>>>> +  VERIFY( out.out - buf == n );
>>>> +  VERIFY( string_view(buf, out.out) == "true 0x0 lon" );
>>>> +}
>>>> +
>>>> +constexpr bool
>>>> +all_tests()
>>>> +{
>>>> +  test_format();
>>>> +  test_format_to();
>>>> +  test_vformat();
>>>> +  test_vformat_to();
>>>> +  test_format_to_n();
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +static_assert(all_tests());
>>>> diff --git a/libstdc++-v3/testsuite/std/format/debug.cc
>>>> b/libstdc++-v3/testsuite/std/format/debug.cc
>>>> index 43e930c579e..c45659d0d69 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/debug.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/debug.cc
>>>> @@ -1,14 +1,20 @@
>>>> -// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE
>>>> -DUNICODE_ENC" { target le } }
>>>> -// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE
>>>> -DUNICODE_ENC" { target be } }
>>>> +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE
>>>> -DUNICODE_ENC -fconstexpr-ops-limit=500000000" { target le } }
>>>> +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE
>>>> -DUNICODE_ENC -fconstexpr-ops-limit=500000000" { target be } }
>>>>  // { dg-do run { target c++23 } }
>>>>  // { dg-require-effective-target 4byte_wchar_t }
>>>>  // { dg-add-options no_pch }
>>>>  // { dg-timeout-factor 2 }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>  #include <testsuite_hooks.h>
>>>>
>>>> -std::string
>>>> +constexpr26 std::string
>>>>  fdebug(char t)
>>>>  { return std::format("{:?}", t); }
>>>>
>>>> @@ -16,7 +22,7 @@ std::wstring
>>>>  fdebug(wchar_t t)
>>>>  { return std::format(L"{:?}", t); }
>>>>
>>>> -std::string
>>>> +constexpr26 std::string
>>>>  fdebug(std::string_view t)
>>>>  { return std::format("{:?}", t); }
>>>>
>>>> @@ -29,7 +35,7 @@ fdebug(std::wstring_view t)
>>>>  #define WIDEN(S) WIDEN_(CharT, S)
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_basic_escapes()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -72,7 +78,7 @@ test_basic_escapes()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_ascii_escapes()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -89,7 +95,7 @@ test_ascii_escapes()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_extended_ascii()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -117,7 +123,7 @@ test_extended_ascii()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_unicode_escapes()
>>>>  {
>>>>  #if UNICODE_ENC
>>>> @@ -166,7 +172,7 @@ test_unicode_escapes()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_grapheme_extend()
>>>>  {
>>>>  #if UNICODE_ENC
>>>> @@ -192,7 +198,7 @@ test_grapheme_extend()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_replacement_char()
>>>>  {
>>>>  #if UNICODE_ENC
>>>> @@ -206,7 +212,7 @@ test_replacement_char()
>>>>  #endif // UNICODE_ENC
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_ill_formed_utf8_seq()
>>>>  {
>>>>  #if UNICODE_ENC
>>>> @@ -269,7 +275,7 @@ test_ill_formed_utf32()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_fill()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -315,7 +321,7 @@ test_fill()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_prec()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -341,7 +347,8 @@ test_prec()
>>>>  #endif // UNICODE_ENC
>>>>  }
>>>>
>>>> -bool strip_quote(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_quote(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('"'))
>>>>      return false;
>>>> @@ -349,7 +356,8 @@ bool strip_quote(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_quotes(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_quotes(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('"') || !v.ends_with('"'))
>>>>      return false;
>>>> @@ -358,7 +366,8 @@ bool strip_quotes(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_prefix(std::string_view& v, size_t n, char c)
>>>> +constexpr26 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)
>>>> @@ -369,7 +378,8 @@ bool strip_prefix(std::string_view& v, size_t n,
>>>> char c)
>>>>    return true;
>>>>  }
>>>>
>>>> -void test_padding()
>>>> +constexpr26 void
>>>> +test_padding()
>>>>  {
>>>>    std::string res;
>>>>    std::string_view resv;
>>>> @@ -751,8 +761,9 @@ struct std::formatter<DebugWrapper<T>, CharT>
>>>>    }
>>>>
>>>>    template<typename Out>
>>>> -  Out format(DebugWrapper<T> const& t,
>>>> -            std::basic_format_context<Out, CharT>& fc) const
>>>> +  constexpr26 Out
>>>> +  format(DebugWrapper<T> const& t,
>>>> +        std::basic_format_context<Out, CharT>& fc) const
>>>>    { return under.format(t.val, fc); }
>>>>
>>>>  private:
>>>> @@ -760,7 +771,7 @@ private:
>>>>  };
>>>>
>>>>  template<typename CharT, typename StrT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_formatter_str()
>>>>  {
>>>>    CharT buf[]{ 'a', 'b', 'c', 0 };
>>>> @@ -770,7 +781,7 @@ test_formatter_str()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_formatter_arr()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>> @@ -786,7 +797,7 @@ test_formatter_arr()
>>>>  }
>>>>
>>>>  template<typename CharT, typename SrcT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_formatter_char()
>>>>  {
>>>>    DebugWrapper<SrcT> in{ 'a' };
>>>> @@ -795,7 +806,7 @@ test_formatter_char()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void
>>>> +constexpr26 void
>>>>  test_formatters()
>>>>  {
>>>>    test_formatter_char<CharT, CharT>();
>>>> @@ -806,38 +817,60 @@ test_formatters()
>>>>    test_formatter_arr<CharT>();
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_formatters_c()
>>>>  {
>>>>    test_formatters<char>();
>>>> -  test_formatters<wchar_t>();
>>>> -  test_formatter_char<wchar_t, char>();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_formatters<wchar_t>();
>>>> +      test_formatter_char<wchar_t, char>();
>>>> +    }
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    test_basic_escapes<char>();
>>>> -  test_basic_escapes<wchar_t>();
>>>>    test_ascii_escapes<char>();
>>>> -  test_ascii_escapes<wchar_t>();
>>>>    test_extended_ascii<char>();
>>>> -  test_extended_ascii<wchar_t>();
>>>>
>>>>    test_unicode_escapes<char>();
>>>> -  test_unicode_escapes<wchar_t>();
>>>>    test_grapheme_extend<char>();
>>>> -  test_grapheme_extend<wchar_t>();
>>>>    test_replacement_char<char>();
>>>> -  test_replacement_char<wchar_t>();
>>>>    test_ill_formed_utf8_seq();
>>>> -  test_ill_formed_utf32();
>>>>
>>>>    test_fill<char>();
>>>> -  test_fill<wchar_t>();
>>>>    test_prec<char>();
>>>> -  test_prec<wchar_t>();
>>>> +
>>>> +  // constexpr wide formatting not yet implemented
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_basic_escapes<wchar_t>();
>>>> +      test_ascii_escapes<wchar_t>();
>>>> +      test_extended_ascii<wchar_t>();
>>>> +
>>>> +      test_unicode_escapes<wchar_t>();
>>>> +      test_grapheme_extend<wchar_t>();
>>>> +      test_replacement_char<wchar_t>();
>>>> +      test_ill_formed_utf32();
>>>> +
>>>> +      test_fill<wchar_t>();
>>>> +      test_prec<wchar_t>();
>>>> +    }
>>>>
>>>>    test_padding();
>>>>
>>>>    test_formatters_c();
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc
>>>> b/libstdc++-v3/testsuite/std/format/functions/format.cc
>>>> index d342114083e..9d921d59d5f 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/functions/format.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
>>>> @@ -3,6 +3,12 @@
>>>>  // { dg-add-options no_pch }
>>>>  // { dg-additional-options "-DUNICODE" { target 4byte_wchar_t } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>
>>>>  #ifndef __cpp_lib_format
>>>> @@ -41,7 +47,7 @@
>>>>  #include <cstdio>
>>>>  #include <testsuite_hooks.h>
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_no_args()
>>>>  {
>>>>    std::string s;
>>>> @@ -55,6 +61,7 @@ test_no_args()
>>>>    VERIFY( s == "128bpm }" );
>>>>  }
>>>>
>>>> +// not constexpr because of PR124145
>>>>  void
>>>>  test_unescaped()
>>>>  {
>>>> @@ -78,7 +85,7 @@ struct brit_punc : std::numpunct<char>
>>>>    std::string do_falsename() const override { return "nah bruv"; }
>>>>  };
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_std_examples()
>>>>  {
>>>>    using namespace std;
>>>> @@ -125,10 +132,13 @@ 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 (!std::is_constant_evaluated())
>>>> +      {
>>>> +       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,34 +153,35 @@ test_std_examples()
>>>>    }
>>>>
>>>>    // integer presentation types
>>>> -  {
>>>> -    // Change global locale so "{:L}" adds digit separators.
>>>> -    std::locale::global(std::locale({}, new brit_punc));
>>>> -
>>>> -    string s0 = format("{}", 42);
>>>> -    VERIFY(s0 == "42");
>>>> -    string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42);
>>>> -    VERIFY(s1 == "101010 42 52 2a");
>>>> -    string s2 = format("{0:#x} {0:#X}", 42);
>>>> -    VERIFY(s2 == "0x2a 0X2A");
>>>> -    string s3 = format("{:L}", 1234);
>>>> -    VERIFY(s3 == "1,234");
>>>> -
>>>> -    // Test locale's "byte-and-a-half" grouping (Imperial word?
>>>> tribble?).
>>>> -    string s4 = format("{:#Lx}", 0xfffff);
>>>> -    VERIFY(s4 == "0xff,fff");
>>>> -
>>>> -    // Restore
>>>> -    std::locale::global(std::locale::classic());
>>>> -
>>>> -    string s5 = format("{}", -100); // PR libstdc++/114325
>>>> -    VERIFY(s5 == "-100");
>>>> -    string s6 = format("{:d} {:d}", -123, 999);
>>>> -    VERIFY(s6 == "-123 999");
>>>> -  }
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      // Change global locale so "{:L}" adds digit separators.
>>>> +      std::locale::global(std::locale({}, new brit_punc));
>>>> +
>>>> +      string s0 = format("{}", 42);
>>>> +      VERIFY(s0 == "42");
>>>> +      string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42);
>>>> +      VERIFY(s1 == "101010 42 52 2a");
>>>> +      string s2 = format("{0:#x} {0:#X}", 42);
>>>> +      VERIFY(s2 == "0x2a 0X2A");
>>>> +      string s3 = format("{:L}", 1234);
>>>> +      VERIFY(s3 == "1,234");
>>>> +
>>>> +      // Test locale's "byte-and-a-half" grouping (Imperial word?
>>>> tribble?).
>>>> +      string s4 = format("{:#Lx}", 0xfffff);
>>>> +      VERIFY(s4 == "0xff,fff");
>>>> +
>>>> +      // Restore
>>>> +      std::locale::global(std::locale::classic());
>>>> +
>>>> +      string s5 = format("{}", -100); // PR libstdc++/114325
>>>> +      VERIFY(s5 == "-100");
>>>> +      string s6 = format("{:d} {:d}", -123, 999);
>>>> +      VERIFY(s6 == "-123 999");
>>>> +    }
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_alternate_forms()
>>>>  {
>>>>    std::string s;
>>>> @@ -180,23 +191,26 @@ 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" );
>>>> -
>>>> -  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++/113512
>>>> -  s = std::format("{:#.3g}", 0.025);
>>>> -  VERIFY( s == "0.0250" );
>>>> -  s = std::format("{:#07.3g}", 0.02);
>>>> -  VERIFY( s == "00.0200" );
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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" );
>>>> +
>>>> +      // 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" );
>>>> +    }
>>>>  }
>>>>
>>>>  void
>>>> @@ -275,7 +289,7 @@ test_locale()
>>>>    std::locale::global(cloc);
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_width()
>>>>  {
>>>>    std::string s;
>>>> @@ -294,30 +308,34 @@ 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&) {
>>>> -  }
>>>> -
>>>> -  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&) {
>>>> -  }
>>>> +  // not constexpr because of PR124145
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 {
>>>> +       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
>>>> +constexpr26 void
>>>>  test_char()
>>>>  {
>>>>    std::string s;
>>>> @@ -347,6 +365,7 @@ test_char()
>>>>    VERIFY( s == "11110000 11110000 240 360 f0 F0" );
>>>>  }
>>>>
>>>> +// constexpr wide formatting not yet implemented
>>>>  void
>>>>  test_wchar()
>>>>  {
>>>> @@ -395,7 +414,7 @@ test_wchar()
>>>>    VERIFY( ws == L"0.5" );
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_minmax()
>>>>  {
>>>>    auto check = []<typename T, typename U = std::make_unsigned_t<T>>(T,
>>>> U = 0) {
>>>> @@ -422,7 +441,7 @@ test_minmax()
>>>>  #endif
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_p1652r1() // printf corner cases in std::format
>>>>  {
>>>>    std::string s;
>>>> @@ -436,27 +455,33 @@ 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&) {
>>>> -  }
>>>> -
>>>> -  s = std::format("{:06}", nan);
>>>> -  VERIFY( s == "   nan" );
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      // 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" );
>>>> +    }
>>>>
>>>>    // 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      // Problem 5: double does not roundtrip float
>>>> +      s = std::format("{}", 3.31f);
>>>> +      VERIFY( s == "3.31" );
>>>> +    }
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_pointer()
>>>>  {
>>>>    void* p = nullptr;
>>>> @@ -477,28 +502,31 @@ 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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
>>>> +constexpr26 void
>>>>  test_bool()
>>>>  {
>>>>    std::string s;
>>>> @@ -519,7 +547,7 @@ test_bool()
>>>>    VERIFY( s == "0 0x1 0X0" );
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_unicode()
>>>>  {
>>>>  #ifdef UNICODE
>>>> @@ -579,19 +607,36 @@ test_unicode()
>>>>  #endif
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_unescaped();
>>>> +      test_infnan();
>>>> +      test_locale();
>>>> +      test_wchar();
>>>> +    }
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>>>> b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>>>> index 94e6262bc66..ae6ffb3a562 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>>>> @@ -1,5 +1,11 @@
>>>>  // { dg-do run { target c++20 } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>  #include <locale>
>>>>  #include <vector>
>>>> @@ -11,17 +17,20 @@ struct punct : std::numpunct<char>
>>>>    std::string do_grouping() const override { return "\2"; }
>>>>  };
>>>>
>>>> -void
>>>> +constexpr26 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 +38,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 +60,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
>>>> +constexpr26 void
>>>>  test_move_only()
>>>>  {
>>>>    std::string str;
>>>> @@ -72,14 +82,17 @@ 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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
>>>> +constexpr26 void
>>>>  test_pr110917()
>>>>  {
>>>>    // PR libstdc++/110917
>>>> @@ -90,10 +103,24 @@ test_pr110917()
>>>>    VERIFY( ! std::memcmp(buf, "abc 123", 7) );
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    test();
>>>> -  test_wchar();
>>>>    test_move_only();
>>>>    test_pr110917();
>>>> +
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_wchar();
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/functions/size.cc
>>>> b/libstdc++-v3/testsuite/std/format/functions/size.cc
>>>> index 1ece4108d85..24220f632fe 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/functions/size.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/functions/size.cc
>>>> @@ -1,10 +1,16 @@
>>>>  // { dg-do run { target c++20 } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>  #include <string>
>>>>  #include <testsuite_hooks.h>
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test()
>>>>  {
>>>>    auto n = std::formatted_size("");
>>>> @@ -44,8 +50,20 @@ test_wchar()
>>>>    VERIFY( n == 5 );
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    test();
>>>> -  test_wchar();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_wchar();
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>>>> b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>>>> index 1450fbaebc5..48795440d13 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>>>> @@ -1,5 +1,11 @@
>>>>  // { dg-do run { target c++23 } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <deque>
>>>>  #include <flat_map>
>>>>  #include <flat_set>
>>>> @@ -64,7 +70,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()
>>>> +constexpr26 bool
>>>> +test_override()
>>>>  {
>>>>    CustFormat<int, std::range_format::disabled> disabledf;
>>>>    static_assert( !std::formattable<decltype(disabledf), char> );
>>>> @@ -88,8 +95,14 @@ void test_override()
>>>>    VERIFY( std::format("{}", debugf) == R"("abcd")" );
>>>>    // Support precision as string do
>>>>    VERIFY( std::format("{:.3}", debugf) == R"("ab)" );
>>>> +
>>>> +  return true;
>>>>  }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +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..3bd5f37403e 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
>>>> @@ -1,5 +1,11 @@
>>>>  // { dg-do run { target c++23 } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <flat_map>
>>>>  #include <format>
>>>>  #include <testsuite_hooks.h>
>>>> @@ -32,7 +38,7 @@ struct std::formatter<MyVector<T, Formatter>, CharT>
>>>>    { return _formatter.parse(pc);  }
>>>>
>>>>    template<typename Out>
>>>> -  typename std::basic_format_context<Out, CharT>::iterator
>>>> +  constexpr26 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 +48,7 @@ private:
>>>>  };
>>>>
>>>>  template<typename CharT, template<typename, typename> class Formatter>
>>>> -void
>>>> +constexpr26 void
>>>>  test_default()
>>>>  {
>>>>    MyVector<int, Formatter> vec{1, 2, 3};
>>>> @@ -94,7 +100,7 @@ test_default()
>>>>  }
>>>>
>>>>  template<typename CharT, template<typename, typename> class Formatter>
>>>> -void
>>>> +constexpr26 void
>>>>  test_override()
>>>>  {
>>>>    MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
>>>> @@ -115,15 +121,20 @@ test_override()
>>>>  }
>>>>
>>>>  template<template<typename, typename> class Formatter>
>>>> -void test_outputs()
>>>> +constexpr26 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_default<wchar_t, Formatter>();
>>>> +      test_override<wchar_t, Formatter>();
>>>> +    }
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_nested()
>>>>  {
>>>>    MyVector<MyVector<int>> v
>>>> @@ -152,7 +163,8 @@ struct std::formatter<MyFlatMap, CharT>
>>>>    : std::range_formatter<MyFlatMap::reference>
>>>>  {};
>>>>
>>>> -void test_const_ref_type_mismatch()
>>>> +constexpr26 void
>>>> +test_const_ref_type_mismatch()
>>>>  {
>>>>    MyFlatMap m{{1, 11}, {2, 22}};
>>>>    std::string res = std::format("{:m}", m);
>>>> @@ -163,13 +175,15 @@ template<typename T, typename CharT>
>>>>  using VectorFormatter = std::formatter<std::vector<T>, CharT>;
>>>>
>>>>  template<template<typename> typename Range>
>>>> -void test_nonblocking()
>>>> +constexpr26 void
>>>> +test_nonblocking()
>>>>  {
>>>>    static_assert(!std::enable_nonlocking_formatter_optimization<
>>>>                   Range<int>>);
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    test_outputs<std::range_formatter>();
>>>>    test_outputs<VectorFormatter>();
>>>> @@ -179,4 +193,15 @@ int main()
>>>>    test_nonblocking<std::span>();
>>>>    test_nonblocking<std::vector>();
>>>>    test_nonblocking<MyVector>();
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>>>> b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>>>> index 7fb65f9c551..da1fe7e0df7 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>>>> @@ -1,7 +1,13 @@
>>>>  // { dg-do run { target c++23 } }
>>>> -// { dg-options "-fexec-charset=UTF-8" }
>>>> +// { dg-options "-fexec-charset=UTF-8
>>>> -fconstexpr-ops-limit=5000000000" }
>>>>  // { dg-timeout-factor 2 }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <array>
>>>>  #include <format>
>>>>  #include <list>
>>>> @@ -19,7 +25,7 @@
>>>> static_assert(!std::formattable<std::vector<NotFormattable>, char>);
>>>>  static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>);
>>>>
>>>>  template<typename... Args>
>>>> -bool
>>>> +constexpr26 bool
>>>>  is_format_string_for(const char* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -31,7 +37,7 @@ is_format_string_for(const char* str, Args&&... args)
>>>>  }
>>>>
>>>>  template<typename... Args>
>>>> -bool
>>>> +constexpr26 bool
>>>>  is_format_string_for(const wchar_t* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -43,7 +49,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)
>>>> +constexpr26 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 +63,7 @@ bool is_range_formatter_spec_for(CharT const* spec,
>>>> Rg&& rg)
>>>>    }
>>>>  }
>>>>
>>>> +// not constexpr because of PR124145
>>>>  void
>>>>  test_format_string()
>>>>  {
>>>> @@ -79,7 +87,8 @@ test_format_string()
>>>>  #define WIDEN(S) WIDEN_(CharT, S)
>>>>
>>>>  template<typename CharT, typename Range, typename Storage>
>>>> -void test_output()
>>>> +constexpr26 void
>>>> +test_output()
>>>>  {
>>>>    using Sv = std::basic_string_view<CharT>;
>>>>    using T = std::ranges::range_value_t<Range>;
>>>> @@ -153,25 +162,32 @@ void test_output()
>>>>  }
>>>>
>>>>  template<typename Cont>
>>>> -void test_output_cont()
>>>> +constexpr26 void
>>>> +test_output_cont()
>>>>  {
>>>>    test_output<char, Cont&, Cont>();
>>>> -  test_output<wchar_t, Cont const&, Cont>();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_output<wchar_t, Cont const&, Cont>();
>>>>  }
>>>>
>>>>  template<typename View>
>>>> -void test_output_view()
>>>> +constexpr26 void
>>>> +test_output_view()
>>>>  {
>>>>    test_output<char, View, int[3]>();
>>>> -  test_output<wchar_t, View, int[3]>();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_output<wchar_t, View, int[3]>();
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_outputs()
>>>>  {
>>>>    using namespace __gnu_test;
>>>>    test_output_cont<std::vector<int>>();
>>>> -  test_output_cont<std::list<int>>();
>>>> +
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_output_cont<std::list<int>>();
>>>> +
>>>>    test_output_cont<std::array<int, 3>>();
>>>>
>>>>    test_output_view<std::span<int>>();
>>>> @@ -185,7 +201,7 @@ test_outputs()
>>>>    test_output_view<test_forward_range<const int>>();
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_nested()
>>>>  {
>>>>    std::vector<std::vector<int>> v
>>>> @@ -201,7 +217,8 @@ test_nested()
>>>>    VERIFY( res == "+[01, 02, 11, 12]+" );
>>>>  }
>>>>
>>>> -bool strip_quote(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_quote(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('"'))
>>>>      return false;
>>>> @@ -209,7 +226,8 @@ bool strip_quote(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_prefix(std::string_view& v, std::string_view expected, bool
>>>> quoted = false)
>>>> +constexpr26 bool
>>>> +strip_prefix(std::string_view& v, std::string_view expected, bool
>>>> quoted = false)
>>>>  {
>>>>    if (quoted && !strip_quote(v))
>>>>      return false;
>>>> @@ -221,7 +239,8 @@ bool strip_prefix(std::string_view& v,
>>>> std::string_view expected, bool quoted =
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_squares(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_squares(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('[') || !v.ends_with(']'))
>>>>      return false;
>>>> @@ -230,7 +249,8 @@ bool strip_squares(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_prefix(std::string_view& v, size_t n, char c)
>>>> +constexpr26 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 +261,8 @@ bool strip_prefix(std::string_view& v, size_t n,
>>>> char c)
>>>>    return true;
>>>>  }
>>>>
>>>> -void test_padding()
>>>> +constexpr26 void
>>>> +test_padding()
>>>>  {
>>>>    std::string res;
>>>>    std::string_view resv;
>>>> @@ -323,10 +344,24 @@ void test_padding()
>>>>    VERIFY( check_elems(resv, false) );
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>> -  test_format_string();
>>>>    test_outputs();
>>>>    test_nested();
>>>>    test_padding();
>>>> +
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_format_string();
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/runtime_format.cc
>>>> b/libstdc++-v3/testsuite/std/format/runtime_format.cc
>>>> index f2bfa5b434d..6bb402a4108 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/runtime_format.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/runtime_format.cc
>>>> @@ -3,7 +3,7 @@
>>>>  #include <format>
>>>>  #include <testsuite_hooks.h>
>>>>
>>>> -void
>>>> +constexpr void
>>>>  test_char()
>>>>  {
>>>>    std::string fmt = "{}";
>>>> @@ -19,7 +19,7 @@ test_wchar()
>>>>    VERIFY( s == L"0710" );
>>>>  }
>>>>
>>>> -void
>>>> +constexpr void
>>>>  test_internal_api()
>>>>  {
>>>>    // Using _Runtime_format_string directly works even in C++20 mode.
>>>> @@ -40,9 +40,19 @@ static_assert(
>>>> !std::is_constructible_v<std::format_string<>,
>>>>  static_assert( !std::is_constructible_v<std::wformat_string<>,
>>>>
>>>> decltype(std::runtime_format(L""))&&> );
>>>>
>>>> -int main()
>>>> +constexpr bool
>>>> +test_all()
>>>>  {
>>>>    test_char();
>>>> -  test_wchar();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_wchar();
>>>>    test_internal_api();
>>>> +  return true;
>>>> +}
>>>> +
>>>> +static_assert(test_all());
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/string.cc
>>>> b/libstdc++-v3/testsuite/std/format/string.cc
>>>> index ee987a15ec3..90222db90aa 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/string.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/string.cc
>>>> @@ -1,10 +1,16 @@
>>>>  // { dg-do run { target c++20 } }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>  #include <testsuite_hooks.h>
>>>>
>>>>  template<typename... Args>
>>>> -bool
>>>> +constexpr26 bool
>>>>  is_format_string_for(const char* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -16,7 +22,7 @@ is_format_string_for(const char* str, Args&&... args)
>>>>  }
>>>>
>>>>  template<typename... Args>
>>>> -bool
>>>> +constexpr26 bool
>>>>  is_format_string_for(const wchar_t* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -27,28 +33,37 @@ is_format_string_for(const wchar_t* str, Args&&...
>>>> args)
>>>>    }
>>>>  }
>>>>
>>>> -void
>>>> +constexpr26 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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
>>>> +constexpr26 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 +71,14 @@ 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 +87,7 @@ constexpr bool escaped_strings_supported = true;
>>>>  constexpr bool escaped_strings_supported = false;
>>>>  #endif
>>>>
>>>> -void
>>>> +constexpr26 void
>>>>  test_format_spec()
>>>>  {
>>>>    VERIFY( is_format_string_for("{:}", 1) );
>>>> @@ -78,92 +97,114 @@ 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      // 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) );
>>>> +
>>>> +  // not constexpr because of PR124145
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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)) );
>>>> +      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) );
>>>> +      // 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 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") );
>>>> +      // 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 (!std::is_constant_evaluated())
>>>> +    {
>>>> +      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 +219,7 @@ test_pr110862()
>>>>    }
>>>>  }
>>>>
>>>> +// not constexpr because of PR124145
>>>>  void
>>>>  test_pr110974()
>>>>  {
>>>> @@ -197,11 +239,27 @@ test_pr110974()
>>>>    }
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>>    test_no_args();
>>>>    test_indexing();
>>>>    test_format_spec();
>>>> -  test_pr110862();
>>>> -  test_pr110974();
>>>> +
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_pr110862();
>>>> +      test_pr110974();
>>>> +    }
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc
>>>> b/libstdc++-v3/testsuite/std/format/tuple.cc
>>>> index eace82730f0..10e19149935 100644
>>>> --- a/libstdc++-v3/testsuite/std/format/tuple.cc
>>>> +++ b/libstdc++-v3/testsuite/std/format/tuple.cc
>>>> @@ -2,6 +2,12 @@
>>>>  // { dg-options "-fexec-charset=UTF-8" }
>>>>  // { dg-timeout-factor 2 }
>>>>
>>>> +#if __cplusplus >= 202400L
>>>> +# define constexpr26 constexpr
>>>> +#else
>>>> +# define constexpr26
>>>> +#endif
>>>> +
>>>>  #include <format>
>>>>  #include <string>
>>>>  #include <testsuite_hooks.h>
>>>> @@ -15,7 +21,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
>>>> +constexpr26 bool
>>>>  is_format_string_for(const char* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -27,7 +33,7 @@ is_format_string_for(const char* str, Args&&... args)
>>>>  }
>>>>
>>>>  template<typename... Args>
>>>> -bool
>>>> +constexpr26 bool
>>>>  is_format_string_for(const wchar_t* str, Args&&... args)
>>>>  {
>>>>    try {
>>>> @@ -41,6 +47,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 +130,8 @@ void test_multi()
>>>>  }
>>>>
>>>>  template<typename CharT, typename Tuple>
>>>> -void test_empty()
>>>> +constexpr26 void
>>>> +test_empty()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>>
>>>> @@ -142,7 +150,8 @@ void test_empty()
>>>>  }
>>>>
>>>>  template<typename CharT, typename Pair>
>>>> -void test_pair()
>>>> +constexpr26 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 +176,8 @@ void test_pair()
>>>>  }
>>>>
>>>>  template<typename CharT, template<typename, typename> class PairT>
>>>> -void test_pair_e()
>>>> +constexpr26 void
>>>> +test_pair_e()
>>>>  {
>>>>    test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
>>>>    test_pair<CharT, PairT<int, const CharT*>>();
>>>> @@ -196,7 +206,7 @@ struct std::formatter<MyPair<Pair>, CharT>
>>>>    { return _formatter.parse(pc);  }
>>>>
>>>>    template<typename Out>
>>>> -  typename std::basic_format_context<Out, CharT>::iterator
>>>> +  constexpr26 typename std::basic_format_context<Out, CharT>::iterator
>>>>    format(const MyPair<Pair>& mp,
>>>>          std::basic_format_context<Out, CharT>& fc) const
>>>>    { return _formatter.format(mp, fc); }
>>>> @@ -206,7 +216,8 @@ private:
>>>>  };
>>>>
>>>>  template<typename CharT, template<typename, typename> class PairT>
>>>> -void test_custom()
>>>> +constexpr26 void
>>>> +test_custom()
>>>>  {
>>>>    std::basic_string<CharT> res;
>>>>    MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc"));
>>>> @@ -228,9 +239,12 @@ void test_custom()
>>>>  }
>>>>
>>>>  template<typename CharT>
>>>> -void test_outputs()
>>>> +constexpr26 void
>>>> +test_outputs()
>>>>  {
>>>> -  test_multi<CharT>();
>>>> +  if (!std::is_constant_evaluated())
>>>> +    test_multi<CharT>();
>>>> +
>>>>    test_empty<CharT, std::tuple<>>();
>>>>    test_pair_e<CharT, std::pair>();
>>>>    test_pair_e<CharT, std::tuple>();
>>>> @@ -238,7 +252,8 @@ void test_outputs()
>>>>    test_custom<CharT, std::tuple>();
>>>>  }
>>>>
>>>> -void test_nested()
>>>> +constexpr26 void
>>>> +test_nested()
>>>>  {
>>>>    std::string res;
>>>>    std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1,
>>>> "abc"}};
>>>> @@ -251,7 +266,8 @@ void test_nested()
>>>>    VERIFY( res == R"((): (1, "abc"))" );
>>>>  }
>>>>
>>>> -bool strip_quote(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_quote(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('"'))
>>>>      return false;
>>>> @@ -259,7 +275,8 @@ bool strip_quote(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_prefix(std::string_view& v, std::string_view expected, bool
>>>> quoted = false)
>>>> +constexpr26 bool
>>>> +strip_prefix(std::string_view& v, std::string_view expected, bool
>>>> quoted = false)
>>>>  {
>>>>    if (quoted && !strip_quote(v))
>>>>      return false;
>>>> @@ -271,7 +288,8 @@ bool strip_prefix(std::string_view& v,
>>>> std::string_view expected, bool quoted =
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_parens(std::string_view& v)
>>>> +constexpr26 bool
>>>> +strip_parens(std::string_view& v)
>>>>  {
>>>>    if (!v.starts_with('(') || !v.ends_with(')'))
>>>>      return false;
>>>> @@ -280,7 +298,8 @@ bool strip_parens(std::string_view& v)
>>>>    return true;
>>>>  }
>>>>
>>>> -bool strip_prefix(std::string_view& v, size_t n, char c)
>>>> +constexpr26 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 +310,8 @@ bool strip_prefix(std::string_view& v, size_t n,
>>>> char c)
>>>>    return true;
>>>>  }
>>>>
>>>> -void test_padding()
>>>> +constexpr26 void
>>>> +test_padding()
>>>>  {
>>>>    std::string res;
>>>>    std::string_view resv;
>>>> @@ -351,13 +371,14 @@ struct std::formatter<Custom, CharT>
>>>>    { return pc.begin();  }
>>>>
>>>>    template<typename Out>
>>>> -  typename std::basic_format_context<Out, CharT>::iterator
>>>> +  constexpr26 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()
>>>> +constexpr26 void
>>>> +test_nonblocking()
>>>>  {
>>>>    static_assert(std::enable_nonlocking_formatter_optimization<
>>>>                   Tuple<int, float>>);
>>>> @@ -374,14 +395,31 @@ void test_nonblocking()
>>>>                   Tuple<Custom&, float&>>);
>>>>  }
>>>>
>>>> -int main()
>>>> +constexpr26 bool
>>>> +test_all()
>>>>  {
>>>> -  test_format_string();
>>>>    test_outputs<char>();
>>>> -  test_outputs<wchar_t>();
>>>>    test_nested();
>>>>    test_padding();
>>>>
>>>>    test_nonblocking<std::pair>();
>>>>    test_nonblocking<std::tuple>();
>>>> +
>>>> +  if (!std::is_constant_evaluated())
>>>> +    {
>>>> +      test_format_string();
>>>> +      // constexpr wide formatting not yet implemented
>>>> +      test_outputs<wchar_t>();
>>>> +    }
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +#if __cplusplus >= 202400L
>>>> +static_assert(test_all());
>>>> +#endif
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test_all();
>>>>  }
>>>> --
>>>> 2.43.0
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260302/c8f40dbe/attachment-0001.htm>


More information about the Libstdc++ mailing list