On Mon, 1 Jun 2026 at 16:58, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Mon, Jun 1, 2026 at 5:48 PM Jonathan Wakely <[email protected]> wrote:
>>
>> On Fri, 15 May 2026 at 10:53 +0200, Tomasz Kamiński wrote:
>> >From: Ivan Lazaric <[email protected]>
>> >
>> >This patch implements constexpr formatting from P3391R2,
>> >and introduces the constexpr_format feature-test macro.
>> >Since pre-cxx11 cow_string is not constexpr-enabled,
>> >only exposing the feature-test macro under cxx11 ABI.
>> >
>> >Add `__format::__toupper_numeric` function that work in constexpr.
>> >It is not fully general, but `<format>` doesn't need all uppercasing.
>> >
>> >The `__write_escaped_ascii` is not marked constexpr, to enable
>> >futhure improvement for non-unicode literal encodings (for example
>> >using `iconv`).
>> >
>> >Update `__check_dynamic_spec` to check if `__args` is run, to
>> >accomodate for dynamic_format or vformat invoked at compile time.
>> >
>> >Mark `basic_format_string` consteval constructor noexcept,
>> >since exceptions are now constexpr, and the standard mandates
>> >failure to parse to be non-catchable ill-formed.
>> >https://eel.is/c++draft/format#fmt.string-3
>> >> Remarks: A call to this function is not a core constant expression
>> >> ([expr.const]) unless there exist args of types Args such that
>> >> str is a format string for args.
>> >
>> >Update some formatting tests to test constexpr as well,
>> >and introduce a dedicated smoke test for constexpr formatting.
>> >
>> >libstdc++-v3/include/ChangeLog:
>>
>> There is no ChangeLog file in the include directory, nor in the
>> testsuite directory. There is only libstdc++-v3/ChangeLog, so
>> everything should be a single ChangeLog entry.
>>
>> >
>> >        * bits/version.def (constexpr_exceptions): Move before
>> >       format.
>> >       (constexpr_format): Define.
>> >        * bits/version.h: Regenerate.
>> >        * std/format (_GLIBCXX_CONSTEXPR_FORMAT): Define and apply
>> >       to all of functions except __write_escaped_ascii and
>> >       __formatter_fp members.
>> >       (_GLIBCXX_CONSTEXPR_FORMAT_ERROR): Replace with
>> >       _GLIBCXX_CONSTEXPR_FORMAT.
>> >       (basic_format_string::basic_format_string(const _Tp&)):
>> >       Mark as noexcept.
>> >        (__format::__toupper_numeric): Define.
>> >       (__formatter_int::format): Use __format::__toupper_numeric
>> >       and replace __builtin_memcpy with ranges::copy.
>> >       (__formatter_fp::format): Use __format::__toupper_numeric.
>> >       (__formatter_ptr::format): Avoid reinterpret_cast for
>> >       null-pointer value to support std::nullptr_t formatting.
>> >       (__format::__do_vformat_to): Replace __builtin_memcpy with
>> >       ranges::copy.
>> >       (basic_format_parse_context::__check_dynamic_spec):
>> >       Skip checks if __args pointer is null.
>> >
>> >libstdc++-v3/testsuite/ChangeLog:
>> >
>> >        * std/format/arguments/args_neg.cc: Diagnostics change.
>> >        * std/format/constexpr.cc: New test.
>> >        * std/format/debug.cc: Test at compile-time in C++26 and
>> >       update iteration limit for paddding tests.
>> >        * std/format/tuple.cc: Likewise.
>> >        * std/format/functions/format.cc: Test at compile-time in C++26.
>> >        * std/format/functions/format_to.cc: Likewise.
>> >        * std/format/functions/size.cc: Likewise.
>> >        * std/format/ranges/format_kind.cc: Likewise.
>> >        * std/format/ranges/formatter.cc: Likewise.
>> >        * std/format/ranges/sequence.cc: Likewise.
>> >        * std/format/runtime_format.cc: Likewise.
>> >        * std/format/string.cc: Likewise.
>> >        * std/time/format/data_not_present_neg.cc: Diagnostics change.
>> >
>> >Co-authored-by: Tomasz Kamiński <[email protected]>
>> >Signed-off-by: Ivan Lazaric <[email protected]>
>> >---
>> >v2 changes:
>> > - updates changelog
>> > - remove constexpr support for __write_escaped_ascii, they
>> >   will be follow up patch enabling it for common case
>> > - removes workaroung for _Ptr_sink in vformat_to_n,
>> >   after Jakub's make it constexpr in PR124347, clang
>> >   support it in C++|23 or later.
>> > - constexpr_format now depend on constexpr_exceptions,
>> >   (they were moved beforein file), and make
>> >   __cpp_lib_contexp_format defined by <format>
>> > - replaced _GLIBCXX_CONSTEXPR_FORMAT_ERROR with
>> >   simply _GLIBCXX_CONSTEXPR_FORMAT
>> > - increase constexpr iterations limit for also for tuple.cc,
>> >   so transcoding finishes
>> > - removed ctype include was we use to_upper_numeric.
>> >
>> >Tested on x86_64-linux. OK for trunk?
>> >
>> > libstdc++-v3/include/bits/version.def         |  32 +-
>> > libstdc++-v3/include/bits/version.h           |  30 +-
>> > libstdc++-v3/include/std/format               | 394 +++++++++++-------
>> > .../std/format/arguments/args_neg.cc          |   4 +-
>> > .../testsuite/std/format/constexpr.cc         | 166 ++++++++
>> > libstdc++-v3/testsuite/std/format/debug.cc    |  83 ++--
>> > .../testsuite/std/format/dynamic_format.cc    |  25 +-
>> > .../testsuite/std/format/functions/format.cc  | 281 +++++++------
>> > .../std/format/functions/format_to.cc         |  58 ++-
>> > .../testsuite/std/format/functions/size.cc    |  23 +-
>> > .../std/format/ranges/format_kind.cc          |  15 +-
>> > .../testsuite/std/format/ranges/formatter.cc  |  37 +-
>> > .../testsuite/std/format/ranges/sequence.cc   |  64 ++-
>> > libstdc++-v3/testsuite/std/format/string.cc   |  59 ++-
>> > libstdc++-v3/testsuite/std/format/tuple.cc    |  72 +++-
>> > .../std/time/format/data_not_present_neg.cc   |   3 +-
>> > 16 files changed, 932 insertions(+), 414 deletions(-)
>> > create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc
>> >
>> >diff --git a/libstdc++-v3/include/bits/version.def 
>> >b/libstdc++-v3/include/bits/version.def
>> >index 6d789987642..a6adaef42a0 100644
>> >--- a/libstdc++-v3/include/bits/version.def
>> >+++ b/libstdc++-v3/include/bits/version.def
>> >@@ -1328,6 +1328,16 @@ ftms = {
>> >   };
>> > };
>> >
>> >+ftms = {
>> >+  name = constexpr_exceptions;
>> >+  values = {
>> >+    v = 202502;
>> >+    cxxmin = 26;
>> >+    extra_cond = "__cpp_constexpr_exceptions >= 202411L";
>> >+    cxx11abi = yes;
>> >+  };
>> >+};
>> >+
>> > ftms = {
>> >   name = format;
>> >   // 202305 P2757R3 Type checking format args
>> >@@ -1351,6 +1361,18 @@ ftms = {
>> >   };
>> > };
>> >
>> >+ftms = {
>> >+  name = constexpr_format;
>> >+  // 202511 P3391R2 constexpr std::format
>> >+  values = {
>> >+    v = 202511;
>> >+    cxxmin = 26;
>> >+    hosted = yes;
>> >+    extra_cond = "__cpp_lib_constexpr_exceptions >= 202502L";
>> >+    cxx11abi = yes;
>> >+  };
>> >+};
>> >+
>> > ftms = {
>> >   name = format_uchar;
>> >   values = {
>> >@@ -2325,16 +2347,6 @@ ftms = {
>> >   };
>> > };
>> >
>> >-ftms = {
>> >-  name = constexpr_exceptions;
>> >-  values = {
>> >-    v = 202502;
>> >-    cxxmin = 26;
>> >-    extra_cond = "__cpp_constexpr_exceptions >= 202411L";
>> >-    cxx11abi = yes;
>> >-  };
>> >-};
>> >-
>> > ftms = {
>> >   name = philox_engine;
>> >   values = {
>> >diff --git a/libstdc++-v3/include/bits/version.h 
>> >b/libstdc++-v3/include/bits/version.h
>> >index c44fe07ec60..7c24bcc5f44 100644
>> >--- a/libstdc++-v3/include/bits/version.h
>> >+++ b/libstdc++-v3/include/bits/version.h
>> >@@ -1476,6 +1476,16 @@
>> > #endif /* !defined(__cpp_lib_barrier) */
>> > #undef __glibcxx_want_barrier
>> >
>> >+#if !defined(__cpp_lib_constexpr_exceptions)
>> >+# if (__cplusplus >  202302L) && _GLIBCXX_USE_CXX11_ABI && 
>> >(__cpp_constexpr_exceptions >= 202411L)
>> >+#  define __glibcxx_constexpr_exceptions 202502L
>> >+#  if defined(__glibcxx_want_all) || 
>> >defined(__glibcxx_want_constexpr_exceptions)
>> >+#   define __cpp_lib_constexpr_exceptions 202502L
>> >+#  endif
>> >+# endif
>> >+#endif /* !defined(__cpp_lib_constexpr_exceptions) */
>> >+#undef __glibcxx_want_constexpr_exceptions
>> >+
>> > #if !defined(__cpp_lib_format)
>> > # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
>> > #  define __glibcxx_format 202603L
>> >@@ -1491,6 +1501,16 @@
>> > #endif /* !defined(__cpp_lib_format) */
>> > #undef __glibcxx_want_format
>> >
>> >+#if !defined(__cpp_lib_constexpr_format)
>> >+# if (__cplusplus >  202302L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED 
>> >&& (__cpp_lib_constexpr_exceptions >= 202502L)
>> >+#  define __glibcxx_constexpr_format 202511L
>> >+#  if defined(__glibcxx_want_all) || 
>> >defined(__glibcxx_want_constexpr_format)
>> >+#   define __cpp_lib_constexpr_format 202511L
>> >+#  endif
>> >+# endif
>> >+#endif /* !defined(__cpp_lib_constexpr_format) */
>> >+#undef __glibcxx_want_constexpr_format
>> >+
>> > #if !defined(__cpp_lib_format_uchar)
>> > # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
>> > #  define __glibcxx_format_uchar 202311L
>> >@@ -2586,16 +2606,6 @@
>> > #endif /* !defined(__cpp_lib_bitset) */
>> > #undef __glibcxx_want_bitset
>> >
>> >-#if !defined(__cpp_lib_constexpr_exceptions)
>> >-# if (__cplusplus >  202302L) && _GLIBCXX_USE_CXX11_ABI && 
>> >(__cpp_constexpr_exceptions >= 202411L)
>> >-#  define __glibcxx_constexpr_exceptions 202502L
>> >-#  if defined(__glibcxx_want_all) || 
>> >defined(__glibcxx_want_constexpr_exceptions)
>> >-#   define __cpp_lib_constexpr_exceptions 202502L
>> >-#  endif
>> >-# endif
>> >-#endif /* !defined(__cpp_lib_constexpr_exceptions) */
>> >-#undef __glibcxx_want_constexpr_exceptions
>> >-
>> > #if !defined(__cpp_lib_philox_engine)
>> > # if (__cplusplus >  202302L)
>> > #  define __glibcxx_philox_engine 202406L
>> >diff --git a/libstdc++-v3/include/std/format 
>> >b/libstdc++-v3/include/std/format
>> >index 0f20fcc8d88..fe0f611b833 100644
>> >--- a/libstdc++-v3/include/std/format
>> >+++ b/libstdc++-v3/include/std/format
>> >@@ -39,6 +39,7 @@
>> > #define __glibcxx_want_format_ranges
>> > #define __glibcxx_want_format_uchar
>> > #define __glibcxx_want_constexpr_exceptions
>> >+#define __glibcxx_want_constexpr_format
>> > #include <bits/version.h>
>> >
>> > #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
>> >@@ -63,8 +64,10 @@
>> > #include <bits/utility.h>      // tuple_size_v
>> > #include <ext/numeric_traits.h> // __int_traits
>> >
>> >-#if !__has_builtin(__builtin_toupper)
>> >-# include <cctype>
>> >+#ifdef __glibcxx_constexpr_format // C++ >= 26 && HOSTED && CXX11 strings
>> >+# define _GLIBCXX_CONSTEXPR_FORMAT constexpr
>> >+#else
>> >+# define _GLIBCXX_CONSTEXPR_FORMAT
>> > #endif
>> >
>> > #pragma GCC diagnostic push
>> >@@ -128,6 +131,7 @@ namespace __format
>> >     struct _Dynamic_format_string
>> >     {
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Dynamic_format_string(basic_string_view<_CharT> __s) noexcept
>> >       : _M_str(__s) { }
>> >
>> >@@ -170,9 +174,10 @@ namespace __format
>> >       template<typename _Tp>
>> >       requires convertible_to<const _Tp&, basic_string_view<_CharT>>
>> >       consteval
>> >-      basic_format_string(const _Tp& __s);
>> >+      basic_format_string(const _Tp& __s) noexcept;
>> >
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       basic_format_string(__format::_Dynamic_format_string<_CharT> __s) 
>> > noexcept
>> >       : _M_str(__s._M_str)
>> >       { }
>> >@@ -197,13 +202,13 @@ namespace __format
>> >
>> > #if __cpp_lib_format >= 202603L // >= C++26
>> >   [[__gnu__::__always_inline__]]
>> >-  inline __format::_Dynamic_format_string<char>
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT __format::_Dynamic_format_string<char>
>> >   dynamic_format(string_view __fmt) noexcept
>> >   { return __fmt; }
>> >
>> > #ifdef _GLIBCXX_USE_WCHAR_T
>> >   [[__gnu__::__always_inline__]]
>> >-  inline __format::_Dynamic_format_string<wchar_t>
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT 
>> >__format::_Dynamic_format_string<wchar_t>
>> >   dynamic_format(wstring_view __fmt) noexcept
>> >   { return __fmt; }
>> > #endif
>> >@@ -220,56 +225,51 @@ namespace __format
>> >       formatter& operator=(const formatter&) = delete;
>> >     };
>> >
>> >-#if __cpp_lib_constexpr_exceptions >= 202502L
>> >-#define _GLIBCXX_CONSTEXPR_FORMAT_ERROR constexpr
>> >-#else
>> >-#define _GLIBCXX_CONSTEXPR_FORMAT_ERROR
>> >-#endif
>> >-
>> >   // [format.error], class format_error
>> >   class format_error : public runtime_error
>> >   {
>> >   public:
>> >-    _GLIBCXX_CONSTEXPR_FORMAT_ERROR explicit format_error(const string& 
>> >__what)
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >+    explicit format_error(const string& __what)
>> >     : runtime_error(__what) { }
>> >-    _GLIBCXX_CONSTEXPR_FORMAT_ERROR explicit format_error(const char* 
>> >__what)
>> >+
>> >+    _GLIBCXX_CONSTEXPR_FORMAT explicit
>> >+    format_error(const char* __what)
>> >     : runtime_error(__what) { }
>> >   };
>> >
>> >   /// @cond undocumented
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __throw_format_error(const char* __what)
>> >   { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
>> >
>> >-#undef _GLIBCXX_CONSTEXPR_FORMAT_ERROR
>> >-
>> > namespace __format
>> > {
>> >   // XXX use named functions for each constexpr error?
>> >
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __unmatched_left_brace_in_format_string()
>> >   { __throw_format_error("format error: unmatched '{' in format string"); }
>> >
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __unmatched_right_brace_in_format_string()
>> >   { __throw_format_error("format error: unmatched '}' in format string"); }
>> >
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __conflicting_indexing_in_format_string()
>> >   { __throw_format_error("format error: conflicting indexing style in 
>> > format string"); }
>> >
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __invalid_arg_id_in_format_string()
>> >   { __throw_format_error("format error: invalid arg-id in format string"); 
>> > }
>> >
>> >   [[noreturn]]
>> >-  inline void
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT void
>> >   __failed_to_parse_format_spec()
>> >   { __throw_format_error("format error: failed to parse format-spec"); }
>> >
>> >@@ -517,7 +517,7 @@ namespace __format
>> >   using enum _WidthPrec;
>> >
>> >   template<typename _Context>
>> >-    size_t
>> >+    _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >     __int_from_arg(const basic_format_arg<_Context>& __arg);
>> >
>> >   constexpr bool __is_digit(char __c)
>> >@@ -750,7 +750,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Context>
>> >-      size_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       _M_get_width(_Context& __ctx) const
>> >       {
>> >         size_t __width = 0;
>> >@@ -762,7 +762,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Context>
>> >-      size_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       _M_get_precision(_Context& __ctx) const
>> >       {
>> >         size_t __prec = -1;
>> >@@ -775,7 +775,7 @@ namespace __format
>> >     };
>> >
>> >   template<typename _Int>
>> >-    inline char*
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT char*
>> >     __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
>> >     {
>> >       if (__i < 0)
>> >@@ -792,7 +792,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 _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write(_Out __out, basic_string_view<_CharT> __str)
>> >     {
>> >       if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>> >@@ -809,7 +809,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
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_padded(_Out __out, basic_string_view<_CharT> __str,
>> >                  _Align __align, size_t __nfill, char32_t __fill_char)
>> >     {
>> >@@ -883,7 +883,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
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _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 +905,7 @@ namespace __format
>> >     }
>> >
>> >    template<typename _CharT>
>> >-     size_t
>> >+     _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >      __truncate(basic_string_view<_CharT>& __s, size_t __prec)
>> >      {
>> >        if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
>> >@@ -1049,7 +1049,7 @@ namespace __format
>> >
>> >   using uint_least32_t = __UINT_LEAST32_TYPE__;
>> >   template<typename _Out, typename _CharT>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escape_seq(_Out __out, uint_least32_t __val,
>> >                      basic_string_view<_CharT> __prefix)
>> >     {
>> >@@ -1079,7 +1079,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _Out, typename _CharT>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
>> >     {
>> >       using _UChar = make_unsigned_t<_CharT>;
>> >@@ -1090,7 +1090,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _Out, typename _CharT>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escaped_char(_Out __out, _CharT __c)
>> >     {
>> >       using _UChar = make_unsigned_t<_CharT>;
>> >@@ -1146,7 +1146,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _CharT, typename _Out>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escaped_unicode_part(_Out __out, basic_string_view<_CharT>& 
>> > __str,
>> >                                bool& __prev_esc, _Term_char __term)
>> >     {
>> >@@ -1224,7 +1224,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _CharT, typename _Out>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str,
>> >                           _Term_char __term)
>> >     {
>> >@@ -1236,7 +1236,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _CharT, typename _Out>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __write_escaped(_Out __out,  basic_string_view<_CharT> __str, 
>> > _Term_char __term)
>> >     {
>> >       __out = __format::__write(__out, _Escapes<_CharT>::_S_term(__term));
>> >@@ -1257,12 +1257,14 @@ namespace __format
>> >   struct _Optional_locale
>> >   {
>> >     [[__gnu__::__always_inline__]]
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >     _Optional_locale() : _M_dummy(), _M_hasval(false) { }
>> >
>> >     _Optional_locale(const locale& __loc) noexcept
>> >     : _M_loc(__loc), _M_hasval(true)
>> >     { }
>> >
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >     _Optional_locale(const _Optional_locale& __l) noexcept
>> >     : _M_dummy(), _M_hasval(__l._M_hasval)
>> >     {
>> >@@ -1270,6 +1272,7 @@ namespace __format
>> >       std::construct_at(&_M_loc, __l._M_loc);
>> >     }
>> >
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >     _Optional_locale&
>> >     operator=(const _Optional_locale& __l) noexcept
>> >     {
>> >@@ -1291,6 +1294,7 @@ namespace __format
>> >       return *this;
>> >     }
>> >
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >     ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
>> >
>> >     _Optional_locale&
>> >@@ -1317,7 +1321,8 @@ namespace __format
>> >       return _M_loc;
>> >     }
>> >
>> >-    bool has_value() const noexcept { return _M_hasval; }
>> >+    _GLIBCXX_CONSTEXPR_FORMAT bool
>> >+    has_value() const noexcept { return _M_hasval; }
>> >
>> >     union {
>> >       char _M_dummy = '\0';
>> >@@ -1391,7 +1396,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >-      _Out
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >       format(basic_string_view<_CharT> __s,
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -1408,7 +1413,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >-      _Out
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >       _M_format_escaped(basic_string_view<_CharT> __s,
>> >                         basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -1433,7 +1438,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
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >       _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& 
>> > __fc) const
>> >       {
>> >         using _Range = remove_reference_t<_Rg>;
>> >@@ -1482,6 +1487,28 @@ namespace __format
>> >       _Spec<_CharT> _M_spec{};
>> >     };
>> >
>> >+  // A partial implementation of std::toupper that is constexpr-enabled,
>> >+  // sufficient for formatting purposes.
>> >+  [[__gnu__::__always_inline__]]
>> >+  constexpr char
>> >+  __toupper_numeric(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';
>> >+      case 'x': return 'X';
>> >+      default: return __c;
>> >+    }
>> >+  }
>> >+
>> >   template<__char _CharT>
>> >     struct __formatter_int
>> >     {
>> >@@ -1641,6 +1668,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Int, typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -1690,11 +1718,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_numeric(*__p);
>> >             break;
>> >           default:
>> >             __builtin_unreachable();
>> >@@ -1703,8 +1727,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);
>>
>> I'm concerned about the impact on compilation speed of this change.
>
> We are only calling ranges::copy with string_view and char* and
> ranges::copy_n with char* (we could change it to string_view).
> So this should only have one instantiation of the algorithm for all
> possible formatters (if we do ranges::copy_n change).

Ah, and we get it from bits/ranges_algobase.h which is already
included. So we're not parsing all of <ranges> just for
ranges::copy_n.

OK, I'm less concerned now.

>>
>>
>> OK for trunk, but we might need to revisit this part.
>>
>> >           }
>> >         __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1);
>> >
>> >@@ -1728,6 +1751,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -1758,6 +1782,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       _M_format_character(_CharT __c,
>> >                           basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -1789,7 +1814,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Int>
>> >-      static _CharT
>> >+      static _GLIBCXX_CONSTEXPR_FORMAT _CharT
>> >       _S_to_character(_Int __i)
>> >       {
>> >         using _Traits = __gnu_cxx::__int_traits<_CharT>;
>> >@@ -1810,6 +1835,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       _M_format_int(basic_string_view<_CharT> __str, size_t __prefix_len,
>> >                     basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -2199,7 +2225,7 @@ namespace __format
>> >         if (__upper)
>> >           {
>> >             for (char* __p = __start; __p != __res.ptr; ++__p)
>> >-              *__p = std::toupper(*__p);
>> >+              *__p = __format::__toupper_numeric(*__p);
>> >           }
>> >
>> >         bool __have_sign = true;
>> >@@ -2512,10 +2538,13 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       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);
>> >+        auto __u = __v
>> >+          ? reinterpret_cast<__UINTPTR_TYPE__>(__v)
>> >+          : static_cast<__UINTPTR_TYPE__>(0);
>> >         return __formatter_int<_CharT>(_M_spec).format(__u, __fc);
>> >       }
>> >
>> >@@ -2550,6 +2579,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -2588,6 +2618,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, wchar_t>::iterator
>> >       format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
>> >       {
>> >@@ -2623,6 +2654,7 @@ namespace __format
>> >
>> >       template<typename _Out>
>> >       [[__gnu__::__nonnull__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
>> >       { return _M_f.format(__u, __fc); }
>> >@@ -2652,6 +2684,7 @@ namespace __format
>> >
>> >       template<typename _Out>
>> >       [[__gnu__::__nonnull__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(const _CharT* __u,
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -2682,6 +2715,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(const _CharT (&__u)[_Nm],
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -2711,6 +2745,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, char>::iterator
>> >       format(const basic_string<char, _Traits, _Alloc>& __u,
>> >              basic_format_context<_Out, char>& __fc) const
>> >@@ -2743,6 +2778,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       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
>> >@@ -2776,6 +2812,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, char>::iterator
>> >       format(basic_string_view<char, _Traits> __u,
>> >              basic_format_context<_Out, char>& __fc) const
>> >@@ -2808,6 +2845,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, wchar_t>::iterator
>> >       format(basic_string_view<wchar_t, _Traits> __u,
>> >              basic_format_context<_Out, wchar_t>& __fc) const
>> >@@ -2871,6 +2909,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
>> >       { return _M_f.format(__u, __fc); }
>> >@@ -3082,6 +3121,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(const void* __v, basic_format_context<_Out, _CharT>& __fc) 
>> > const
>> >       { return _M_f.format(__v, __fc); }
>> >@@ -3107,6 +3147,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
>> >       { return _M_f.format(__v, __fc); }
>> >@@ -3132,6 +3173,7 @@ namespace __format
>> >       { return _M_f.parse(__pc); }
>> >
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
>> >       { return _M_f.format(nullptr, __fc); }
>> >@@ -3276,11 +3318,11 @@ namespace __format
>> >       constexpr _Sink_iter
>> >       operator++(int) { return *this; }
>> >
>> >-      auto
>> >+      _GLIBCXX_CONSTEXPR_FORMAT auto
>> >       _M_reserve(size_t __n) const
>> >       { return _M_sink->_M_reserve(__n); }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_discarding() const
>> >       { return _M_sink->_M_discarding(); }
>> >     };
>> >@@ -3312,7 +3354,7 @@ namespace __format
>> >
>> >       // The portion of the span that has been written to.
>> >       [[__gnu__::__always_inline__]]
>> >-      span<_CharT>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT span<_CharT>
>> >       _M_used() const noexcept
>> >       { return _M_span.first(_M_next - _M_span.begin()); }
>> >
>> >@@ -3329,7 +3371,7 @@ namespace __format
>> >       { _M_next = _M_span.begin(); }
>> >
>> >       // Replace the current output range.
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
>> >       {
>> >       _M_span = __s;
>> >@@ -3369,11 +3411,14 @@ namespace __format
>> >       struct _Reservation
>> >       {
>> >       // True if the reservation was successful, false otherwise.
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       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->(); 
>> >}
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _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); }
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >+      _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
>> >       _Sink* _M_sink;
>> >       };
>> >
>> >@@ -3381,7 +3426,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
>> >+      _GLIBCXX_CONSTEXPR_FORMAT virtual _Reservation
>> >       _M_reserve(size_t __n)
>> >       {
>> >       if (__n <= _M_unused().size())
>> >@@ -3398,12 +3443,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
>> >+      _GLIBCXX_CONSTEXPR_FORMAT virtual void
>> >       _M_bump(size_t __n)
>> >       { _M_next += __n; }
>> >
>> >       // Returns true if the _Sink is discarding incoming characters.
>> >-      virtual bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT virtual bool
>> >       _M_discarding() const
>> >       { return false; }
>> >
>> >@@ -3421,7 +3466,7 @@ namespace __format
>> >   template<typename _CharT>
>> >     class _Fixedbuf_sink final : public _Sink<_CharT>
>> >     {
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       __glibcxx_assert(false);
>> >@@ -3469,7 +3514,7 @@ namespace __format
>> >       _Seq _M_seq;
>> >     protected:
>> >       // Transfer buffer contents to the sequence, so buffer can be 
>> > refilled.
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       auto __s = this->_M_used();
>> >@@ -3488,7 +3533,7 @@ namespace __format
>> >       this->_M_rewind();
>> >       }
>> >
>> >-      typename _Sink<_CharT>::_Reservation
>> >+      _GLIBCXX_CONSTEXPR_FORMAT typename _Sink<_CharT>::_Reservation
>> >       _M_reserve(size_t __n) override
>> >       {
>> >       // We might already have n characters available in this->_M_unused(),
>> >@@ -3524,7 +3569,7 @@ namespace __format
>> >         return _Sink<_CharT>::_M_reserve(__n);
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_bump(size_t __n) override
>> >       {
>> >       if constexpr (__is_specialization_of<_Seq, basic_string>
>> >@@ -3539,7 +3584,8 @@ namespace __format
>> >         }
>> >       }
>> >
>> >-      void _M_trim(span<const _CharT> __s)
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >+      _M_trim(span<const _CharT> __s)
>> >       requires __is_specialization_of<_Seq, basic_string>
>> >       {
>> >       _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf
>> >@@ -3555,16 +3601,18 @@ namespace __format
>> >       // to _M_buf if it overflows? Or even do that for all unused 
>> > capacity?
>> >
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
>> >       { }
>> >
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Seq_sink(_Seq&& __s) noexcept(is_nothrow_move_constructible_v<_Seq>)
>> >       : _M_seq(std::move(__s))
>> >       { }
>> >
>> >       using _Sink<_CharT>::out;
>> >
>> >-      _Seq
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Seq
>> >       get() &&
>> >       {
>> >       if (this->_M_used().size() != 0)
>> >@@ -3574,7 +3622,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>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT span<_CharT>
>> >       _M_span()
>> >       {
>> >       auto __s = this->_M_used();
>> >@@ -3587,7 +3635,7 @@ namespace __format
>> >       return __s;
>> >       }
>> >
>> >-      basic_string_view<_CharT>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT basic_string_view<_CharT>
>> >       view()
>> >       {
>> >       auto __span = _M_span();
>> >@@ -3612,7 +3660,7 @@ namespace __format
>> >     protected:
>> >       size_t _M_count = 0;
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       auto __s = this->_M_used();
>> >@@ -3632,7 +3680,7 @@ namespace __format
>> >       _M_count += __s.size();
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_discarding() const override
>> >       {
>> >       // format_to_n return total number of characters, that would be 
>> > written,
>> >@@ -3642,14 +3690,14 @@ namespace __format
>> >
>> >     public:
>> >       [[__gnu__::__always_inline__]]
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT 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>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT format_to_n_result<_OutIter>
>> >       _M_finish() &&
>> >       {
>> >       if (this->_M_used().size() != 0)
>> >@@ -3678,7 +3726,7 @@ namespace __format
>> >       _CharT _M_buf[64]; // Write here after outputting _M_max characters.
>> >
>> >     protected:
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       if (this->_M_unused().size() != 0)
>> >@@ -3702,7 +3750,7 @@ namespace __format
>> >         }
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_discarding() const override
>> >       {
>> >       // format_to_n return total number of characters, that would be 
>> > written,
>> >@@ -3710,7 +3758,7 @@ namespace __format
>> >       return false;
>> >       }
>> >
>> >-      typename _Sink<_CharT>::_Reservation
>> >+      _GLIBCXX_CONSTEXPR_FORMAT typename _Sink<_CharT>::_Reservation
>> >       _M_reserve(size_t __n) final
>> >       {
>> >       auto __avail = this->_M_unused();
>> >@@ -3727,7 +3775,7 @@ namespace __format
>> >
>> >     private:
>> >       template<typename _IterDifference>
>> >-      static size_t
>> >+      static _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       _S_trim_max(_IterDifference __max)
>> >       {
>> >         if (__max < 0)
>> >@@ -3740,7 +3788,7 @@ namespace __format
>> >       }
>> >
>> >       [[__gnu__::__always_inline__]]
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_rebuf(_CharT* __ptr, size_t __total, size_t __inuse = 0)
>> >       {
>> >       std::span<_CharT> __span(__ptr, __total);
>> >@@ -3748,7 +3796,7 @@ namespace __format
>> >       }
>> >
>> >     public:
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT explicit
>> >       _Ptr_sink(_CharT* __ptr, size_t __n = _S_no_limit) noexcept
>> >       : _Sink<_CharT>(_M_buf), _M_max(__n)
>> >       {
>> >@@ -3773,13 +3821,13 @@ namespace __format
>> >       }
>> >
>> >       template<contiguous_iterator _OutIter>
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT 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>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT format_to_n_result<_OutIter>
>> >       _M_finish(_OutIter __first) const
>> >       {
>> >         auto __s = this->_M_used();
>> >@@ -3821,12 +3869,12 @@ namespace __format
>> >       size_t _M_printwidth;
>> >
>> >       [[__gnu__::__always_inline__]]
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_ignoring() const
>> >       { return _M_printwidth >= _M_maxwidth; }
>> >
>> >       [[__gnu__::__always_inline__]]
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_buffering() const
>> >       {
>> >       if (_M_printwidth < _M_padwidth)
>> >@@ -3836,7 +3884,7 @@ namespace __format
>> >       return false;
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_sync_discarding()
>> >       {
>> >       if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>> >@@ -3844,7 +3892,7 @@ namespace __format
>> >           _M_maxwidth = _M_printwidth;
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_flush()
>> >       {
>> >       span<_CharT> __new = this->_M_used();
>> >@@ -3854,7 +3902,7 @@ namespace __format
>> >       this->_M_rewind();
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_force_update()
>> >       {
>> >       auto __str = this->view();
>> >@@ -3882,7 +3930,7 @@ namespace __format
>> >       return false;
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_update(size_t __new)
>> >       {
>> >       _M_printwidth += __new;
>> >@@ -3892,7 +3940,7 @@ namespace __format
>> >       return true;
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       // Ignore characters in buffer, and override it.
>> >@@ -3907,11 +3955,11 @@ namespace __format
>> >         _Str_sink<_CharT>::_M_overflow();
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_discarding() const override
>> >       { return _M_ignoring(); }
>> >
>> >-      typename _Sink<_CharT>::_Reservation
>> >+      _GLIBCXX_CONSTEXPR_FORMAT typename _Sink<_CharT>::_Reservation
>> >       _M_reserve(size_t __n) override
>> >       {
>> >       // Ignore characters in buffer, if any.
>> >@@ -3930,7 +3978,7 @@ namespace __format
>> >       return _Sink<_CharT>::_M_reserve(__n);
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_bump(size_t __n) override
>> >       {
>> >       // Ignore the written characters.
>> >@@ -3945,19 +3993,19 @@ namespace __format
>> >
>> >     public:
>> >       [[__gnu__::__always_inline__]]
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT 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
>> >+      _GLIBCXX_CONSTEXPR_FORMAT explicit
>> >       _Padding_sink(_Out __out, size_t __padwidth)
>> >       : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
>> >       { }
>> >
>> >-      _Out
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >       _M_finish(_Align __align, char32_t __fill_char)
>> >       {
>> >       // Handle any characters in the buffer.
>> >@@ -3996,14 +4044,14 @@ namespace __format
>> >       unsigned _M_prev_escape : 1;
>> >       unsigned _M_out_discards : 1;
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_sync_discarding()
>> >       {
>> >       if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
>> >         _M_out_discards = _M_out._M_discarding();
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_write()
>> >       {
>> >       span<_CharT> __bytes = this->_M_used();
>> >@@ -4029,7 +4077,7 @@ namespace __format
>> >       _M_sync_discarding();
>> >       }
>> >
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_overflow() override
>> >       {
>> >       if (_M_out_discards)
>> >@@ -4038,13 +4086,13 @@ namespace __format
>> >         _M_write();
>> >       }
>> >
>> >-      bool
>> >+      _GLIBCXX_CONSTEXPR_FORMAT bool
>> >       _M_discarding() const override
>> >       { return _M_out_discards; }
>> >
>> >     public:
>> >       [[__gnu__::__always_inline__]]
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT explicit
>> >       _Escaping_sink(_Out __out, _Term_char __term)
>> >       : _M_out(std::move(__out)), _M_term(__term),
>> >       _M_prev_escape(true), _M_out_discards(false)
>> >@@ -4053,7 +4101,7 @@ namespace __format
>> >       _M_sync_discarding();
>> >       }
>> >
>> >-      _Out
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >       _M_finish()
>> >       {
>> >       if (_M_out_discards)
>> >@@ -4105,7 +4153,7 @@ namespace __format
>> >                             const _Tp, _Tp>;
>> >
>> >       template<typename _Tq>
>> >-        static void
>> >+        static _GLIBCXX_CONSTEXPR_FORMAT void
>> >         _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
>> >                   _Context& __format_ctx, const void* __ptr)
>> >         {
>> >@@ -4118,7 +4166,7 @@ namespace __format
>> >
>> >       template<typename _Tp>
>> >         requires (!is_same_v<remove_cv_t<_Tp>, handle>)
>> >-        explicit
>> >+        explicit _GLIBCXX_CONSTEXPR_FORMAT
>> >         handle(_Tp& __val) noexcept
>> >         : _M_ptr(__builtin_addressof(__val))
>> >         , _M_func(&_S_format<__maybe_const_t<_Tp>>)
>> >@@ -4131,7 +4179,7 @@ namespace __format
>> >       handle& operator=(const handle&) = default;
>> >
>> >       [[__gnu__::__always_inline__]]
>> >-      void
>> >+      void _GLIBCXX_CONSTEXPR_FORMAT
>> >       format(basic_format_parse_context<_CharT>& __pc, _Context& __fc) 
>> > const
>> >       { _M_func(__pc, __fc, this->_M_ptr); }
>> >
>> >@@ -4183,10 +4231,12 @@ namespace __format
>> >       };
>> >
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Arg_value() : _M_none() { }
>> >
>> > #if 0
>> >       template<typename _Tp>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Arg_value(in_place_type_t<_Tp>, _Tp __val)
>> >       { _S_get<_Tp>() = __val; }
>> > #endif
>> >@@ -4195,7 +4245,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 _GLIBCXX_CONSTEXPR_FORMAT auto&
>> >       _S_access(_Self& __u, _Value... __value) noexcept
>> >       {
>> >         static_assert(sizeof...(_Value) <= 1);
>> >@@ -4259,23 +4309,24 @@ namespace __format
>> >         else if constexpr (is_same_v<_Tp, handle>)
>> >           return __u._M_handle;
>> >         // Otherwise, ill-formed.
>> >+        __builtin_unreachable();
>> >       }
>> >
>> >       template<typename _Tp>
>> >       [[__gnu__::__always_inline__]]
>> >-      auto&
>> >+      _GLIBCXX_CONSTEXPR_FORMAT auto&
>> >       _M_get() noexcept
>> >       { return _S_access<_Tp>(*this); }
>> >
>> >       template<typename _Tp>
>> >       [[__gnu__::__always_inline__]]
>> >-      const auto&
>> >+      _GLIBCXX_CONSTEXPR_FORMAT const auto&
>> >       _M_get() const noexcept
>> >       { return _S_access<_Tp>(*this); }
>> >
>> >       template<typename _Tp>
>> >       [[__gnu__::__always_inline__]]
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_set(_Tp __v) noexcept
>> >       {
>> >         // Explicitly construct types without trivial default constructor.
>> >@@ -4295,7 +4346,8 @@ namespace __format
>> >     class _Arg_store;
>> >
>> >   template<typename _Visitor, typename _Ctx>
>> >-    decltype(auto) __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>> >+    _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >+    __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>> >
>> >   template<typename _Ch, typename _Tp>
>> >     consteval _Arg_t
>> >@@ -4312,20 +4364,21 @@ namespace __format
>> >       using handle = __format::_Arg_value<_Context>::handle;
>> >
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
>> >
>> >       [[nodiscard,__gnu__::__always_inline__]]
>> >-      explicit operator bool() const noexcept
>> >+      explicit _GLIBCXX_CONSTEXPR_FORMAT operator bool() const noexcept
>> >       { return _M_type != __format::_Arg_none; }
>> >
>> > #if __cpp_lib_format >= 202306L // >= C++26
>> >       template<typename _Visitor>
>> >-      decltype(auto)
>> >+      _GLIBCXX_CONSTEXPR_FORMAT 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
>> >+      _GLIBCXX_CONSTEXPR_FORMAT _Res
>> >       visit(this basic_format_arg __arg, _Visitor&& __vis)
>> >       { return __arg._M_visit_user(std::forward<_Visitor>(__vis), 
>> > __arg._M_type); }
>> > #endif
>> >@@ -4502,7 +4555,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Tp>
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_set(_Tp __v) noexcept
>> >       {
>> >         _M_type = _S_to_enum<_Tp>();
>> >@@ -4511,7 +4564,7 @@ namespace __format
>> >
>> >       template<typename _Tp>
>> >       requires __format::__formattable_with<_Tp, _Context>
>> >-      explicit
>> >+      _GLIBCXX_CONSTEXPR_FORMAT explicit
>> >       basic_format_arg(_Tp& __v) noexcept
>> >       {
>> >         using _Td = _Normalize<_Tp>;
>> >@@ -4525,15 +4578,15 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Ctx, typename... _Argz>
>> >-      friend auto
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT auto
>> >       make_format_args(_Argz&...) noexcept;
>> >
>> >       template<typename _Visitor, typename _Ctx>
>> >-      friend decltype(auto)
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >       visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
>> >
>> >       template<typename _Visitor, typename _Ctx>
>> >-      friend decltype(auto)
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >       __format::__visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>> >
>> >       template<typename _Ch, typename _Tp>
>> >@@ -4541,7 +4594,7 @@ namespace __format
>> >       __format::__to_arg_t_enum() noexcept;
>> >
>> >       template<typename _Visitor>
>> >-      decltype(auto)
>> >+      _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >       _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
>> >       {
>> >         using namespace __format;
>> >@@ -4616,7 +4669,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Visitor>
>> >-      decltype(auto)
>> >+      _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >       _M_visit_user(_Visitor&& __vis, __format::_Arg_t __type)
>> >       {
>> >         return _M_visit([&__vis]<typename _Tp>(_Tp& __val) -> 
>> > decltype(auto)
>> >@@ -4640,7 +4693,7 @@ namespace __format
>> >
>> >   template<typename _Visitor, typename _Context>
>> >     _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
>> >-    inline decltype(auto)
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >     visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
>> >     {
>> >       return __arg._M_visit_user(std::forward<_Visitor>(__vis), 
>> > __arg._M_type);
>> >@@ -4650,7 +4703,7 @@ namespace __format
>> > namespace __format
>> > {
>> >   template<typename _Visitor, typename _Ctx>
>> >-    inline decltype(auto)
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT decltype(auto)
>> >     __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg)
>> >     {
>> >       return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type);
>> >@@ -4659,7 +4712,7 @@ namespace __format
>> >   struct _WidthPrecVisitor
>> >   {
>> >     template<typename _Tp>
>> >-      size_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       operator()(_Tp& __arg) const
>> >       {
>> >       if constexpr (is_same_v<_Tp, monostate>)
>> >@@ -4685,7 +4738,7 @@ namespace __format
>> > #pragma GCC diagnostic push
>> > #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
>> >   template<typename _Context>
>> >-    inline size_t
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >     __int_from_arg(const basic_format_arg<_Context>& __arg)
>> >     { return __format::__visit_format_arg(_WidthPrecVisitor(), __arg); }
>> >
>> >@@ -4733,11 +4786,11 @@ namespace __format
>> >       const _Format_arg* _M_args;       // Active when _M_packed_size == 0
>> >       };
>> >
>> >-      size_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       _M_size() const noexcept
>> >       { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
>> >
>> >-      typename __format::_Arg_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT typename __format::_Arg_t
>> >       _M_type(size_t __i) const noexcept
>> >       {
>> >       uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
>> >@@ -4745,7 +4798,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Ctx, typename... _Args>
>> >-      friend auto
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT auto
>> >       make_format_args(_Args&...) noexcept;
>> >
>> >       // An array of _Arg_t enums corresponding to _Args...
>> >@@ -4756,10 +4809,11 @@ namespace __format
>> >
>> >     public:
>> >       template<typename... _Args>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       basic_format_args(const _Store<_Args...>& __store) noexcept;
>> >
>> >       [[nodiscard,__gnu__::__always_inline__]]
>> >-      basic_format_arg<_Context>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT basic_format_arg<_Context>
>> >       get(size_t __i) const noexcept
>> >       {
>> >       basic_format_arg<_Context> __arg;
>> >@@ -4781,7 +4835,7 @@ namespace __format
>> >       -> basic_format_args<_Context>;
>> >
>> >   template<typename _Context, typename... _Args>
>> >-    auto
>> >+    _GLIBCXX_CONSTEXPR_FORMAT auto
>> >     make_format_args(_Args&... __fmt_args) noexcept;
>> >
>> >   // An array of type-erased formatting arguments.
>> >@@ -4791,7 +4845,7 @@ namespace __format
>> >       friend std::basic_format_args<_Context>;
>> >
>> >       template<typename _Ctx, typename... _Argz>
>> >-      friend auto std::
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT auto std::
>> > #if _GLIBCXX_INLINE_VERSION
>> >       __8:: // Needed for PR c++/59256
>> > #endif
>> >@@ -4810,7 +4864,7 @@ namespace __format
>> >       _Element_t _M_args[sizeof...(_Args)];
>> >
>> >       template<typename _Tp>
>> >-      static _Element_t
>> >+      static _GLIBCXX_CONSTEXPR_FORMAT _Element_t
>> >       _S_make_elt(_Tp& __v)
>> >       {
>> >         using _Tq = remove_const_t<_Tp>;
>> >@@ -4836,6 +4890,7 @@ namespace __format
>> >       template<typename... _Tp>
>> >       requires (sizeof...(_Tp) == sizeof...(_Args))
>> >       [[__gnu__::__always_inline__]]
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Arg_store(_Tp&... __a) noexcept
>> >       : _M_args{_S_make_elt(__a)...}
>> >       { }
>> >@@ -4847,7 +4902,7 @@ namespace __format
>> >
>> >   template<typename _Context>
>> >     template<typename... _Args>
>> >-      inline
>> >+      inline _GLIBCXX_CONSTEXPR_FORMAT
>> >       basic_format_args<_Context>::
>> >       basic_format_args(const _Store<_Args...>& __store) noexcept
>> >       {
>> >@@ -4881,7 +4936,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 _GLIBCXX_CONSTEXPR_FORMAT auto
>> >     make_format_args(_Args&... __fmt_args) noexcept
>> >     {
>> >       using _Fmt_arg = basic_format_arg<_Context>;
>> >@@ -4894,7 +4949,7 @@ namespace __format
>> >   /// Capture formatting arguments for use by `std::vformat` (for wide 
>> > output).
>> >   template<typename... _Args>
>> >     [[nodiscard,__gnu__::__always_inline__]]
>> >-    inline auto
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT auto
>> >     make_wformat_args(_Args&... __args) noexcept
>> >     { return std::make_format_args<wformat_context>(__args...); }
>> > #endif
>> >@@ -4903,7 +4958,7 @@ namespace __format
>> > namespace __format
>> > {
>> >   template<typename _Out, typename _CharT, typename _Context>
>> >-    _Out
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __do_vformat_to(_Out, basic_string_view<_CharT>,
>> >                   const basic_format_args<_Context>&,
>> >                   const locale* = nullptr);
>> >@@ -4935,11 +4990,13 @@ namespace __format
>> >       _Out _M_out;
>> >       __format::_Optional_locale _M_loc;
>> >
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       basic_format_context(basic_format_args<basic_format_context> __args,
>> >                          _Out __out)
>> >       : _M_args(__args), _M_out(std::move(__out))
>> >       { }
>> >
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       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)
>> >@@ -4952,7 +5009,7 @@ namespace __format
>> >       basic_format_context& operator=(const basic_format_context&) = 
>> > delete;
>> >
>> >       template<typename _Out2, typename _CharT2, typename _Context2>
>> >-      friend _Out2
>> >+      friend _GLIBCXX_CONSTEXPR_FORMAT _Out2
>> >       __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
>> >                                 const basic_format_args<_Context2>&,
>> >                                 const locale*);
>> >@@ -4968,7 +5025,7 @@ namespace __format
>> >       using formatter_type = formatter<_Tp, _CharT>;
>> >
>> >       [[nodiscard]]
>> >-      basic_format_arg<basic_format_context>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT basic_format_arg<basic_format_context>
>> >       arg(size_t __id) const noexcept
>> >       { return _M_args.get(__id); }
>> >
>> >@@ -4976,9 +5033,11 @@ namespace __format
>> >       std::locale locale() { return _M_loc.value(); }
>> >
>> >       [[nodiscard]]
>> >-      iterator out() { return std::move(_M_out); }
>> >+      _GLIBCXX_CONSTEXPR_FORMAT iterator
>> >+      out() { return std::move(_M_out); }
>> >
>> >-      void advance_to(iterator __it) { _M_out = std::move(__it); }
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >+      advance_to(iterator __it) { _M_out = std::move(__it); }
>> >     };
>> >
>> >
>> >@@ -5117,6 +5176,7 @@ namespace __format
>> >     class _Formatting_scanner : public _Scanner<_CharT>
>> >     {
>> >     public:
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
>> >                         basic_string_view<_CharT> __str)
>> >       : _Scanner<_CharT>(__str), _M_fc(__fc)
>> >@@ -5224,7 +5284,7 @@ namespace __format
>> >     };
>> >
>> >   template<typename _CharT, unsigned = 
>> > __unicode::__literal_encoding_is_unicode<_CharT>()>
>> >-    _Sink_iter<_CharT>
>> >+    _GLIBCXX_CONSTEXPR_FORMAT _Sink_iter<_CharT>
>> >     __do_vformat_to(_Sink_iter<_CharT> __out, basic_string_view<_CharT> 
>> > __fmt,
>> >                   __format_context<_CharT>& __ctx)
>> >     {
>> >@@ -5241,7 +5301,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;
>> >                   }
>> >@@ -5279,7 +5339,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;
>> >                   }
>> >@@ -5312,7 +5372,7 @@ namespace __format
>> > #endif
>> >
>> >   template<typename _Out, typename _CharT, typename _Context>
>> >-    inline _Out
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
>> >                   const basic_format_args<_Context>& __args,
>> >                   const locale* __loc)
>> >@@ -5339,7 +5399,7 @@ namespace __format
>> >     }
>> >
>> >   template<typename _Out, typename _CharT>
>> >-    inline format_to_n_result<_Out>
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT 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<
>> >@@ -5379,7 +5439,12 @@ 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, no type check.
>> >+          if (!__args)
>> >+            return;
>> >+
>> >+          auto __arg = __args[__id];
>> >           __format::_Arg_t __types[] = {
>> >             __format::__to_arg_t_enum<_CharT, _Ts>()...
>> >           };
>> >@@ -5397,7 +5462,7 @@ namespace __format
>> >       requires convertible_to<const _Tp&, basic_string_view<_CharT>>
>> >       consteval
>> >       basic_format_string<_CharT, _Args...>::
>> >-      basic_format_string(const _Tp& __s)
>> >+      basic_format_string(const _Tp& __s) noexcept
>> >       : _M_str(__s)
>> >       {
>> >       __format::_Checking_scanner<_CharT, remove_cvref_t<_Args>...>
>> >@@ -5409,14 +5474,14 @@ namespace __format
>> >
>> >   template<typename _Out> requires output_iterator<_Out, const char&>
>> >     [[__gnu__::__always_inline__]]
>> >-    inline _Out
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT _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 _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
>> >     { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
>> > #endif
>> >@@ -5442,7 +5507,7 @@ namespace __format
>> > #endif
>> >
>> >   [[nodiscard]]
>> >-  inline string
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT string
>> >   vformat(string_view __fmt, format_args __args)
>> >   {
>> >     __format::_Str_sink<char> __buf;
>> >@@ -5452,7 +5517,7 @@ namespace __format
>> >
>> > #ifdef _GLIBCXX_USE_WCHAR_T
>> >   [[nodiscard]]
>> >-  inline wstring
>> >+  inline _GLIBCXX_CONSTEXPR_FORMAT wstring
>> >   vformat(wstring_view __fmt, wformat_args __args)
>> >   {
>> >     __format::_Str_sink<wchar_t> __buf;
>> >@@ -5483,14 +5548,14 @@ namespace __format
>> >
>> >   template<typename... _Args>
>> >     [[nodiscard]]
>> >-    inline string
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT 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 _GLIBCXX_CONSTEXPR_FORMAT wstring
>> >     format(wformat_string<_Args...> __fmt, _Args&&... __args)
>> >     { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); 
>> > }
>> > #endif
>> >@@ -5519,7 +5584,7 @@ namespace __format
>> >
>> >   template<typename _Out, typename... _Args>
>> >     requires output_iterator<_Out, const char&>
>> >-    inline _Out
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args)
>> >     {
>> >       return std::vformat_to(std::move(__out), __fmt.get(),
>> >@@ -5529,7 +5594,7 @@ namespace __format
>> > #ifdef _GLIBCXX_USE_WCHAR_T
>> >   template<typename _Out, typename... _Args>
>> >     requires output_iterator<_Out, const wchar_t&>
>> >-    inline _Out
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT _Out
>> >     format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... 
>> > __args)
>> >     {
>> >       return std::vformat_to(std::move(__out), __fmt.get(),
>> >@@ -5561,7 +5626,7 @@ namespace __format
>> >
>> >   template<typename _Out, typename... _Args>
>> >     requires output_iterator<_Out, const char&>
>> >-    inline format_to_n_result<_Out>
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT format_to_n_result<_Out>
>> >     format_to_n(_Out __out, iter_difference_t<_Out> __n,
>> >               format_string<_Args...> __fmt, _Args&&... __args)
>> >     {
>> >@@ -5573,7 +5638,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 _GLIBCXX_CONSTEXPR_FORMAT format_to_n_result<_Out>
>> >     format_to_n(_Out __out, iter_difference_t<_Out> __n,
>> >               wformat_string<_Args...> __fmt, _Args&&... __args)
>> >     {
>> >@@ -5615,10 +5680,11 @@ namespace __format
>> >     class _Counting_sink final : public _Ptr_sink<_CharT>
>> >     {
>> >     public:
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       _Counting_sink() : _Ptr_sink<_CharT>(nullptr, 0) { }
>> >
>> >       [[__gnu__::__always_inline__]]
>> >-      size_t
>> >+      _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >       count() const
>> >       { return this->_M_count + this->_M_used().size(); }
>> >     };
>> >@@ -5653,7 +5719,7 @@ namespace __format
>> >
>> >   template<typename... _Args>
>> >     [[nodiscard]]
>> >-    inline size_t
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >     formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
>> >     {
>> >       __format::_Counting_sink<char> __buf;
>> >@@ -5665,7 +5731,7 @@ namespace __format
>> > #ifdef _GLIBCXX_USE_WCHAR_T
>> >   template<typename... _Args>
>> >     [[nodiscard]]
>> >-    inline size_t
>> >+    inline _GLIBCXX_CONSTEXPR_FORMAT size_t
>> >     formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
>> >     {
>> >       __format::_Counting_sink<wchar_t> __buf;
>> >@@ -5736,6 +5802,7 @@ namespace __format
>> > namespace __format
>> > {
>> >   template<typename _CharT, typename _Out, typename _Callback>
>> >+    _GLIBCXX_CONSTEXPR_FORMAT
>> >     typename basic_format_context<_Out, _CharT>::iterator
>> >     __format_padded(basic_format_context<_Out, _CharT>& __fc,
>> >                   const _Spec<_CharT>& __spec,
>> >@@ -5755,14 +5822,16 @@ namespace __format
>> >
>> >        struct _Restore_out
>> >        {
>> >+         _GLIBCXX_CONSTEXPR_FORMAT
>> >          _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& 
>> > __fc)
>> >          : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
>> >         { }
>> >
>> >-        void
>> >+        _GLIBCXX_CONSTEXPR_FORMAT void
>> >         _M_disarm()
>> >         { _M_ctx = nullptr; }
>> >
>> >+        _GLIBCXX_CONSTEXPR_FORMAT
>> >         ~_Restore_out()
>> >         {
>> >           if (_M_ctx)
>> >@@ -5796,7 +5865,7 @@ namespace __format
>> >       }
>> >
>> >       template<typename _Out>
>> >-      void
>> >+      _GLIBCXX_CONSTEXPR_FORMAT void
>> >       _M_format(__maybe_const<_Tp, _CharT>& __elem,
>> >                 basic_format_context<_Out, _CharT>& __fc,
>> >                 basic_string_view<_CharT> __sep) const
>> >@@ -5894,12 +5963,14 @@ namespace __format
>> >
>> >     protected:
>> >       template<typename _Tuple, typename _Out, size_t... _Ids>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       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>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems,
>> >                       basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -5929,7 +6000,7 @@ namespace __format
>> >         }
>> >
>> >         template<typename _Out>
>> >-          void
>> >+          _GLIBCXX_CONSTEXPR_FORMAT void
>> >           _M_format(__maybe_const<_Tps, _CharT>&... __elems,
>> >                     basic_format_context<_Out, _CharT>& __fc,
>> >                     _String_view __sep) const
>> >@@ -5945,7 +6016,7 @@ namespace __format
>> >       };
>> >
>> >       template<size_t... _Ids>
>> >-      static auto
>> >+      static _GLIBCXX_CONSTEXPR_FORMAT auto
>> >       _S_create_storage(index_sequence<_Ids...>)
>> >         -> __formatters_storage<_Ids...>;
>> >       using _Formatters
>> >@@ -5981,6 +6052,7 @@ namespace __format
>> >       // We deviate from standard, that declares this as template accepting
>> >       // unconstrained FormatContext type, which seems unimplementable.
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(__maybe_const_pair& __p,
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -6008,6 +6080,7 @@ namespace __format
>> >       // We deviate from standard, that declares this as template accepting
>> >       // unconstrained FormatContext type, which seems unimplementable.
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(__maybe_const_tuple& __t,
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -6171,6 +6244,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>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -6189,6 +6263,7 @@ namespace __format
>> >
>> >     private:
>> >       template<ranges::input_range _Rg, typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const
>> >       {
>> >@@ -6206,6 +6281,7 @@ namespace __format
>> >
>> >
>> >       template<ranges::input_range _Rg, typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       _M_format_elems(_Rg& __rg,
>> >                       basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -6305,6 +6381,7 @@ namespace __format
>> >       // We deviate from standard, that declares this as template accepting
>> >       // unconstrained FormatContext type, which seems unimplementable.
>> >       template<typename _Out>
>> >+      _GLIBCXX_CONSTEXPR_FORMAT
>> >       typename basic_format_context<_Out, _CharT>::iterator
>> >       format(__format::__maybe_const_range<_Rg, _CharT>& __rg,
>> >              basic_format_context<_Out, _CharT>& __fc) const
>> >@@ -6331,6 +6408,7 @@ namespace __format
>> >
>> > #endif // C++23 formatting ranges
>> > #undef _GLIBCXX_WIDEN
>> >+#undef _GLIBCXX_CONSTEXPR_FORMAT
>> >
>> > _GLIBCXX_END_NAMESPACE_VERSION
>> > } // namespace std
>> >diff --git a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc 
>> >b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
>> >index 83c7b22d081..6894d6c4fc3 100644
>> >--- a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
>> >@@ -15,7 +15,7 @@ void test_missing_specialization()
>> > {
>> >   struct X { };
>> >   X x;
>> >-  (void)std::make_format_args(x); // { dg-error "here" }
>> >+  (void)std::make_format_args(x); // { dg-error "(here|in 'constexpr' 
>> >expansion of)" }
>> > // { dg-error "std::formatter must be specialized" "" { target *-*-* } 0 }
>> > }
>> >
>> >@@ -37,7 +37,7 @@ void test(std::formatter<Y>& f, 
>> >std::format_parse_context& pc) {
>> > void test_const_arg()
>> > {
>> >   const Y y;
>> >-  (void)std::make_format_args(y); // { dg-error "here" }
>> >+  (void)std::make_format_args(y); // { dg-error "(here|in 'constexpr' 
>> >expansion of)" }
>> > // { dg-error "format arg must be non-const" "" { target *-*-* } 0 }
>> > }
>> >
>> >diff --git a/libstdc++-v3/testsuite/std/format/constexpr.cc 
>> >b/libstdc++-v3/testsuite/std/format/constexpr.cc
>> >new file mode 100644
>> >index 00000000000..7f806081f4e
>> >--- /dev/null
>> >+++ b/libstdc++-v3/testsuite/std/format/constexpr.cc
>> >@@ -0,0 +1,166 @@
>> >+// { dg-do compile { target c++26 } }
>> >+
>> >+#include <format>
>> >+#include <string>
>> >+#include <string_view>
>> >+#include <tuple>
>> >+#include <vector>
>> >+#include <testsuite_hooks.h>
>> >+
>> >+#if _GLIBCXX_USE_CXX11_ABI
>> >+
>> >+#ifndef __glibcxx_constexpr_format
>> >+# error "Feature test macro for constexpr std::format is missing in 
>> ><format>"
>> >+#elif __glibcxx_constexpr_format < 202511L
>> >+# error "Feature test macro for constexpr std::format has wrong value in 
>> ><format>"
>> >+#endif
>> >+
>> >+// Slightly more general from __format::_Widen, works with character 
>> >literals.
>> >+template<typename CharT>
>> >+consteval auto widen(auto narrow, auto wide)
>> >+{
>> >+  if constexpr (std::is_same_v<CharT, wchar_t>)
>> >+    return wide;
>> >+  else
>> >+    return narrow;
>> >+}
>> >+
>> >+#define WIDEN_(C, S) widen<C>(S, L##S)
>> >+#define WIDEN(S) WIDEN_(CharT, S)
>> >+
>> >+template<typename CharT>
>> >+constexpr void
>> >+test_format()
>> >+{
>> >+  using namespace std;
>> >+
>> >+  basic_string<CharT> res;
>> >+
>> >+  res = format(WIDEN("{}"), WIDEN('c'));
>> >+  VERIFY( res == WIDEN("c") );
>> >+  res = format(WIDEN("{1} {0} {0}"), WIDEN('a'), WIDEN('b'));
>> >+  VERIFY( res == WIDEN("b a a") );
>> >+  res = format(WIDEN("{:?}"), WIDEN('\n'));
>> >+  VERIFY( res == WIDEN("'\\n'") );
>> >+  res = format(WIDEN("{:.^10}"), WIDEN("hello"));
>> >+  VERIFY( res == WIDEN("..hello...") );
>> >+  res = format(WIDEN("{:.>{}}"), WIDEN("world"), 8);
>> >+  VERIFY( res == WIDEN("...world") );
>> >+  res = format(WIDEN("{:+#06X}"), 0xa);
>> >+  VERIFY( res == WIDEN("+0X00A") );
>> >+  res = format(WIDEN("{:p}"), nullptr);
>> >+  VERIFY( res == WIDEN("0x0") );
>> >+  res = format(WIDEN("{:07P}"), nullptr);
>> >+  VERIFY( res == WIDEN("0X00000") );
>> >+  res = format(WIDEN("{} {}"), true, false);
>> >+  VERIFY( res == WIDEN("true false") );
>> >+  res = format(WIDEN("{:+#06b}"), true);
>> >+  VERIFY( res == WIDEN("+0b001") );
>> >+  res = format(WIDEN("{} {} {}"), WIDEN("abc"), 
>> >basic_string_view<CharT>(WIDEN("def")), basic_string<CharT>(WIDEN("ghi")));
>> >+  VERIFY( res == WIDEN("abc def ghi") );
>> >+  res = format(WIDEN("{:?}"), WIDEN("hello\nworld"));
>> >+  VERIFY( res == WIDEN("\"hello\\nworld\"") );
>> >+  res = format(WIDEN("{}"), tuple(1, true));
>> >+  VERIFY( res == WIDEN("(1, true)") );
>> >+  res = format(WIDEN("{:t<12m}"), tuple(WIDEN('a'), WIDEN("bc")));
>> >+  VERIFY( res == WIDEN("'a': \"bc\"ttt") );
>> >+  res = format(WIDEN("{:n}"), tuple(nullptr, -1, 1));
>> >+  VERIFY( res == WIDEN("0x0, -1, 1") );
>> >+  res = format(WIDEN("{}"), vector{1, 2, 3, 4});
>> >+  VERIFY( res == WIDEN("[1, 2, 3, 4]") );
>> >+  res = format(WIDEN("{:?s}"), vector{WIDEN('a'), WIDEN('\n'), 
>> >WIDEN('b')});
>> >+  VERIFY( res == WIDEN("\"a\\nb\"") );
>> >+  res = format(WIDEN("{:n:+}"), vector{1, 2, 3});
>> >+  VERIFY( res == WIDEN("+1, +2, +3") );
>> >+}
>> >+
>> >+template<typename CharT>
>> >+constexpr void
>> >+test_format_to()
>> >+{
>> >+  using namespace std;
>> >+
>> >+  CharT buf[100];
>> >+  CharT* out;
>> >+
>> >+  out = format_to(buf, WIDEN("{:.^5}"), WIDEN("foo"));
>> >+  VERIFY( basic_string_view<CharT>(buf, out) == WIDEN(".foo.") );
>> >+  out = format_to(buf, WIDEN("{} {}"), nullptr, true);
>> >+  VERIFY( basic_string_view<CharT>(buf, out) == WIDEN("0x0 true") );
>> >+}
>> >+
>> >+template<typename CharT>
>> >+constexpr void
>> >+test_vformat()
>> >+{
>> >+  using namespace std;
>> >+  using context = __format::__format_context<CharT>;
>> >+
>> >+  basic_string<CharT> res;
>> >+
>> >+  int arg1 = 1;
>> >+  CharT arg2 = WIDEN('a');
>> >+  bool arg3 = true;
>> >+  res = vformat(WIDEN("{} {:?} {}"), make_format_args<context>(arg1, arg2, 
>> >arg3));
>> >+  VERIFY( res == WIDEN("1 'a' true") );
>> >+}
>> >+
>> >+template<typename CharT>
>> >+constexpr void
>> >+test_vformat_to()
>> >+{
>> >+  using namespace std;
>> >+  using context = __format::__format_context<CharT>;
>> >+
>> >+  CharT buf[100];
>> >+  CharT* out;
>> >+
>> >+  nullptr_t arg1 = nullptr;
>> >+  basic_string<CharT> arg2 = WIDEN("foo");
>> >+  tuple<int, int> arg3{-3, 5};
>> >+  out = vformat_to(buf, WIDEN("{} {:?} {}"), 
>> >make_format_args<context>(arg1, arg2, arg3));
>> >+  VERIFY( basic_string_view<CharT>(buf, out) == WIDEN("0x0 \"foo\" (-3, 
>> >5)") );
>> >+}
>> >+
>> >+template<typename CharT>
>> >+constexpr void
>> >+test_format_to_n()
>> >+{
>> >+  using namespace std;
>> >+
>> >+  CharT buf[100];
>> >+  format_to_n_result<CharT*> out;
>> >+  int n;
>> >+
>> >+  n = 100;
>> >+  out = format_to_n(buf, n, WIDEN("{:+} {:?} {}"), 1, WIDEN("\n\n"), 
>> >vector{1, 2, 3});
>> >+  VERIFY( out.size <= n );
>> >+  VERIFY( out.out - buf == out.size );
>> >+  VERIFY( basic_string_view<CharT>(buf, out.size) == WIDEN("+1 \"\\n\\n\" 
>> >[1, 2, 3]") );
>> >+  n = 12;
>> >+  out = format_to_n(buf, n, WIDEN("{} {} {}"), true, nullptr, WIDEN("long 
>> >string"));
>> >+  VERIFY( out.size > n );
>> >+  VERIFY( out.out - buf == n );
>> >+  VERIFY( basic_string_view<CharT>(buf, out.out) == WIDEN("true 0x0 lon") 
>> >);
>> >+}
>> >+
>> >+constexpr bool
>> >+all_tests()
>> >+{
>> >+  test_format<char>();
>> >+  test_format<wchar_t>();
>> >+  test_format_to<char>();
>> >+  test_format_to<wchar_t>();
>> >+  test_vformat<char>();
>> >+  test_vformat<wchar_t>();
>> >+  test_vformat_to<char>();
>> >+  test_vformat_to<wchar_t>();
>> >+  test_format_to_n<char>();
>> >+  test_format_to_n<wchar_t>();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+static_assert(all_tests());
>> >+
>> >+#endif // _GLIBCXX_USE_CXX11_ABI
>> >diff --git a/libstdc++-v3/testsuite/std/format/debug.cc 
>> >b/libstdc++-v3/testsuite/std/format/debug.cc
>> >index 43e930c579e..01bb9074ba7 100644
>> >--- a/libstdc++-v3/testsuite/std/format/debug.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/debug.cc
>> >@@ -1,5 +1,5 @@
>> >-// { 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 }
>> >@@ -8,19 +8,25 @@
>> > #include <format>
>> > #include <testsuite_hooks.h>
>> >
>> >-std::string
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> >+CONSTEXPR std::string
>> > fdebug(char t)
>> > { return std::format("{:?}", t); }
>> >
>> >-std::wstring
>> >+CONSTEXPR std::wstring
>> > fdebug(wchar_t t)
>> > { return std::format(L"{:?}", t); }
>> >
>> >-std::string
>> >+CONSTEXPR std::string
>> > fdebug(std::string_view t)
>> > { return std::format("{:?}", t); }
>> >
>> >-std::wstring
>> >+CONSTEXPR std::wstring
>> > fdebug(std::wstring_view t)
>> > { return std::format(L"{:?}", t); }
>> >
>> >@@ -29,7 +35,7 @@ fdebug(std::wstring_view t)
>> > #define WIDEN(S) WIDEN_(CharT, S)
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_basic_escapes()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -72,7 +78,7 @@ test_basic_escapes()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_ascii_escapes()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -89,7 +95,7 @@ test_ascii_escapes()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_extended_ascii()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -117,7 +123,7 @@ test_extended_ascii()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_unicode_escapes()
>> > {
>> > #if UNICODE_ENC
>> >@@ -166,7 +172,7 @@ test_unicode_escapes()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_grapheme_extend()
>> > {
>> > #if UNICODE_ENC
>> >@@ -192,7 +198,7 @@ test_grapheme_extend()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_replacement_char()
>> > {
>> > #if UNICODE_ENC
>> >@@ -206,7 +212,7 @@ test_replacement_char()
>> > #endif // UNICODE_ENC
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_ill_formed_utf8_seq()
>> > {
>> > #if UNICODE_ENC
>> >@@ -244,7 +250,7 @@ test_ill_formed_utf8_seq()
>> > #endif // UNICODE_ENC
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_ill_formed_utf32()
>> > {
>> > #if UNICODE_ENC
>> >@@ -269,7 +275,7 @@ test_ill_formed_utf32()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_fill()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -315,7 +321,7 @@ test_fill()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_prec()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -341,7 +347,8 @@ test_prec()
>> > #endif // UNICODE_ENC
>> > }
>> >
>> >-bool strip_quote(std::string_view& v)
>> >+CONSTEXPR 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)
>> >+CONSTEXPR 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)
>> >+CONSTEXPR bool
>> >+strip_prefix(std::string_view& v, size_t n, char c)
>> > {
>> >   size_t pos = v.find_first_not_of(c);
>> >   if (pos == std::string_view::npos)
>> >@@ -369,7 +378,8 @@ bool strip_prefix(std::string_view& v, size_t n, char c)
>> >   return true;
>> > }
>> >
>> >-void test_padding()
>> >+CONSTEXPR void
>> >+test_padding()
>> > {
>> >   std::string res;
>> >   std::string_view resv;
>> >@@ -719,7 +729,8 @@ void test_padding()
>> > #endif // UNICODE_ENC
>> > }
>> >
>> >-void test_char_as_wchar()
>> >+CONSTEXPR void
>> >+test_char_as_wchar()
>> > {
>> >   std::wstring res;
>> >
>> >@@ -751,8 +762,9 @@ struct std::formatter<DebugWrapper<T>, CharT>
>> >   }
>> >
>> >   template<typename Out>
>> >-  Out format(DebugWrapper<T> const& t,
>> >-           std::basic_format_context<Out, CharT>& fc) const
>> >+  CONSTEXPR Out
>> >+  format(DebugWrapper<T> const& t,
>> >+       std::basic_format_context<Out, CharT>& fc) const
>> >   { return under.format(t.val, fc); }
>> >
>> > private:
>> >@@ -760,7 +772,7 @@ private:
>> > };
>> >
>> > template<typename CharT, typename StrT>
>> >-void
>> >+CONSTEXPR void
>> > test_formatter_str()
>> > {
>> >   CharT buf[]{ 'a', 'b', 'c', 0 };
>> >@@ -770,7 +782,7 @@ test_formatter_str()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_formatter_arr()
>> > {
>> >   std::basic_string<CharT> res;
>> >@@ -786,7 +798,7 @@ test_formatter_arr()
>> > }
>> >
>> > template<typename CharT, typename SrcT>
>> >-void
>> >+CONSTEXPR void
>> > test_formatter_char()
>> > {
>> >   DebugWrapper<SrcT> in{ 'a' };
>> >@@ -795,7 +807,7 @@ test_formatter_char()
>> > }
>> >
>> > template<typename CharT>
>> >-void
>> >+CONSTEXPR void
>> > test_formatters()
>> > {
>> >   test_formatter_char<CharT, CharT>();
>> >@@ -806,7 +818,7 @@ test_formatters()
>> >   test_formatter_arr<CharT>();
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_formatters_c()
>> > {
>> >   test_formatters<char>();
>> >@@ -814,7 +826,8 @@ test_formatters_c()
>> >   test_formatter_char<wchar_t, char>();
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_basic_escapes<char>();
>> >   test_basic_escapes<wchar_t>();
>> >@@ -840,4 +853,16 @@ int main()
>> >   test_padding();
>> >
>> >   test_formatters_c();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#if defined(__glibcxx_constexpr_format) && defined(UNICODE_ENC)
>> >+// Deboug ouput is supported only for unicode literal encoding
>> >+static_assert(test_all());
>> >+#endif
>> >+
>> >+int main()
>> >+{
>> >+  test_all();
>> > }
>> >diff --git a/libstdc++-v3/testsuite/std/format/dynamic_format.cc 
>> >b/libstdc++-v3/testsuite/std/format/dynamic_format.cc
>> >index fde2555ccb2..aa3109cca4e 100644
>> >--- a/libstdc++-v3/testsuite/std/format/dynamic_format.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/dynamic_format.cc
>> >@@ -3,7 +3,13 @@
>> > #include <format>
>> > #include <testsuite_hooks.h>
>> >
>> >-void
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> >+CONSTEXPR void
>> > test_char()
>> > {
>> >   std::string fmt = "{}";
>> >@@ -11,7 +17,7 @@ test_char()
>> >   VERIFY( s == "123" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_wchar()
>> > {
>> >   std::wstring fmt = L"{:#o}";
>> >@@ -19,7 +25,7 @@ test_wchar()
>> >   VERIFY( s == L"0710" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_internal_api()
>> > {
>> >   // Using _Dynamic_format_string directly works even in C++20 mode.
>> >@@ -40,9 +46,20 @@ static_assert( 
>> >!std::is_constructible_v<std::format_string<>,
>> > static_assert( !std::is_constructible_v<std::wformat_string<>,
>> >                                       
>> > decltype(std::dynamic_format(L""))&&> );
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_char();
>> >   test_wchar();
>> >   test_internal_api();
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..88e95a788b5 100644
>> >--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
>> >@@ -5,6 +5,12 @@
>> >
>> > #include <format>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > #ifndef __cpp_lib_format
>> > # error "Feature test macro for std::format is missing in <format>"
>> > #elif __cpp_lib_format < 202110L
>> >@@ -41,7 +47,7 @@
>> > #include <cstdio>
>> > #include <testsuite_hooks.h>
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_no_args()
>> > {
>> >   std::string s;
>> >@@ -55,7 +61,7 @@ test_no_args()
>> >   VERIFY( s == "128bpm }" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_unescaped()
>> > {
>> > #ifdef __cpp_exceptions
>> >@@ -78,7 +84,7 @@ struct brit_punc : std::numpunct<char>
>> >   std::string do_falsename() const override { return "nah bruv"; }
>> > };
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_std_examples()
>> > {
>> >   using namespace std;
>> >@@ -125,10 +131,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 +152,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
>> >+CONSTEXPR void
>> > test_alternate_forms()
>> > {
>> >   std::string s;
>> >@@ -180,23 +190,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 +288,7 @@ test_locale()
>> >   std::locale::global(cloc);
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_width()
>> > {
>> >   std::string s;
>> >@@ -317,7 +330,7 @@ test_width()
>> >   }
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_char()
>> > {
>> >   std::string s;
>> >@@ -347,7 +360,7 @@ test_char()
>> >   VERIFY( s == "11110000 11110000 240 360 f0 F0" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_wchar()
>> > {
>> >   using namespace std::literals;
>> >@@ -356,24 +369,27 @@ test_wchar()
>> >   s = std::format(L"{}", L'a');
>> >   VERIFY( s == L"a" );
>> >
>> >-  s = std::format(L"{} {} {} {} {} {}", L'0', 1, 2LL, 3.4, L"five", 
>> >L"six"s);
>> >-  VERIFY( s == L"0 1 2 3.4 five six" );
>> >-
>> >-  std::locale loc;
>> >-  s = std::format(loc, L"{:L} {:.3s}{:Lc}", true, L"data"sv, '.');
>> >-  VERIFY( s == L"true dat." );
>> >-
>> >-  s = std::format(L"{}", 0.0625);
>> >-  VERIFY( s == L"0.0625" );
>> >-  s = std::format(L"{}", 0.25);
>> >-  VERIFY( s == L"0.25" );
>> >-  s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15);
>> >-  VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" );
>> >-
>> >-  double inf = std::numeric_limits<double>::infinity();
>> >-  double nan = std::numeric_limits<double>::quiet_NaN();
>> >-  s = std::format(L"{0} {0:F} {1} {1:E}", -inf, -nan);
>> >-  VERIFY( s == L"-inf -INF -nan -NAN" );
>> >+  if (!std::is_constant_evaluated())
>> >+    {
>> >+      s = std::format(L"{} {} {} {} {} {}", L'0', 1, 2LL, 3.4, L"five", 
>> >L"six"s);
>> >+      VERIFY( s == L"0 1 2 3.4 five six" );
>> >+
>> >+      std::locale loc;
>> >+      s = std::format(loc, L"{:L} {:.3s}{:Lc}", true, L"data"sv, '.');
>> >+      VERIFY( s == L"true dat." );
>> >+
>> >+      s = std::format(L"{}", 0.0625);
>> >+      VERIFY( s == L"0.0625" );
>> >+      s = std::format(L"{}", 0.25);
>> >+      VERIFY( s == L"0.25" );
>> >+      s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15);
>> >+      VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" );
>> >+
>> >+      double inf = std::numeric_limits<double>::infinity();
>> >+      double nan = std::numeric_limits<double>::quiet_NaN();
>> >+      s = std::format(L"{0} {0:F} {1} {1:E}", -inf, -nan);
>> >+      VERIFY( s == L"-inf -INF -nan -NAN" );
>> >+    }
>> >
>> >   s = std::format(L"{0:#b} {0:#B} {0:#x} {0:#X}", 99);
>> >   VERIFY( s == L"0b1100011 0B1100011 0x63 0X63" );
>> >@@ -382,20 +398,23 @@ test_wchar()
>> >   s = std::format(L"{:d} {:d}", wchar_t(-1), char(-1));
>> >   VERIFY( s.find('-') == std::wstring::npos );
>> >
>> >-  auto ws = std::format(L"{:L}", 0.5);
>> >-  VERIFY( ws == L"0.5" );
>> >-  // The default C locale.
>> >-  std::locale cloc = std::locale::classic();
>> >-  // PR libstdc++/119671 use-after-free formatting floating-point to 
>> >wstring
>> >-  ws = std::format(cloc, L"{:L}", 0.5);
>> >-  VERIFY( ws == L"0.5" );
>> >-  // A locale with no name, but with the same facets as the C locale.
>> >-  std::locale locx(cloc, &std::use_facet<std::ctype<char>>(cloc));
>> >-  ws = std::format(locx, L"{:L}", 0.5);
>> >-  VERIFY( ws == L"0.5" );
>> >+  if (!std::is_constant_evaluated())
>> >+    {
>> >+      auto ws = std::format(L"{:L}", 0.5);
>> >+      VERIFY( ws == L"0.5" );
>> >+      // The default C locale.
>> >+      std::locale cloc = std::locale::classic();
>> >+      // PR libstdc++/119671 use-after-free formatting floating-point to 
>> >wstring
>> >+      ws = std::format(cloc, L"{:L}", 0.5);
>> >+      VERIFY( ws == L"0.5" );
>> >+      // A locale with no name, but with the same facets as the C locale.
>> >+      std::locale locx(cloc, &std::use_facet<std::ctype<char>>(cloc));
>> >+      ws = std::format(locx, L"{:L}", 0.5);
>> >+      VERIFY( ws == L"0.5" );
>> >+    }
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_minmax()
>> > {
>> >   auto check = []<typename T, typename U = std::make_unsigned_t<T>>(T, U = 
>> > 0) {
>> >@@ -422,7 +441,7 @@ test_minmax()
>> > #endif
>> > }
>> >
>> >-void
>> >+CONSTEXPR 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
>> >+CONSTEXPR 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
>> >+CONSTEXPR void
>> > test_bool()
>> > {
>> >   std::string s;
>> >@@ -519,7 +547,7 @@ test_bool()
>> >   VERIFY( s == "0 0x1 0X0" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_unicode()
>> > {
>> > #ifdef UNICODE
>> >@@ -579,13 +607,13 @@ test_unicode()
>> > #endif
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_no_args();
>> >   test_unescaped();
>> >   test_std_examples();
>> >   test_alternate_forms();
>> >-  test_locale();
>> >   test_width();
>> >   test_char();
>> >   test_wchar();
>> >@@ -594,4 +622,21 @@ int main()
>> >   test_pointer();
>> >   test_bool();
>> >   test_unicode();
>> >+
>> >+  if (!std::is_constant_evaluated())
>> >+    {
>> >+      test_infnan();
>> >+      test_locale();
>> >+    }
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..ec6816ddba9 100644
>> >--- a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
>> >@@ -6,22 +6,31 @@
>> > #include <cstring>
>> > #include <testsuite_hooks.h>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > struct punct : std::numpunct<char>
>> > {
>> >   std::string do_grouping() const override { return "\2"; }
>> > };
>> >
>> >-void
>> >+CONSTEXPR void
>> > test()
>> > {
>> >   char buf[32] = { };
>> >   auto out = std::format_to(buf, "test");
>> >   VERIFY( out == buf+4 );
>> >
>> >-  std::locale loc({}, new punct);
>> >-  auto out2 = std::format_to(buf, loc, "{:Ld}", 12345);
>> >-  VERIFY( out2 == buf+7 );
>> >-  VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" );
>> >+  if (!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,17 +38,20 @@ struct wpunct : std::numpunct<wchar_t>
>> >   std::string do_grouping() const override { return "\2"; }
>> > };
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_wchar()
>> > {
>> >   wchar_t buf[32] = { };
>> >   auto out = std::format_to(buf, L"123 + 456 = {}", 579);
>> >   VERIFY( out == buf+15 );
>> >
>> >-  std::locale loc({}, new wpunct);
>> >-  auto out2 = std::format_to(buf, loc, L"{:Ld}", 12345);
>> >-  VERIFY( out2 == buf+7 );
>> >-  VERIFY( std::wstring_view(buf, out2 - buf) == L"1,23,45" );
>> >+  if (!std::is_constant_evaluated())
>> >+    {
>> >+      std::locale loc({}, new wpunct);
>> >+      auto out2 = std::format_to(buf, loc, L"{:Ld}", 12345);
>> >+      VERIFY( out2 == buf+7 );
>> >+      VERIFY( std::wstring_view(buf, out2 - buf) == L"1,23,45" );
>> >+    }
>> > }
>> >
>> > template<typename I>
>> >@@ -50,20 +62,20 @@ struct move_only_iterator
>> >   using difference_type = iterator::difference_type;
>> >   using iterator_category = std::output_iterator_tag;
>> >
>> >-  move_only_iterator(iterator b) : base_(b) { }
>> >+  constexpr move_only_iterator(iterator b) : base_(b) { }
>> >   move_only_iterator(move_only_iterator&&) = default;
>> >   move_only_iterator& operator=(move_only_iterator&&) = default;
>> >
>> >-  move_only_iterator& operator++() { ++base_; return *this; }
>> >-  move_only_iterator operator++(int) { auto tmp = *this; ++base_; return 
>> >tmp; }
>> >+  constexpr move_only_iterator& operator++() { ++base_; return *this; }
>> >+  constexpr move_only_iterator operator++(int) { auto tmp = *this; 
>> >++base_; return tmp; }
>> >
>> >-  decltype(auto) operator*() { return *base_; }
>> >+  constexpr decltype(auto) operator*() { return *base_; }
>> >
>> > private:
>> >   iterator base_;
>> > };
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_move_only()
>> > {
>> >   std::string str;
>> >@@ -79,7 +91,7 @@ test_move_only()
>> >   VERIFY( std::wstring_view(vec.data(), vec.size()) == L"format hat!" );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_pr110917()
>> > {
>> >   // PR libstdc++/110917
>> >@@ -90,10 +102,22 @@ test_pr110917()
>> >   VERIFY( ! std::memcmp(buf, "abc 123", 7) );
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test();
>> >   test_wchar();
>> >   test_move_only();
>> >   test_pr110917();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..16029bd5949 100644
>> >--- a/libstdc++-v3/testsuite/std/format/functions/size.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/functions/size.cc
>> >@@ -4,7 +4,13 @@
>> > #include <string>
>> > #include <testsuite_hooks.h>
>> >
>> >-void
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> >+CONSTEXPR void
>> > test()
>> > {
>> >   auto n = std::formatted_size("");
>> >@@ -24,7 +30,7 @@ test()
>> >   VERIFY( n == 5 );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_wchar()
>> > {
>> >   auto n = std::formatted_size(L"");
>> >@@ -44,8 +50,19 @@ test_wchar()
>> >   VERIFY( n == 5 );
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test();
>> >   test_wchar();
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..49c8246fee2 100644
>> >--- a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
>> >@@ -12,6 +12,12 @@
>> > #include <unordered_set>
>> > #include <vector>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > static_assert( std::format_kind<std::vector<int>> == 
>> > std::range_format::sequence );
>> > static_assert( std::format_kind<std::deque<int>> == 
>> > std::range_format::sequence );
>> > static_assert( std::format_kind<std::list<int>> == 
>> > std::range_format::sequence );
>> >@@ -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()
>> >+CONSTEXPR 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;
>> > }
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+static_assert(test_override());
>> >+#endif
>> >+
>> > int main()
>> > {
>> >   test_override();
>> >diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc 
>> >b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
>> >index a50c5b1033f..947e6c3bc60 100644
>> >--- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
>> >@@ -6,6 +6,12 @@
>> > #include <vector>
>> > #include <span>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
>> > #define WIDEN(S) WIDEN_(CharT, S)
>> >
>> >@@ -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
>> >+  CONSTEXPR std::basic_format_context<Out, CharT>::iterator
>> >   format(const MyVector<T, Formatter>& mv,
>> >        std::basic_format_context<Out, CharT>& fc) const
>> >   { return _formatter.format(mv, fc); }
>> >@@ -42,7 +48,7 @@ private:
>> > };
>> >
>> > template<typename CharT, template<typename, typename> class Formatter>
>> >-void
>> >+CONSTEXPR 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
>> >+CONSTEXPR void
>> > test_override()
>> > {
>> >   MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
>> >@@ -115,7 +121,8 @@ test_override()
>> > }
>> >
>> > template<template<typename, typename> class Formatter>
>> >-void test_outputs()
>> >+CONSTEXPR void
>> >+test_outputs()
>> > {
>> >   test_default<char, Formatter>();
>> >   test_default<wchar_t, Formatter>();
>> >@@ -123,7 +130,7 @@ void test_outputs()
>> >   test_override<wchar_t, Formatter>();
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_nested()
>> > {
>> >   MyVector<MyVector<int>> v
>> >@@ -152,7 +159,8 @@ struct std::formatter<MyFlatMap, CharT>
>> >   : std::range_formatter<MyFlatMap::reference>
>> > {};
>> >
>> >-void test_const_ref_type_mismatch()
>> >+CONSTEXPR void
>> >+test_const_ref_type_mismatch()
>> > {
>> >   MyFlatMap m{{1, 11}, {2, 22}};
>> >   std::string res = std::format("{:m}", m);
>> >@@ -163,13 +171,15 @@ template<typename T, typename CharT>
>> > using VectorFormatter = std::formatter<std::vector<T>, CharT>;
>> >
>> > template<template<typename> typename Range>
>> >-void test_nonblocking()
>> >+CONSTEXPR void
>> >+test_nonblocking()
>> > {
>> >   static_assert(!std::enable_nonlocking_formatter_optimization<
>> >                 Range<int>>);
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_outputs<std::range_formatter>();
>> >   test_outputs<VectorFormatter>();
>> >@@ -179,4 +189,15 @@ int main()
>> >   test_nonblocking<std::span>();
>> >   test_nonblocking<std::vector>();
>> >   test_nonblocking<MyVector>();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..cba53b46270 100644
>> >--- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
>> >@@ -1,5 +1,5 @@
>> > // { dg-do run { target c++23 } }
>> >-// { dg-options "-fexec-charset=UTF-8" }
>> >+// { dg-options "-fexec-charset=UTF-8 -fconstexpr-ops-limit=5000000000" }
>> > // { dg-timeout-factor 2 }
>> >
>> > #include <array>
>> >@@ -12,6 +12,12 @@
>> > #include <testsuite_iterators.h>
>> > #include <vector>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > struct NotFormattable
>> > {};
>> >
>> >@@ -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
>> >+CONSTEXPR 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
>> >+CONSTEXPR 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)
>> >+CONSTEXPR bool
>> >+is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
>> > {
>> >   using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
>> >   std::range_formatter<V, CharT> fmt;
>> >@@ -56,7 +63,7 @@ bool is_range_formatter_spec_for(CharT const* spec, Rg&& 
>> >rg)
>> >   }
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_format_string()
>> > {
>> >   // invalid format spec 'p'
>> >@@ -79,7 +86,8 @@ test_format_string()
>> > #define WIDEN(S) WIDEN_(CharT, S)
>> >
>> > template<typename CharT, typename Range, typename Storage>
>> >-void test_output()
>> >+CONSTEXPR void
>> >+test_output()
>> > {
>> >   using Sv = std::basic_string_view<CharT>;
>> >   using T = std::ranges::range_value_t<Range>;
>> >@@ -153,25 +161,30 @@ void test_output()
>> > }
>> >
>> > template<typename Cont>
>> >-void test_output_cont()
>> >+CONSTEXPR void
>> >+test_output_cont()
>> > {
>> >   test_output<char, Cont&, Cont>();
>> >   test_output<wchar_t, Cont const&, Cont>();
>> > }
>> >
>> > template<typename View>
>> >-void test_output_view()
>> >+CONSTEXPR void
>> >+test_output_view()
>> > {
>> >   test_output<char, View, int[3]>();
>> >   test_output<wchar_t, View, int[3]>();
>> > }
>> >
>> >-void
>> >+CONSTEXPR 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 +198,7 @@ test_outputs()
>> >   test_output_view<test_forward_range<const int>>();
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_nested()
>> > {
>> >   std::vector<std::vector<int>> v
>> >@@ -201,7 +214,8 @@ test_nested()
>> >   VERIFY( res == "+[01, 02, 11, 12]+" );
>> > }
>> >
>> >-bool strip_quote(std::string_view& v)
>> >+CONSTEXPR bool
>> >+strip_quote(std::string_view& v)
>> > {
>> >   if (!v.starts_with('"'))
>> >     return false;
>> >@@ -209,7 +223,8 @@ bool strip_quote(std::string_view& v)
>> >   return true;
>> > }
>> >
>> >-bool strip_prefix(std::string_view& v, std::string_view expected, bool 
>> >quoted = false)
>> >+CONSTEXPR bool
>> >+strip_prefix(std::string_view& v, std::string_view expected, bool quoted = 
>> >false)
>> > {
>> >   if (quoted && !strip_quote(v))
>> >     return false;
>> >@@ -221,7 +236,8 @@ bool strip_prefix(std::string_view& v, std::string_view 
>> >expected, bool quoted =
>> >   return true;
>> > }
>> >
>> >-bool strip_squares(std::string_view& v)
>> >+CONSTEXPR bool
>> >+strip_squares(std::string_view& v)
>> > {
>> >   if (!v.starts_with('[') || !v.ends_with(']'))
>> >     return false;
>> >@@ -230,7 +246,8 @@ bool strip_squares(std::string_view& v)
>> >   return true;
>> > }
>> >
>> >-bool strip_prefix(std::string_view& v, size_t n, char c)
>> >+CONSTEXPR bool
>> >+strip_prefix(std::string_view& v, size_t n, char c)
>> > {
>> >   size_t pos = v.find_first_not_of(c);
>> >   if (pos == std::string_view::npos)
>> >@@ -241,7 +258,8 @@ bool strip_prefix(std::string_view& v, size_t n, char c)
>> >   return true;
>> > }
>> >
>> >-void test_padding()
>> >+CONSTEXPR void
>> >+test_padding()
>> > {
>> >   std::string res;
>> >   std::string_view resv;
>> >@@ -323,10 +341,22 @@ void test_padding()
>> >   VERIFY( check_elems(resv, false) );
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_format_string();
>> >   test_outputs();
>> >   test_nested();
>> >   test_padding();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+static_assert(test_all());
>> >+#endif
>> >+
>> >+int main()
>> >+{
>> >+  test_all();
>> > }
>> >diff --git a/libstdc++-v3/testsuite/std/format/string.cc 
>> >b/libstdc++-v3/testsuite/std/format/string.cc
>> >index ee987a15ec3..004690ad8da 100644
>> >--- a/libstdc++-v3/testsuite/std/format/string.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/string.cc
>> >@@ -1,10 +1,17 @@
>> > // { dg-do run { target c++20 } }
>> >+// { dg-options "-fconstexpr-ops-limit=100000000" }
>> >
>> > #include <format>
>> > #include <testsuite_hooks.h>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > template<typename... Args>
>> >-bool
>> >+CONSTEXPR bool
>> > is_format_string_for(const char* str, Args&&... args)
>> > {
>> >   try {
>> >@@ -16,7 +23,7 @@ is_format_string_for(const char* str, Args&&... args)
>> > }
>> >
>> > template<typename... Args>
>> >-bool
>> >+CONSTEXPR bool
>> > is_format_string_for(const wchar_t* str, Args&&... args)
>> > {
>> >   try {
>> >@@ -27,7 +34,7 @@ is_format_string_for(const wchar_t* str, Args&&... args)
>> >   }
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_no_args()
>> > {
>> >   VERIFY( is_format_string_for("") );
>> >@@ -42,7 +49,7 @@ test_no_args()
>> >   VERIFY( ! is_format_string_for("{{{{{") );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_indexing()
>> > {
>> >   VERIFY( is_format_string_for("{} to {}", "a", "b") );   // automatic 
>> > indexing
>> >@@ -68,7 +75,7 @@ constexpr bool escaped_strings_supported = true;
>> > constexpr bool escaped_strings_supported = false;
>> > #endif
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_format_spec()
>> > {
>> >   VERIFY( is_format_string_for("{:}", 1) );
>> >@@ -78,9 +85,14 @@ 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 );
>> >@@ -130,13 +142,16 @@ test_format_spec()
>> >   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) );
>> >+  if (!std::is_constant_evaluated())
>> >+    {
>> >+      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) );
>> >@@ -164,7 +179,7 @@ test_format_spec()
>> >   VERIFY( ! is_format_string_for(L"{:9999999}", 1) );
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_pr110862()
>> > {
>> >   try {
>> >@@ -178,7 +193,7 @@ test_pr110862()
>> >   }
>> > }
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_pr110974()
>> > {
>> >   try {
>> >@@ -197,11 +212,23 @@ test_pr110974()
>> >   }
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_no_args();
>> >   test_indexing();
>> >   test_format_spec();
>> >   test_pr110862();
>> >   test_pr110974();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+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..dc7b860a902 100644
>> >--- a/libstdc++-v3/testsuite/std/format/tuple.cc
>> >+++ b/libstdc++-v3/testsuite/std/format/tuple.cc
>> >@@ -1,5 +1,5 @@
>> > // { dg-do run { target c++23 } }
>> >-// { dg-options "-fexec-charset=UTF-8" }
>> >+// { dg-options "-fexec-charset=UTF-8 -fconstexpr-ops-limit=500000000" }
>> > // { dg-timeout-factor 2 }
>> >
>> > #include <format>
>> >@@ -8,6 +8,12 @@
>> > #include <tuple>
>> > #include <utility>
>> >
>> >+#ifdef __glibcxx_constexpr_format
>> >+# define CONSTEXPR constexpr
>> >+#else
>> >+# define CONSTEXPR
>> >+#endif
>> >+
>> > struct NotFormattable
>> > {};
>> >
>> >@@ -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
>> >+CONSTEXPR 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
>> >+CONSTEXPR bool
>> > is_format_string_for(const wchar_t* str, Args&&... args)
>> > {
>> >   try {
>> >@@ -41,7 +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)
>> >
>> >-void
>> >+CONSTEXPR void
>> > test_format_string()
>> > {
>> >   // invalid format stringss
>> >@@ -123,7 +129,8 @@ void test_multi()
>> > }
>> >
>> > template<typename CharT, typename Tuple>
>> >-void test_empty()
>> >+CONSTEXPR void
>> >+test_empty()
>> > {
>> >   std::basic_string<CharT> res;
>> >
>> >@@ -142,7 +149,8 @@ void test_empty()
>> > }
>> >
>> > template<typename CharT, typename Pair>
>> >-void test_pair()
>> >+CONSTEXPR void
>> >+test_pair()
>> > {
>> >   using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>;
>> >   using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>;
>> >@@ -167,7 +175,8 @@ void test_pair()
>> > }
>> >
>> > template<typename CharT, template<typename, typename> class PairT>
>> >-void test_pair_e()
>> >+CONSTEXPR void
>> >+test_pair_e()
>> > {
>> >   test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
>> >   test_pair<CharT, PairT<int, const CharT*>>();
>> >@@ -196,7 +205,7 @@ struct std::formatter<MyPair<Pair>, CharT>
>> >   { return _formatter.parse(pc);  }
>> >
>> >   template<typename Out>
>> >-  typename std::basic_format_context<Out, CharT>::iterator
>> >+  CONSTEXPR 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 +215,8 @@ private:
>> > };
>> >
>> > template<typename CharT, template<typename, typename> class PairT>
>> >-void test_custom()
>> >+CONSTEXPR void
>> >+test_custom()
>> > {
>> >   std::basic_string<CharT> res;
>> >   MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc"));
>> >@@ -228,9 +238,12 @@ void test_custom()
>> > }
>> >
>> > template<typename CharT>
>> >-void test_outputs()
>> >+CONSTEXPR 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 +251,8 @@ void test_outputs()
>> >   test_custom<CharT, std::tuple>();
>> > }
>> >
>> >-void test_nested()
>> >+CONSTEXPR void
>> >+test_nested()
>> > {
>> >   std::string res;
>> >   std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1, "abc"}};
>> >@@ -251,7 +265,8 @@ void test_nested()
>> >   VERIFY( res == R"((): (1, "abc"))" );
>> > }
>> >
>> >-bool strip_quote(std::string_view& v)
>> >+CONSTEXPR bool
>> >+strip_quote(std::string_view& v)
>> > {
>> >   if (!v.starts_with('"'))
>> >     return false;
>> >@@ -259,7 +274,8 @@ bool strip_quote(std::string_view& v)
>> >   return true;
>> > }
>> >
>> >-bool strip_prefix(std::string_view& v, std::string_view expected, bool 
>> >quoted = false)
>> >+CONSTEXPR bool
>> >+strip_prefix(std::string_view& v, std::string_view expected, bool quoted = 
>> >false)
>> > {
>> >   if (quoted && !strip_quote(v))
>> >     return false;
>> >@@ -271,7 +287,8 @@ bool strip_prefix(std::string_view& v, std::string_view 
>> >expected, bool quoted =
>> >   return true;
>> > }
>> >
>> >-bool strip_parens(std::string_view& v)
>> >+CONSTEXPR bool
>> >+strip_parens(std::string_view& v)
>> > {
>> >   if (!v.starts_with('(') || !v.ends_with(')'))
>> >     return false;
>> >@@ -280,7 +297,8 @@ bool strip_parens(std::string_view& v)
>> >   return true;
>> > }
>> >
>> >-bool strip_prefix(std::string_view& v, size_t n, char c)
>> >+CONSTEXPR bool
>> >+strip_prefix(std::string_view& v, size_t n, char c)
>> > {
>> >   size_t pos = v.find_first_not_of(c);
>> >   if (pos == std::string_view::npos)
>> >@@ -291,7 +309,8 @@ bool strip_prefix(std::string_view& v, size_t n, char c)
>> >   return true;
>> > }
>> >
>> >-void test_padding()
>> >+CONSTEXPR void
>> >+test_padding()
>> > {
>> >   std::string res;
>> >   std::string_view resv;
>> >@@ -351,13 +370,14 @@ struct std::formatter<Custom, CharT>
>> >   { return pc.begin();  }
>> >
>> >   template<typename Out>
>> >-  typename std::basic_format_context<Out, CharT>::iterator
>> >+  CONSTEXPR typename std::basic_format_context<Out, CharT>::iterator
>> >   format(Custom, const std::basic_format_context<Out, CharT>& fc) const
>> >   { return fc.out(); }
>> > };
>> >
>> > template<template<typename...> typename Tuple>
>> >-void test_nonblocking()
>> >+CONSTEXPR void
>> >+test_nonblocking()
>> > {
>> >   static_assert(std::enable_nonlocking_formatter_optimization<
>> >                 Tuple<int, float>>);
>> >@@ -374,7 +394,8 @@ void test_nonblocking()
>> >                 Tuple<Custom&, float&>>);
>> > }
>> >
>> >-int main()
>> >+CONSTEXPR bool
>> >+test_all()
>> > {
>> >   test_format_string();
>> >   test_outputs<char>();
>> >@@ -384,4 +405,15 @@ int main()
>> >
>> >   test_nonblocking<std::pair>();
>> >   test_nonblocking<std::tuple>();
>> >+
>> >+  return true;
>> >+}
>> >+
>> >+#ifdef __glibcxx_constexpr_format
>> >+static_assert(test_all());
>> >+#endif
>> >+
>> >+int main()
>> >+{
>> >+  test_all();
>> > }
>> >diff --git a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc 
>> >b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> >index cb8f916f216..86f3b618599 100644
>> >--- a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> >+++ b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
>> >@@ -161,4 +161,5 @@ auto si7 = std::format("{:%Q}", sys_info()); // { 
>> >dg-error "call to consteval fu
>> > auto si8 = std::format("{:%Z}", sys_info()); // { dg-error "call to 
>> > consteval function" "" { target cxx11_abi } }
>> > #endif
>> >
>> >-// { dg-error "call to non-'constexpr' function" "" { target *-*-* } 0 }
>> >+// { dg-error "call to non-'constexpr' function" "" { target c++23_down } 
>> >0 }
>> >+// { dg-error "'std::terminate' called after throwing an exception" "" { 
>> >target { ! c++23_down } } 0 }
>> >--
>> >2.54.0
>> >
>> >
>>


Reply via email to