[PATCH] libstdc++: implement constexpr std::format
Tomasz Kaminski
tkaminsk@redhat.com
Thu Apr 16 10:33:45 GMT 2026
On Thu, Mar 5, 2026 at 11:27 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
wrote:
> This patch implements constexpr formatting from P3391R2,
> and introduces the constexpr_format feature-test macro.
>
> This patch mostly adds `_GLIBCXX26_CONSTEXPR` to functions.
>
> Add `__format::__toupper_numeric` function that work in constexpr.
> It is not fully general, but `<format>` doesn't need all uppercasing.
>
> Avoid using `_Ptr_sink` in constexpr in `__do_vformat_to`,
> since it is a bit non-trivial to get it to work, and it is just an
> optimization.
>
> 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.
>
> Mark integer to_{,w}string functions constexpr.
> Introduce constexpr tests for them.
>
> Update some formatting tests to test constexpr as well,
> and introduce a dedicated smoke test for constexpr formatting.
>
> libstdc++-v3/include/ChangeLog:
>
> * bits/basic_string.h:
> Add _GLIBCXX26_CONSTEXPR to std::to_{,w}string.
> * bits/version.def: Add constexpr_format.
> * bits/version.h: Regenerate.
> * std/format:
> Expose constexpr_format feature-test macro,
> pepper in _GLIBCXX26_CONSTEXPR, replace memcpy with ranges::copy.
> (__format::__toupper_numeric): Define.
> (__format::__do_vformat_to): Avoid using _Ptr_sink in constexpr.
>
> libstdc++-v3/testsuite/ChangeLog:
>
> * std/format/arguments/args_neg.cc: Diagnostics change.
> * std/format/constexpr.cc: New test.
> * std/format/debug.cc: Constexpr testing.
> * std/format/functions/format.cc: Constexpr testing.
> * std/format/functions/format_to.cc: Constexpr testing.
> * std/format/functions/size.cc: Constexpr testing.
> * std/format/ranges/format_kind.cc: Constexpr testing.
> * std/format/ranges/formatter.cc: Constexpr testing.
> * std/format/ranges/sequence.cc: Constexpr testing.
> * std/format/runtime_format.cc: Constexpr testing.
> * std/format/string.cc: Constexpr testing.
> * std/format/tuple.cc: Constexpr testing.
> * std/time/format/data_not_present_neg.cc: Diagnostics change.
> *
> 21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc:
> New test.
> *
> 21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc:
> New test.
>
> Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> ---
> Rebased, only non-merged prerequisites are:
> * libstdc++: Introduce __format::_Ptr_sink for contingous iterators.
> * libstdc+: Eliminate usage of alloca for non-localized formatting
>
> Added constexpr to std::to_{,w}string, added tests for them.
> The couple existing tests I looked at don't allow for easy constexpr
> testing,
> for example to_string_int.cc test depends on snprintf.
>
> In current shape it's rather complete, might make sense to drop no_stdname
> from the feature-test macro.
>
>
> libstdc++-v3/include/bits/basic_string.h | 24 +-
> libstdc++-v3/include/bits/version.def | 11 +
> libstdc++-v3/include/bits/version.h | 9 +
> libstdc++-v3/include/std/format | 387 +++++++++++-------
> .../char/to_string_constexpr.cc | 63 +++
> .../wchar_t/to_wstring_constexpr.cc | 63 +++
> .../std/format/arguments/args_neg.cc | 4 +-
> .../testsuite/std/format/constexpr.cc | 156 +++++++
> libstdc++-v3/testsuite/std/format/debug.cc | 82 ++--
> .../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 ++-
> .../testsuite/std/format/runtime_format.cc | 17 +-
> libstdc++-v3/testsuite/std/format/string.cc | 59 ++-
> libstdc++-v3/testsuite/std/format/tuple.cc | 70 +++-
> .../std/time/format/data_not_present_neg.cc | 3 +-
> 19 files changed, 1026 insertions(+), 400 deletions(-)
> create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc
> create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc
> create mode 100644 libstdc++-v3/testsuite/std/format/constexpr.cc
>
> diff --git a/libstdc++-v3/include/bits/basic_string.h
> b/libstdc++-v3/include/bits/basic_string.h
> index 9bbe16507d0..1317b292335 100644
> --- a/libstdc++-v3/include/bits/basic_string.h
> +++ b/libstdc++-v3/include/bits/basic_string.h
> @@ -4582,7 +4582,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> // DR 1261. Insufficent overloads for to_string / to_wstring
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(int __val)
> #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_INT__) <= 32
> noexcept // any 32-bit value fits in the SSO buffer
> @@ -4601,7 +4601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> }
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(unsigned __val)
> #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_INT__) <= 32
> noexcept // any 32-bit value fits in the SSO buffer
> @@ -4617,7 +4617,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> }
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(long __val)
> #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_LONG__) <= 32
> noexcept // any 32-bit value fits in the SSO buffer
> @@ -4636,7 +4636,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> }
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(unsigned long __val)
> #if _GLIBCXX_USE_CXX11_ABI && (__CHAR_BIT__ * __SIZEOF_LONG__) <= 32
> noexcept // any 32-bit value fits in the SSO buffer
> @@ -4652,7 +4652,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> }
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(long long __val)
> {
> const bool __neg = __val < 0;
> @@ -4669,7 +4669,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> }
>
> _GLIBCXX_NODISCARD
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> to_string(unsigned long long __val)
> {
> const auto __len = __detail::__to_chars_len(__val);
> @@ -4893,32 +4893,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> #pragma GCC diagnostic pop
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(int __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(unsigned __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(long __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(unsigned long __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(long long __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> _GLIBCXX_NODISCARD
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> to_wstring(unsigned long long __val)
> { return std::__to_wstring_numeric(std::to_string(__val)); }
>
> diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> index dbe95b8b79f..c754ee1c483 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1330,6 +1330,17 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = constexpr_format;
> + // 202511 P3391R2 constexpr std::format
> + no_stdname = true; // not fully implemented yet
> + values = {
> + v = 202511;
> + cxxmin = 26;
> + hosted = yes;
> + };
> +};
> +
> ftms = {
> name = format_uchar;
> values = {
> diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> index eee99847490..13c0466c0dd 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -1476,6 +1476,15 @@
> #endif /* !defined(__cpp_lib_format) */
> #undef __glibcxx_want_format
>
> +#if !defined(__cpp_lib_constexpr_format)
> +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
> +# define __glibcxx_constexpr_format 202511L
> +# if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_constexpr_format)
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_constexpr_format) */
> +#undef __glibcxx_want_constexpr_format
> +
> #if !defined(__cpp_lib_format_uchar)
> # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
> # define __glibcxx_format_uchar 202311L
> diff --git a/libstdc++-v3/include/std/format
> b/libstdc++-v3/include/std/format
> index c5173bfac80..f732dcbd281 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
> @@ -128,6 +129,7 @@ namespace __format
> struct _Runtime_format_string
> {
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> _Runtime_format_string(basic_string_view<_CharT> __s) noexcept
> : _M_str(__s) { }
>
> @@ -170,9 +172,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__]]
> + _GLIBCXX26_CONSTEXPR
> basic_format_string(__format::_Runtime_format_string<_CharT> __s)
> noexcept
> : _M_str(__s._M_str)
> { }
> @@ -197,13 +200,13 @@ namespace __format
>
> #if __cpp_lib_format >= 202311L // >= C++26
> [[__gnu__::__always_inline__]]
> - inline __format::_Runtime_format_string<char>
> + inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string<char>
> runtime_format(string_view __fmt) noexcept
> { return __fmt; }
>
> #ifdef _GLIBCXX_USE_WCHAR_T
> [[__gnu__::__always_inline__]]
> - inline __format::_Runtime_format_string<wchar_t>
> + inline _GLIBCXX26_CONSTEXPR __format::_Runtime_format_string<wchar_t>
> runtime_format(wstring_view __fmt) noexcept
> { return __fmt; }
> #endif
> @@ -238,7 +241,7 @@ namespace __format
>
> /// @cond undocumented
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __throw_format_error(const char* __what)
> { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
>
> @@ -249,27 +252,27 @@ namespace __format
> // XXX use named functions for each constexpr error?
>
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __unmatched_left_brace_in_format_string()
> { __throw_format_error("format error: unmatched '{' in format string");
> }
>
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __unmatched_right_brace_in_format_string()
> { __throw_format_error("format error: unmatched '}' in format string");
> }
>
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __conflicting_indexing_in_format_string()
> { __throw_format_error("format error: conflicting indexing style in
> format string"); }
>
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __invalid_arg_id_in_format_string()
> { __throw_format_error("format error: invalid arg-id in format
> string"); }
>
> [[noreturn]]
> - inline void
> + inline _GLIBCXX26_CONSTEXPR void
> __failed_to_parse_format_spec()
> { __throw_format_error("format error: failed to parse format-spec"); }
>
> @@ -517,7 +520,7 @@ namespace __format
> using enum _WidthPrec;
>
> template<typename _Context>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> __int_from_arg(const basic_format_arg<_Context>& __arg);
>
> constexpr bool __is_digit(char __c)
> @@ -750,7 +753,7 @@ namespace __format
> }
>
> template<typename _Context>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> _M_get_width(_Context& __ctx) const
> {
> size_t __width = 0;
> @@ -762,7 +765,7 @@ namespace __format
> }
>
> template<typename _Context>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> _M_get_precision(_Context& __ctx) const
> {
> size_t __prec = -1;
> @@ -775,7 +778,7 @@ namespace __format
> };
>
> template<typename _Int>
> - inline char*
> + inline _GLIBCXX26_CONSTEXPR char*
> __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
> {
> if (__i < 0)
> @@ -792,7 +795,7 @@ namespace __format
> // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter).
> template<typename _Out, typename _CharT>
> requires output_iterator<_Out, const _CharT&>
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> __write(_Out __out, basic_string_view<_CharT> __str)
> {
> if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
> @@ -809,7 +812,7 @@ namespace __format
> // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN.
> // pre: __align != _Align_default
> template<typename _Out, typename _CharT>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_padded(_Out __out, basic_string_view<_CharT> __str,
> _Align __align, size_t __nfill, char32_t __fill_char)
> {
> @@ -883,7 +886,7 @@ namespace __format
> // Write STR to OUT, with alignment and padding as determined by SPEC.
> // pre: __spec._M_align != _Align_default || __align != _Align_default
> template<typename _CharT, typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>>
> __str,
> size_t __estimated_width,
> basic_format_context<_Out, _CharT>& __fc,
> @@ -905,7 +908,7 @@ namespace __format
> }
>
> template<typename _CharT>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> __truncate(basic_string_view<_CharT>& __s, size_t __prec)
> {
> if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
> @@ -1049,7 +1052,7 @@ namespace __format
>
> using uint_least32_t = __UINT_LEAST32_TYPE__;
> template<typename _Out, typename _CharT>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escape_seq(_Out __out, uint_least32_t __val,
> basic_string_view<_CharT> __prefix)
> {
> @@ -1079,7 +1082,7 @@ namespace __format
> }
>
> template<typename _Out, typename _CharT>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
> {
> using _UChar = make_unsigned_t<_CharT>;
> @@ -1090,7 +1093,7 @@ namespace __format
> }
>
> template<typename _Out, typename _CharT>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escaped_char(_Out __out, _CharT __c)
> {
> using _UChar = make_unsigned_t<_CharT>;
> @@ -1116,7 +1119,7 @@ namespace __format
> }
>
> template<typename _CharT, typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
>
We need to consider whether to make this function constexpr, because
currently
for all non-unicode encodings, we do not escape anything higher than >= 7F.
In future we may want to implement a better solution here that might not be
usable at compile time.
time (like transcode to unicode, based on text_encoding::literal).
We could simply make this function non-constexpr, or alternatively have if
cosnteval function,
that will check if __str contains only letters, digits, punctuators,
standard-escapes and 0,
and call __builing_constexpr_diag/non-cosntexpr function otherwise. This
will still accept
decent amount of text.
> __write_escaped_ascii(_Out __out,
> basic_string_view<_CharT> __str,
> _Term_char __term)
> @@ -1146,7 +1149,7 @@ namespace __format
> }
>
> template<typename _CharT, typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escaped_unicode_part(_Out __out, basic_string_view<_CharT>&
> __str,
> bool& __prev_esc, _Term_char __term)
> {
> @@ -1224,7 +1227,7 @@ namespace __format
> }
>
> template<typename _CharT, typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str,
> _Term_char __term)
> {
> @@ -1236,7 +1239,7 @@ namespace __format
> }
>
> template<typename _CharT, typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __write_escaped(_Out __out, basic_string_view<_CharT> __str,
> _Term_char __term)
> {
> __out = __format::__write(__out, _Escapes<_CharT>::_S_term(__term));
> @@ -1257,12 +1260,14 @@ namespace __format
> struct _Optional_locale
> {
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> _Optional_locale() : _M_dummy(), _M_hasval(false) { }
>
> _Optional_locale(const locale& __loc) noexcept
> : _M_loc(__loc), _M_hasval(true)
> { }
>
> + _GLIBCXX26_CONSTEXPR
> _Optional_locale(const _Optional_locale& __l) noexcept
> : _M_dummy(), _M_hasval(__l._M_hasval)
> {
> @@ -1270,6 +1275,7 @@ namespace __format
> std::construct_at(&_M_loc, __l._M_loc);
> }
>
> + _GLIBCXX26_CONSTEXPR
> _Optional_locale&
> operator=(const _Optional_locale& __l) noexcept
> {
> @@ -1291,6 +1297,7 @@ namespace __format
> return *this;
> }
>
> + _GLIBCXX26_CONSTEXPR
> ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
>
> _Optional_locale&
> @@ -1317,7 +1324,8 @@ namespace __format
> return _M_loc;
> }
>
> - bool has_value() const noexcept { return _M_hasval; }
> + _GLIBCXX26_CONSTEXPR bool
> + has_value() const noexcept { return _M_hasval; }
>
> union {
> char _M_dummy = '\0';
> @@ -1391,7 +1399,7 @@ namespace __format
> }
>
> template<typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> format(basic_string_view<_CharT> __s,
> basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -1408,7 +1416,7 @@ namespace __format
> }
>
> template<typename _Out>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> _M_format_escaped(basic_string_view<_CharT> __s,
> basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -1433,7 +1441,7 @@ namespace __format
> #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
> template<ranges::input_range _Rg, typename _Out>
> requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
> _CharT>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>&
> __fc) const
> {
> using _Range = remove_reference_t<_Rg>;
> @@ -1482,6 +1490,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 +1671,7 @@ namespace __format
> }
>
> template<typename _Int, typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -1690,11 +1721,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 +1730,7 @@ namespace __format
> if (_M_spec._M_alt && __base_prefix.size())
> {
> __start -= __base_prefix.size();
> - __builtin_memcpy(__start, __base_prefix.data(),
> - __base_prefix.size());
> + ranges::copy(__base_prefix, __start);
> }
> __start = __format::__put_sign(__i, _M_spec._M_sign, __start -
> 1);
>
> @@ -1726,6 +1752,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -1756,6 +1783,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> _M_format_character(_CharT __c,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -1787,7 +1815,7 @@ namespace __format
> }
>
> template<typename _Int>
> - static _CharT
> + static _GLIBCXX26_CONSTEXPR _CharT
> _S_to_character(_Int __i)
> {
> using _Traits = __gnu_cxx::__int_traits<_CharT>;
> @@ -1808,6 +1836,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> 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
> @@ -2197,7 +2226,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;
> @@ -2508,10 +2537,13 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(const void* __v, basic_format_context<_Out, _CharT>& __fc)
> const
> {
> - auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
> + auto __u = __v
> + ? reinterpret_cast<__UINTPTR_TYPE__>(__v)
> + : (__UINTPTR_TYPE__)0;
> return __formatter_int<_CharT>(_M_spec).format(__u, __fc);
> }
>
> @@ -2546,6 +2578,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -2584,6 +2617,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, wchar_t>::iterator
> format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
> {
> @@ -2619,6 +2653,7 @@ namespace __format
>
> template<typename _Out>
> [[__gnu__::__nonnull__]]
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
> { return _M_f.format(__u, __fc); }
> @@ -2648,6 +2683,7 @@ namespace __format
>
> template<typename _Out>
> [[__gnu__::__nonnull__]]
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(const _CharT* __u,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -2678,6 +2714,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(const _CharT (&__u)[_Nm],
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -2707,6 +2744,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, char>::iterator
> format(const basic_string<char, _Traits, _Alloc>& __u,
> basic_format_context<_Out, char>& __fc) const
> @@ -2739,6 +2777,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, wchar_t>::iterator
> format(const basic_string<wchar_t, _Traits, _Alloc>& __u,
> basic_format_context<_Out, wchar_t>& __fc) const
> @@ -2772,6 +2811,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, char>::iterator
> format(basic_string_view<char, _Traits> __u,
> basic_format_context<_Out, char>& __fc) const
> @@ -2804,6 +2844,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, wchar_t>::iterator
> format(basic_string_view<wchar_t, _Traits> __u,
> basic_format_context<_Out, wchar_t>& __fc) const
> @@ -2867,6 +2908,7 @@ namespace __format
> }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
> { return _M_f.format(__u, __fc); }
> @@ -3078,6 +3120,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(const void* __v, basic_format_context<_Out, _CharT>& __fc)
> const
> { return _M_f.format(__v, __fc); }
> @@ -3103,6 +3146,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
> { return _M_f.format(__v, __fc); }
> @@ -3128,6 +3172,7 @@ namespace __format
> { return _M_f.parse(__pc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
> { return _M_f.format(nullptr, __fc); }
> @@ -3272,11 +3317,11 @@ namespace __format
> constexpr _Sink_iter
> operator++(int) { return *this; }
>
> - auto
> + _GLIBCXX26_CONSTEXPR auto
> _M_reserve(size_t __n) const
> { return _M_sink->_M_reserve(__n); }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_discarding() const
> { return _M_sink->_M_discarding(); }
> };
> @@ -3308,7 +3353,7 @@ namespace __format
>
> // The portion of the span that has been written to.
> [[__gnu__::__always_inline__]]
> - span<_CharT>
> + _GLIBCXX26_CONSTEXPR span<_CharT>
> _M_used() const noexcept
> { return _M_span.first(_M_next - _M_span.begin()); }
>
> @@ -3325,7 +3370,7 @@ namespace __format
> { _M_next = _M_span.begin(); }
>
> // Replace the current output range.
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
> {
> _M_span = __s;
> @@ -3365,11 +3410,14 @@ namespace __format
> struct _Reservation
> {
> // True if the reservation was successful, false otherwise.
> + _GLIBCXX26_CONSTEXPR
> explicit operator bool() const noexcept { return _M_sink; }
> // A pointer to write directly to the sink.
> - _CharT* get() const noexcept { return
> _M_sink->_M_next.operator->(); }
> + _GLIBCXX26_CONSTEXPR _CharT*
> + get() const noexcept { return _M_sink->_M_next.operator->(); }
> // Add n to the _M_next iterator for the sink.
> - void _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
> + _GLIBCXX26_CONSTEXPR void
> + _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
> _Sink* _M_sink;
> };
>
> @@ -3377,7 +3425,7 @@ namespace __format
> // If anything is written to the reservation then there must be a
> call
> // to _M_bump(N2) before any call to another member function of
> *this,
> // where N2 is the number of characters written.
> - virtual _Reservation
> + _GLIBCXX26_CONSTEXPR virtual _Reservation
> _M_reserve(size_t __n)
> {
> if (__n <= _M_unused().size())
> @@ -3394,12 +3442,12 @@ namespace __format
>
> // Update the next output position after writing directly to the
> sink.
> // pre: no calls to _M_write or _M_overflow since _M_reserve.
> - virtual void
> + _GLIBCXX26_CONSTEXPR virtual void
> _M_bump(size_t __n)
> { _M_next += __n; }
>
> // Returns true if the _Sink is discarding incoming characters.
> - virtual bool
> + _GLIBCXX26_CONSTEXPR virtual bool
> _M_discarding() const
> { return false; }
>
> @@ -3417,7 +3465,7 @@ namespace __format
> template<typename _CharT>
> class _Fixedbuf_sink final : public _Sink<_CharT>
> {
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> __glibcxx_assert(false);
> @@ -3465,7 +3513,7 @@ namespace __format
> _Seq _M_seq;
> protected:
> // Transfer buffer contents to the sequence, so buffer can be
> refilled.
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> auto __s = this->_M_used();
> @@ -3484,7 +3532,7 @@ namespace __format
> this->_M_rewind();
> }
>
> - typename _Sink<_CharT>::_Reservation
> + _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
> _M_reserve(size_t __n) override
> {
> // We might already have n characters available in
> this->_M_unused(),
> @@ -3520,7 +3568,7 @@ namespace __format
> return _Sink<_CharT>::_M_reserve(__n);
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_bump(size_t __n) override
> {
> if constexpr (__is_specialization_of<_Seq, basic_string>
> @@ -3535,7 +3583,8 @@ namespace __format
> }
> }
>
> - void _M_trim(span<const _CharT> __s)
> + _GLIBCXX26_CONSTEXPR void
> + _M_trim(span<const _CharT> __s)
> requires __is_specialization_of<_Seq, basic_string>
> {
> _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf
> @@ -3551,16 +3600,18 @@ namespace __format
> // to _M_buf if it overflows? Or even do that for all unused
> capacity?
>
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
> { }
>
> + _GLIBCXX26_CONSTEXPR
> _Seq_sink(_Seq&& __s)
> noexcept(is_nothrow_move_constructible_v<_Seq>)
> : _M_seq(std::move(__s))
> { }
>
> using _Sink<_CharT>::out;
>
> - _Seq
> + _GLIBCXX26_CONSTEXPR _Seq
> get() &&
> {
> if (this->_M_used().size() != 0)
> @@ -3570,7 +3621,7 @@ namespace __format
>
> // A writable span that views everything written to the sink.
> // Will be either a view over _M_seq or the used part of _M_buf.
> - span<_CharT>
> + _GLIBCXX26_CONSTEXPR span<_CharT>
> _M_span()
> {
> auto __s = this->_M_used();
> @@ -3583,7 +3634,7 @@ namespace __format
> return __s;
> }
>
> - basic_string_view<_CharT>
> + _GLIBCXX26_CONSTEXPR basic_string_view<_CharT>
> view()
> {
> auto __span = _M_span();
> @@ -3608,7 +3659,7 @@ namespace __format
> protected:
> size_t _M_count = 0;
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> auto __s = this->_M_used();
> @@ -3628,7 +3679,7 @@ namespace __format
> _M_count += __s.size();
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_discarding() const override
> {
> // format_to_n return total number of characters, that would be
> written,
> @@ -3638,14 +3689,14 @@ namespace __format
>
> public:
> [[__gnu__::__always_inline__]]
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1)
> : _M_out(std::move(__out)), _M_max(__max)
> { }
>
> using _Sink<_CharT>::out;
>
> - format_to_n_result<_OutIter>
> + _GLIBCXX26_CONSTEXPR format_to_n_result<_OutIter>
> _M_finish() &&
> {
> if (this->_M_used().size() != 0)
> @@ -3674,7 +3725,7 @@ namespace __format
> _CharT _M_buf[64]; // Write here after outputting _M_max characters.
>
> protected:
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> if (this->_M_unused().size() != 0)
> @@ -3698,7 +3749,7 @@ namespace __format
> }
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_discarding() const override
> {
> // format_to_n return total number of characters, that would be
> written,
> @@ -3706,7 +3757,7 @@ namespace __format
> return false;
> }
>
> - typename _Sink<_CharT>::_Reservation
> + _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
> _M_reserve(size_t __n) final
> {
> auto __avail = this->_M_unused();
> @@ -3723,7 +3774,7 @@ namespace __format
>
> private:
> template<typename _IterDifference>
> - static size_t
> + static _GLIBCXX26_CONSTEXPR size_t
> _S_trim_max(_IterDifference __max)
> {
> if (__max < 0)
> @@ -3736,7 +3787,7 @@ namespace __format
> }
>
> [[__gnu__::__always_inline__]]
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_rebuf(_CharT* __ptr, size_t __total, size_t __inuse = 0)
> {
> std::span<_CharT> __span(__ptr, __total);
> @@ -3744,7 +3795,7 @@ namespace __format
> }
>
> public:
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Ptr_sink(_CharT* __ptr, size_t __n = _S_no_limit) noexcept
> : _Sink<_CharT>(_M_buf), _M_max(__n)
> {
> @@ -3769,13 +3820,13 @@ namespace __format
> }
>
> template<contiguous_iterator _OutIter>
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Ptr_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1)
> : _Ptr_sink(std::to_address(__out), _S_trim_max(__n))
> { }
>
> template<contiguous_iterator _OutIter>
> - format_to_n_result<_OutIter>
> + _GLIBCXX26_CONSTEXPR format_to_n_result<_OutIter>
> _M_finish(_OutIter __first) const
> {
> auto __s = this->_M_used();
> @@ -3817,12 +3868,12 @@ namespace __format
> size_t _M_printwidth;
>
> [[__gnu__::__always_inline__]]
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_ignoring() const
> { return _M_printwidth >= _M_maxwidth; }
>
> [[__gnu__::__always_inline__]]
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_buffering() const
> {
> if (_M_printwidth < _M_padwidth)
> @@ -3832,7 +3883,7 @@ namespace __format
> return false;
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_sync_discarding()
> {
> if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
> @@ -3840,7 +3891,7 @@ namespace __format
> _M_maxwidth = _M_printwidth;
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_flush()
> {
> span<_CharT> __new = this->_M_used();
> @@ -3850,7 +3901,7 @@ namespace __format
> this->_M_rewind();
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_force_update()
> {
> auto __str = this->view();
> @@ -3878,7 +3929,7 @@ namespace __format
> return false;
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_update(size_t __new)
> {
> _M_printwidth += __new;
> @@ -3888,7 +3939,7 @@ namespace __format
> return true;
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> // Ignore characters in buffer, and override it.
> @@ -3903,11 +3954,11 @@ namespace __format
> _Str_sink<_CharT>::_M_overflow();
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_discarding() const override
> { return _M_ignoring(); }
>
> - typename _Sink<_CharT>::_Reservation
> + _GLIBCXX26_CONSTEXPR typename _Sink<_CharT>::_Reservation
> _M_reserve(size_t __n) override
> {
> // Ignore characters in buffer, if any.
> @@ -3926,7 +3977,7 @@ namespace __format
> return _Sink<_CharT>::_M_reserve(__n);
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_bump(size_t __n) override
> {
> // Ignore the written characters.
> @@ -3941,19 +3992,19 @@ namespace __format
>
> public:
> [[__gnu__::__always_inline__]]
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth)
> : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
> _M_out(std::move(__out)), _M_printwidth(0)
> { _M_sync_discarding(); }
>
> [[__gnu__::__always_inline__]]
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Padding_sink(_Out __out, size_t __padwidth)
> : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
> { }
>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> _M_finish(_Align __align, char32_t __fill_char)
> {
> // Handle any characters in the buffer.
> @@ -3992,14 +4043,14 @@ namespace __format
> unsigned _M_prev_escape : 1;
> unsigned _M_out_discards : 1;
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_sync_discarding()
> {
> if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
> _M_out_discards = _M_out._M_discarding();
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_write()
> {
> span<_CharT> __bytes = this->_M_used();
> @@ -4025,7 +4076,7 @@ namespace __format
> _M_sync_discarding();
> }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_overflow() override
> {
> if (_M_out_discards)
> @@ -4034,13 +4085,13 @@ namespace __format
> _M_write();
> }
>
> - bool
> + _GLIBCXX26_CONSTEXPR bool
> _M_discarding() const override
> { return _M_out_discards; }
>
> public:
> [[__gnu__::__always_inline__]]
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> _Escaping_sink(_Out __out, _Term_char __term)
> : _M_out(std::move(__out)), _M_term(__term),
> _M_prev_escape(true), _M_out_discards(false)
> @@ -4049,7 +4100,7 @@ namespace __format
> _M_sync_discarding();
> }
>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> _M_finish()
> {
> if (_M_out_discards)
> @@ -4101,7 +4152,7 @@ namespace __format
> const _Tp, _Tp>;
>
> template<typename _Tq>
> - static void
> + static _GLIBCXX26_CONSTEXPR void
> _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
> _Context& __format_ctx, const void* __ptr)
> {
> @@ -4114,7 +4165,7 @@ namespace __format
>
> template<typename _Tp>
> requires (!is_same_v<remove_cv_t<_Tp>, handle>)
> - explicit
> + explicit _GLIBCXX26_CONSTEXPR
> handle(_Tp& __val) noexcept
> : _M_ptr(__builtin_addressof(__val))
> , _M_func(&_S_format<__maybe_const_t<_Tp>>)
> @@ -4127,7 +4178,7 @@ namespace __format
> handle& operator=(const handle&) = default;
>
> [[__gnu__::__always_inline__]]
> - void
> + void _GLIBCXX26_CONSTEXPR
> format(basic_format_parse_context<_CharT>& __pc, _Context& __fc)
> const
> { _M_func(__pc, __fc, this->_M_ptr); }
>
> @@ -4179,10 +4230,12 @@ namespace __format
> };
>
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> _Arg_value() : _M_none() { }
>
> #if 0
> template<typename _Tp>
> + _GLIBCXX26_CONSTEXPR
> _Arg_value(in_place_type_t<_Tp>, _Tp __val)
> { _S_get<_Tp>() = __val; }
> #endif
> @@ -4191,7 +4244,7 @@ namespace __format
> // Value of second argument (if provided), is assigned to that
> member.
> template<typename _Tp, typename _Self, typename... _Value>
> [[__gnu__::__always_inline__]]
> - static auto&
> + static _GLIBCXX26_CONSTEXPR auto&
> _S_access(_Self& __u, _Value... __value) noexcept
> {
> static_assert(sizeof...(_Value) <= 1);
> @@ -4255,23 +4308,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&
> + _GLIBCXX26_CONSTEXPR auto&
> _M_get() noexcept
> { return _S_access<_Tp>(*this); }
>
> template<typename _Tp>
> [[__gnu__::__always_inline__]]
> - const auto&
> + _GLIBCXX26_CONSTEXPR const auto&
> _M_get() const noexcept
> { return _S_access<_Tp>(*this); }
>
> template<typename _Tp>
> [[__gnu__::__always_inline__]]
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_set(_Tp __v) noexcept
> {
> // Explicitly construct types without trivial default
> constructor.
> @@ -4291,7 +4345,8 @@ namespace __format
> class _Arg_store;
>
> template<typename _Visitor, typename _Ctx>
> - decltype(auto) __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
> + _GLIBCXX26_CONSTEXPR decltype(auto)
> + __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>
> template<typename _Ch, typename _Tp>
> consteval _Arg_t
> @@ -4308,20 +4363,21 @@ namespace __format
> using handle = __format::_Arg_value<_Context>::handle;
>
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
>
> [[nodiscard,__gnu__::__always_inline__]]
> - explicit operator bool() const noexcept
> + explicit _GLIBCXX26_CONSTEXPR operator bool() const noexcept
> { return _M_type != __format::_Arg_none; }
>
> #if __cpp_lib_format >= 202306L // >= C++26
> template<typename _Visitor>
> - decltype(auto)
> + _GLIBCXX26_CONSTEXPR decltype(auto)
> visit(this basic_format_arg __arg, _Visitor&& __vis)
> { return __arg._M_visit_user(std::forward<_Visitor>(__vis),
> __arg._M_type); }
>
> template<typename _Res, typename _Visitor>
> - _Res
> + _GLIBCXX26_CONSTEXPR _Res
> visit(this basic_format_arg __arg, _Visitor&& __vis)
> { return __arg._M_visit_user(std::forward<_Visitor>(__vis),
> __arg._M_type); }
> #endif
> @@ -4498,7 +4554,7 @@ namespace __format
> }
>
> template<typename _Tp>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_set(_Tp __v) noexcept
> {
> _M_type = _S_to_enum<_Tp>();
> @@ -4507,7 +4563,7 @@ namespace __format
>
> template<typename _Tp>
> requires __format::__formattable_with<_Tp, _Context>
> - explicit
> + _GLIBCXX26_CONSTEXPR explicit
> basic_format_arg(_Tp& __v) noexcept
> {
> using _Td = _Normalize<_Tp>;
> @@ -4521,15 +4577,15 @@ namespace __format
> }
>
> template<typename _Ctx, typename... _Argz>
> - friend auto
> + friend _GLIBCXX26_CONSTEXPR auto
> make_format_args(_Argz&...) noexcept;
>
> template<typename _Visitor, typename _Ctx>
> - friend decltype(auto)
> + friend _GLIBCXX26_CONSTEXPR decltype(auto)
> visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
>
> template<typename _Visitor, typename _Ctx>
> - friend decltype(auto)
> + friend _GLIBCXX26_CONSTEXPR decltype(auto)
> __format::__visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
>
> template<typename _Ch, typename _Tp>
> @@ -4537,7 +4593,7 @@ namespace __format
> __format::__to_arg_t_enum() noexcept;
>
> template<typename _Visitor>
> - decltype(auto)
> + _GLIBCXX26_CONSTEXPR decltype(auto)
> _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
> {
> using namespace __format;
> @@ -4612,7 +4668,7 @@ namespace __format
> }
>
> template<typename _Visitor>
> - decltype(auto)
> + _GLIBCXX26_CONSTEXPR decltype(auto)
> _M_visit_user(_Visitor&& __vis, __format::_Arg_t __type)
> {
> return _M_visit([&__vis]<typename _Tp>(_Tp& __val) ->
> decltype(auto)
> @@ -4636,7 +4692,7 @@ namespace __format
>
> template<typename _Visitor, typename _Context>
> _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
> - inline decltype(auto)
> + inline _GLIBCXX26_CONSTEXPR decltype(auto)
> visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
> {
> return __arg._M_visit_user(std::forward<_Visitor>(__vis),
> __arg._M_type);
> @@ -4646,7 +4702,7 @@ namespace __format
> namespace __format
> {
> template<typename _Visitor, typename _Ctx>
> - inline decltype(auto)
> + inline _GLIBCXX26_CONSTEXPR decltype(auto)
> __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg)
> {
> return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type);
> @@ -4655,7 +4711,7 @@ namespace __format
> struct _WidthPrecVisitor
> {
> template<typename _Tp>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> operator()(_Tp& __arg) const
> {
> if constexpr (is_same_v<_Tp, monostate>)
> @@ -4681,7 +4737,7 @@ namespace __format
> #pragma GCC diagnostic push
> #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
> template<typename _Context>
> - inline size_t
> + inline _GLIBCXX26_CONSTEXPR size_t
> __int_from_arg(const basic_format_arg<_Context>& __arg)
> { return __format::__visit_format_arg(_WidthPrecVisitor(), __arg); }
>
> @@ -4729,11 +4785,11 @@ namespace __format
> const _Format_arg* _M_args; // Active when _M_packed_size ==
> 0
> };
>
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> _M_size() const noexcept
> { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
>
> - typename __format::_Arg_t
> + _GLIBCXX26_CONSTEXPR typename __format::_Arg_t
> _M_type(size_t __i) const noexcept
> {
> uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
> @@ -4741,7 +4797,7 @@ namespace __format
> }
>
> template<typename _Ctx, typename... _Args>
> - friend auto
> + friend _GLIBCXX26_CONSTEXPR auto
> make_format_args(_Args&...) noexcept;
>
> // An array of _Arg_t enums corresponding to _Args...
> @@ -4752,10 +4808,11 @@ namespace __format
>
> public:
> template<typename... _Args>
> + _GLIBCXX26_CONSTEXPR
> basic_format_args(const _Store<_Args...>& __store) noexcept;
>
> [[nodiscard,__gnu__::__always_inline__]]
> - basic_format_arg<_Context>
> + _GLIBCXX26_CONSTEXPR basic_format_arg<_Context>
> get(size_t __i) const noexcept
> {
> basic_format_arg<_Context> __arg;
> @@ -4777,7 +4834,7 @@ namespace __format
> -> basic_format_args<_Context>;
>
> template<typename _Context, typename... _Args>
> - auto
> + _GLIBCXX26_CONSTEXPR auto
> make_format_args(_Args&... __fmt_args) noexcept;
>
> // An array of type-erased formatting arguments.
> @@ -4787,7 +4844,7 @@ namespace __format
> friend std::basic_format_args<_Context>;
>
> template<typename _Ctx, typename... _Argz>
> - friend auto std::
> + friend _GLIBCXX26_CONSTEXPR auto std::
> #if _GLIBCXX_INLINE_VERSION
> __8:: // Needed for PR c++/59256
> #endif
> @@ -4806,7 +4863,7 @@ namespace __format
> _Element_t _M_args[sizeof...(_Args)];
>
> template<typename _Tp>
> - static _Element_t
> + static _GLIBCXX26_CONSTEXPR _Element_t
> _S_make_elt(_Tp& __v)
> {
> using _Tq = remove_const_t<_Tp>;
> @@ -4832,6 +4889,7 @@ namespace __format
> template<typename... _Tp>
> requires (sizeof...(_Tp) == sizeof...(_Args))
> [[__gnu__::__always_inline__]]
> + _GLIBCXX26_CONSTEXPR
> _Arg_store(_Tp&... __a) noexcept
> : _M_args{_S_make_elt(__a)...}
> { }
> @@ -4843,7 +4901,7 @@ namespace __format
>
> template<typename _Context>
> template<typename... _Args>
> - inline
> + inline _GLIBCXX26_CONSTEXPR
> basic_format_args<_Context>::
> basic_format_args(const _Store<_Args...>& __store) noexcept
> {
> @@ -4877,7 +4935,7 @@ namespace __format
> /// Capture formatting arguments for use by `std::vformat`.
> template<typename _Context = format_context, typename... _Args>
> [[nodiscard,__gnu__::__always_inline__]]
> - inline auto
> + inline _GLIBCXX26_CONSTEXPR auto
> make_format_args(_Args&... __fmt_args) noexcept
> {
> using _Fmt_arg = basic_format_arg<_Context>;
> @@ -4890,7 +4948,7 @@ namespace __format
> /// Capture formatting arguments for use by `std::vformat` (for wide
> output).
> template<typename... _Args>
> [[nodiscard,__gnu__::__always_inline__]]
> - inline auto
> + inline _GLIBCXX26_CONSTEXPR auto
> make_wformat_args(_Args&... __args) noexcept
> { return std::make_format_args<wformat_context>(__args...); }
> #endif
> @@ -4899,13 +4957,13 @@ namespace __format
> namespace __format
> {
> template<typename _Out, typename _CharT, typename _Context>
> - _Out
> + _GLIBCXX26_CONSTEXPR _Out
> __do_vformat_to(_Out, basic_string_view<_CharT>,
> const basic_format_args<_Context>&,
> const locale* = nullptr);
>
> template<typename _Out, typename _CharT>
> - format_to_n_result<_Out>
> + _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
> __do_vformat_to_n(_Out, iter_difference_t<_Out>,
> basic_string_view<_CharT>,
> const type_identity_t<
> @@ -4939,11 +4997,13 @@ namespace __format
> _Out _M_out;
> __format::_Optional_locale _M_loc;
>
> + _GLIBCXX26_CONSTEXPR
> basic_format_context(basic_format_args<basic_format_context> __args,
> _Out __out)
> : _M_args(__args), _M_out(std::move(__out))
> { }
>
> + _GLIBCXX26_CONSTEXPR
> basic_format_context(basic_format_args<basic_format_context> __args,
> _Out __out, const std::locale& __loc)
> : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
> @@ -4956,7 +5016,7 @@ namespace __format
> basic_format_context& operator=(const basic_format_context&) =
> delete;
>
> template<typename _Out2, typename _CharT2, typename _Context2>
> - friend _Out2
> + friend _GLIBCXX26_CONSTEXPR _Out2
> __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
> const basic_format_args<_Context2>&,
> const locale*);
> @@ -4972,7 +5032,7 @@ namespace __format
> using formatter_type = formatter<_Tp, _CharT>;
>
> [[nodiscard]]
> - basic_format_arg<basic_format_context>
> + _GLIBCXX26_CONSTEXPR basic_format_arg<basic_format_context>
> arg(size_t __id) const noexcept
> { return _M_args.get(__id); }
>
> @@ -4980,9 +5040,11 @@ namespace __format
> std::locale locale() { return _M_loc.value(); }
>
> [[nodiscard]]
> - iterator out() { return std::move(_M_out); }
> + _GLIBCXX26_CONSTEXPR iterator
> + out() { return std::move(_M_out); }
>
> - void advance_to(iterator __it) { _M_out = std::move(__it); }
> + _GLIBCXX26_CONSTEXPR void
> + advance_to(iterator __it) { _M_out = std::move(__it); }
> };
>
>
> @@ -5121,6 +5183,7 @@ namespace __format
> class _Formatting_scanner : public _Scanner<_CharT>
> {
> public:
> + _GLIBCXX26_CONSTEXPR
> _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
> basic_string_view<_CharT> __str)
> : _Scanner<_CharT>(__str), _M_fc(__fc)
> @@ -5228,7 +5291,7 @@ namespace __format
> };
>
> template<typename _Out, typename _CharT, typename _Context>
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
> const basic_format_args<_Context>& __args,
> const locale* __loc)
> @@ -5248,7 +5311,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;
> }
> @@ -5286,7 +5349,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;
> }
> @@ -5304,14 +5367,16 @@ namespace __format
> __scanner._M_scan();
> return __out;
> }
> - else if constexpr (__contiguous_char_iter<_CharT, _Out>)
> - {
> - _Ptr_sink<_CharT> __sink(__out);
> - __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> - return std::move(__sink)._M_finish(__out).out;
> - }
> else
> {
> + if constexpr (__contiguous_char_iter<_CharT, _Out>)
> + if (!std::is_constant_evaluated())
> + {
> + _Ptr_sink<_CharT> __sink(__out);
> + __format::__do_vformat_to(__sink.out(), __fmt, __args,
> __loc);
> + return std::move(__sink)._M_finish(__out).out;
> + }
> +
> _Iter_sink<_CharT, _Out> __sink(std::move(__out));
> __format::__do_vformat_to(__sink.out(), __fmt, __args, __loc);
> return std::move(__sink)._M_finish().out;
> @@ -5319,7 +5384,7 @@ namespace __format
> }
>
> template<typename _Out, typename _CharT>
> - format_to_n_result<_Out>
> + _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
> __do_vformat_to_n(_Out __out, iter_difference_t<_Out> __n,
> basic_string_view<_CharT> __fmt,
> const type_identity_t<
> @@ -5359,7 +5424,11 @@ namespace __format
> if constexpr (sizeof...(_Ts) != 0)
> {
> using _Parse_ctx = __format::_Scanner<_CharT>::_Parse_context;
> - auto __arg = static_cast<_Parse_ctx*>(this)->_M_types[__id];
> + auto* __args = static_cast<_Parse_ctx*>(this)->_M_types;
> + // formatting scanner
> + if (!__args)
> + return;
> + auto __arg = __args[__id];
> __format::_Arg_t __types[] = {
> __format::__to_arg_t_enum<_CharT, _Ts>()...
> };
> @@ -5377,7 +5446,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>...>
> @@ -5389,14 +5458,14 @@ namespace __format
>
> template<typename _Out> requires output_iterator<_Out, const char&>
> [[__gnu__::__always_inline__]]
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> vformat_to(_Out __out, string_view __fmt, format_args __args)
> { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
>
> #ifdef _GLIBCXX_USE_WCHAR_T
> template<typename _Out> requires output_iterator<_Out, const wchar_t&>
> [[__gnu__::__always_inline__]]
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
> { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
> #endif
> @@ -5422,7 +5491,7 @@ namespace __format
> #endif
>
> [[nodiscard]]
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> vformat(string_view __fmt, format_args __args)
> {
> __format::_Str_sink<char> __buf;
> @@ -5432,7 +5501,7 @@ namespace __format
>
> #ifdef _GLIBCXX_USE_WCHAR_T
> [[nodiscard]]
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> vformat(wstring_view __fmt, wformat_args __args)
> {
> __format::_Str_sink<wchar_t> __buf;
> @@ -5463,14 +5532,14 @@ namespace __format
>
> template<typename... _Args>
> [[nodiscard]]
> - inline string
> + inline _GLIBCXX26_CONSTEXPR string
> format(format_string<_Args...> __fmt, _Args&&... __args)
> { return std::vformat(__fmt.get(), std::make_format_args(__args...));
> }
>
> #ifdef _GLIBCXX_USE_WCHAR_T
> template<typename... _Args>
> [[nodiscard]]
> - inline wstring
> + inline _GLIBCXX26_CONSTEXPR wstring
> format(wformat_string<_Args...> __fmt, _Args&&... __args)
> { return std::vformat(__fmt.get(),
> std::make_wformat_args(__args...)); }
> #endif
> @@ -5499,7 +5568,7 @@ namespace __format
>
> template<typename _Out, typename... _Args>
> requires output_iterator<_Out, const char&>
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> format_to(_Out __out, format_string<_Args...> __fmt, _Args&&...
> __args)
> {
> return std::vformat_to(std::move(__out), __fmt.get(),
> @@ -5509,7 +5578,7 @@ namespace __format
> #ifdef _GLIBCXX_USE_WCHAR_T
> template<typename _Out, typename... _Args>
> requires output_iterator<_Out, const wchar_t&>
> - inline _Out
> + inline _GLIBCXX26_CONSTEXPR _Out
> format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&...
> __args)
> {
> return std::vformat_to(std::move(__out), __fmt.get(),
> @@ -5541,7 +5610,7 @@ namespace __format
>
> template<typename _Out, typename... _Args>
> requires output_iterator<_Out, const char&>
> - inline format_to_n_result<_Out>
> + inline _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
> format_to_n(_Out __out, iter_difference_t<_Out> __n,
> format_string<_Args...> __fmt, _Args&&... __args)
> {
> @@ -5553,7 +5622,7 @@ namespace __format
> #ifdef _GLIBCXX_USE_WCHAR_T
> template<typename _Out, typename... _Args>
> requires output_iterator<_Out, const wchar_t&>
> - inline format_to_n_result<_Out>
> + inline _GLIBCXX26_CONSTEXPR format_to_n_result<_Out>
> format_to_n(_Out __out, iter_difference_t<_Out> __n,
> wformat_string<_Args...> __fmt, _Args&&... __args)
> {
> @@ -5595,10 +5664,11 @@ namespace __format
> class _Counting_sink final : public _Ptr_sink<_CharT>
> {
> public:
> + _GLIBCXX26_CONSTEXPR
> _Counting_sink() : _Ptr_sink<_CharT>(nullptr, 0) { }
>
> [[__gnu__::__always_inline__]]
> - size_t
> + _GLIBCXX26_CONSTEXPR size_t
> count() const
> { return this->_M_count + this->_M_used().size(); }
> };
> @@ -5633,7 +5703,7 @@ namespace __format
>
> template<typename... _Args>
> [[nodiscard]]
> - inline size_t
> + inline _GLIBCXX26_CONSTEXPR size_t
> formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
> {
> __format::_Counting_sink<char> __buf;
> @@ -5645,7 +5715,7 @@ namespace __format
> #ifdef _GLIBCXX_USE_WCHAR_T
> template<typename... _Args>
> [[nodiscard]]
> - inline size_t
> + inline _GLIBCXX26_CONSTEXPR size_t
> formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
> {
> __format::_Counting_sink<wchar_t> __buf;
> @@ -5716,6 +5786,7 @@ namespace __format
> namespace __format
> {
> template<typename _CharT, typename _Out, typename _Callback>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> __format_padded(basic_format_context<_Out, _CharT>& __fc,
> const _Spec<_CharT>& __spec,
> @@ -5735,14 +5806,16 @@ namespace __format
>
> struct _Restore_out
> {
> + _GLIBCXX26_CONSTEXPR
> _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>&
> __fc)
> : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
> { }
>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_disarm()
> { _M_ctx = nullptr; }
>
> + _GLIBCXX26_CONSTEXPR
> ~_Restore_out()
> {
> if (_M_ctx)
> @@ -5776,7 +5849,7 @@ namespace __format
> }
>
> template<typename _Out>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_format(__maybe_const<_Tp, _CharT>& __elem,
> basic_format_context<_Out, _CharT>& __fc,
> basic_string_view<_CharT> __sep) const
> @@ -5874,12 +5947,14 @@ namespace __format
>
> protected:
> template<typename _Tuple, typename _Out, size_t... _Ids>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> _M_format(_Tuple& __tuple, index_sequence<_Ids...>,
> basic_format_context<_Out, _CharT>& __fc) const
> { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); }
>
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -5909,7 +5984,7 @@ namespace __format
> }
>
> template<typename _Out>
> - void
> + _GLIBCXX26_CONSTEXPR void
> _M_format(__maybe_const<_Tps, _CharT>&... __elems,
> basic_format_context<_Out, _CharT>& __fc,
> _String_view __sep) const
> @@ -5925,7 +6000,7 @@ namespace __format
> };
>
> template<size_t... _Ids>
> - static auto
> + static _GLIBCXX26_CONSTEXPR auto
> _S_create_storage(index_sequence<_Ids...>)
> -> __formatters_storage<_Ids...>;
> using _Formatters
> @@ -5961,6 +6036,7 @@ namespace __format
> // We deviate from standard, that declares this as template
> accepting
> // unconstrained FormatContext type, which seems unimplementable.
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(__maybe_const_pair& __p,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -5988,6 +6064,7 @@ namespace __format
> // We deviate from standard, that declares this as template
> accepting
> // unconstrained FormatContext type, which seems unimplementable.
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(__maybe_const_tuple& __t,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -6151,6 +6228,7 @@ namespace __format
> template<ranges::input_range _Rg, typename _Out>
> requires formattable<ranges::range_reference_t<_Rg>, _CharT> &&
> same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
> _Tp>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
> {
> @@ -6163,6 +6241,7 @@ namespace __format
>
> private:
> template<ranges::input_range _Rg, typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc)
> const
> {
> @@ -6180,6 +6259,7 @@ namespace __format
>
>
> template<ranges::input_range _Rg, typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> _M_format_elems(_Rg& __rg,
> basic_format_context<_Out, _CharT>& __fc) const
> @@ -6279,6 +6359,7 @@ namespace __format
> // We deviate from standard, that declares this as template
> accepting
> // unconstrained FormatContext type, which seems unimplementable.
> template<typename _Out>
> + _GLIBCXX26_CONSTEXPR
> typename basic_format_context<_Out, _CharT>::iterator
> format(__format::__maybe_const_range<_Rg, _CharT>& __rg,
> basic_format_context<_Out, _CharT>& __fc) const
> diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc
> new file mode 100644
> index 00000000000..b789e87e6a1
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_constexpr.cc
> @@ -0,0 +1,63 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <string>
> +#include <type_traits>
> +#include <testsuite_hooks.h>
> +
> +template<typename T>
> +constexpr void
> +test()
> +{
> + using namespace std;
> + string res;
> + T value;
> +
> + value = 0;
> + res = to_string(value);
> + VERIFY( res == "0" );
> +
> + value = 1;
> + res = to_string(value);
> + VERIFY( res == "1" );
> +
> + value = 10;
> + res = to_string(value);
> + VERIFY( res == "10" );
> +
> + value = 3000;
> + res = to_string(value);
> + VERIFY( res == "3000" );
> +
> + value = 32767;
> + res = to_string(value);
> + VERIFY( res == "32767" );
> +
> + if (is_unsigned_v<T>)
> + return;
> +
> + value = -1;
> + res = to_string(value);
> + VERIFY( res == "-1" );
> +
> + value = -40;
> + res = to_string(value);
> + VERIFY( res == "-40" );
> +
> + value = -32768;
> + res = to_string(value);
> + VERIFY( res == "-32768" );
> +}
> +
> +constexpr bool
> +test_all()
> +{
> + test<int>();
> + test<unsigned int>();
> + test<long>();
> + test<unsigned long>();
> + test<long long>();
> + test<unsigned long long>();
> + return true;
> +}
> +
> +static_assert(test_all());
> diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc
> new file mode 100644
> index 00000000000..faf54be7d22
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_constexpr.cc
> @@ -0,0 +1,63 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <string>
> +#include <type_traits>
> +#include <testsuite_hooks.h>
> +
> +template<typename T>
> +constexpr void
> +test()
> +{
> + using namespace std;
> + wstring res;
> + T value;
> +
> + value = 0;
> + res = to_wstring(value);
> + VERIFY( res == L"0" );
> +
> + value = 1;
> + res = to_wstring(value);
> + VERIFY( res == L"1" );
> +
> + value = 10;
> + res = to_wstring(value);
> + VERIFY( res == L"10" );
> +
> + value = 3000;
> + res = to_wstring(value);
> + VERIFY( res == L"3000" );
> +
> + value = 32767;
> + res = to_wstring(value);
> + VERIFY( res == L"32767" );
> +
> + if (is_unsigned_v<T>)
> + return;
> +
> + value = -1;
> + res = to_wstring(value);
> + VERIFY( res == L"-1" );
> +
> + value = -40;
> + res = to_wstring(value);
> + VERIFY( res == L"-40" );
> +
> + value = -32768;
> + res = to_wstring(value);
> + VERIFY( res == L"-32768" );
> +}
> +
> +constexpr bool
> +test_all()
> +{
> + test<int>();
> + test<unsigned int>();
> + test<long>();
> + test<unsigned long>();
> + test<long long>();
> + test<unsigned long long>();
> + return true;
> +}
> +
> +static_assert(test_all());
> 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..943a57cc5f8
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/format/constexpr.cc
> @@ -0,0 +1,156 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <format>
> +#include <string>
> +#include <string_view>
> +#include <tuple>
> +#include <vector>
> +#include <testsuite_hooks.h>
> +
> +// 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());
> diff --git a/libstdc++-v3/testsuite/std/format/debug.cc
> b/libstdc++-v3/testsuite/std/format/debug.cc
> index 43e930c579e..1e17ff17ef5 100644
> --- a/libstdc++-v3/testsuite/std/format/debug.cc
> +++ b/libstdc++-v3/testsuite/std/format/debug.cc
> @@ -1,26 +1,32 @@
> -// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE
> -DUNICODE_ENC" { target le } }
> -// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE
> -DUNICODE_ENC" { target be } }
> +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE
> -DUNICODE_ENC -fconstexpr-ops-limit=500000000" { target le } }
> +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE
> -DUNICODE_ENC -fconstexpr-ops-limit=500000000" { target be } }
> // { dg-do run { target c++23 } }
> // { dg-require-effective-target 4byte_wchar_t }
> // { dg-add-options no_pch }
> // { dg-timeout-factor 2 }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <format>
> #include <testsuite_hooks.h>
>
> -std::string
> +constexpr26 std::string
> fdebug(char t)
> { return std::format("{:?}", t); }
>
> -std::wstring
> +constexpr26 std::wstring
> fdebug(wchar_t t)
> { return std::format(L"{:?}", t); }
>
> -std::string
> +constexpr26 std::string
> fdebug(std::string_view t)
> { return std::format("{:?}", t); }
>
> -std::wstring
> +constexpr26 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
> +constexpr26 void
> test_basic_escapes()
> {
> std::basic_string<CharT> res;
> @@ -72,7 +78,7 @@ test_basic_escapes()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_ascii_escapes()
> {
> std::basic_string<CharT> res;
> @@ -89,7 +95,7 @@ test_ascii_escapes()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_extended_ascii()
> {
> std::basic_string<CharT> res;
> @@ -117,7 +123,7 @@ test_extended_ascii()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_unicode_escapes()
> {
> #if UNICODE_ENC
> @@ -166,7 +172,7 @@ test_unicode_escapes()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_grapheme_extend()
> {
> #if UNICODE_ENC
> @@ -192,7 +198,7 @@ test_grapheme_extend()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_replacement_char()
> {
> #if UNICODE_ENC
> @@ -206,7 +212,7 @@ test_replacement_char()
> #endif // UNICODE_ENC
> }
>
> -void
> +constexpr26 void
> test_ill_formed_utf8_seq()
> {
> #if UNICODE_ENC
> @@ -244,7 +250,7 @@ test_ill_formed_utf8_seq()
> #endif // UNICODE_ENC
> }
>
> -void
> +constexpr26 void
> test_ill_formed_utf32()
> {
> #if UNICODE_ENC
> @@ -269,7 +275,7 @@ test_ill_formed_utf32()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_fill()
> {
> std::basic_string<CharT> res;
> @@ -315,7 +321,7 @@ test_fill()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_prec()
> {
> std::basic_string<CharT> res;
> @@ -341,7 +347,8 @@ test_prec()
> #endif // UNICODE_ENC
> }
>
> -bool strip_quote(std::string_view& v)
> +constexpr26 bool
> +strip_quote(std::string_view& v)
> {
> if (!v.starts_with('"'))
> return false;
> @@ -349,7 +356,8 @@ bool strip_quote(std::string_view& v)
> return true;
> }
>
> -bool strip_quotes(std::string_view& v)
> +constexpr26 bool
> +strip_quotes(std::string_view& v)
> {
> if (!v.starts_with('"') || !v.ends_with('"'))
> return false;
> @@ -358,7 +366,8 @@ bool strip_quotes(std::string_view& v)
> return true;
> }
>
> -bool strip_prefix(std::string_view& v, size_t n, char c)
> +constexpr26 bool
> +strip_prefix(std::string_view& v, size_t n, char c)
> {
> size_t pos = v.find_first_not_of(c);
> if (pos == std::string_view::npos)
> @@ -369,7 +378,8 @@ bool strip_prefix(std::string_view& v, size_t n, char
> c)
> return true;
> }
>
> -void test_padding()
> +constexpr26 void
> +test_padding()
> {
> std::string res;
> std::string_view resv;
> @@ -719,7 +729,8 @@ void test_padding()
> #endif // UNICODE_ENC
> }
>
> -void test_char_as_wchar()
> +constexpr26 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
> + constexpr26 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
> +constexpr26 void
> test_formatter_str()
> {
> CharT buf[]{ 'a', 'b', 'c', 0 };
> @@ -770,7 +782,7 @@ test_formatter_str()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_formatter_arr()
> {
> std::basic_string<CharT> res;
> @@ -786,7 +798,7 @@ test_formatter_arr()
> }
>
> template<typename CharT, typename SrcT>
> -void
> +constexpr26 void
> test_formatter_char()
> {
> DebugWrapper<SrcT> in{ 'a' };
> @@ -795,7 +807,7 @@ test_formatter_char()
> }
>
> template<typename CharT>
> -void
> +constexpr26 void
> test_formatters()
> {
> test_formatter_char<CharT, CharT>();
> @@ -806,7 +818,7 @@ test_formatters()
> test_formatter_arr<CharT>();
> }
>
> -void
> +constexpr26 void
> test_formatters_c()
> {
> test_formatters<char>();
> @@ -814,7 +826,8 @@ test_formatters_c()
> test_formatter_char<wchar_t, char>();
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test_basic_escapes<char>();
> test_basic_escapes<wchar_t>();
> @@ -840,4 +853,15 @@ int main()
> test_padding();
>
> test_formatters_c();
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc
> b/libstdc++-v3/testsuite/std/format/functions/format.cc
> index d342114083e..12253242833 100644
> --- a/libstdc++-v3/testsuite/std/format/functions/format.cc
> +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
> @@ -3,6 +3,12 @@
> // { dg-add-options no_pch }
> // { dg-additional-options "-DUNICODE" { target 4byte_wchar_t } }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <format>
>
> #ifndef __cpp_lib_format
> @@ -41,7 +47,7 @@
> #include <cstdio>
> #include <testsuite_hooks.h>
>
> -void
> +constexpr26 void
> test_no_args()
> {
> std::string s;
> @@ -55,7 +61,7 @@ test_no_args()
> VERIFY( s == "128bpm }" );
> }
>
> -void
> +constexpr26 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
> +constexpr26 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
> +constexpr26 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
> +constexpr26 void
> test_width()
> {
> std::string s;
> @@ -317,7 +330,7 @@ test_width()
> }
> }
>
> -void
> +constexpr26 void
> test_char()
> {
> std::string s;
> @@ -347,7 +360,7 @@ test_char()
> VERIFY( s == "11110000 11110000 240 360 f0 F0" );
> }
>
> -void
> +constexpr26 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
> +constexpr26 void
> test_minmax()
> {
> auto check = []<typename T, typename U = std::make_unsigned_t<T>>(T, U
> = 0) {
> @@ -422,7 +441,7 @@ test_minmax()
> #endif
> }
>
> -void
> +constexpr26 void
> test_p1652r1() // printf corner cases in std::format
> {
> std::string s;
> @@ -436,27 +455,33 @@ test_p1652r1() // printf corner cases in std::format
> s = std::format("{:c}", c);
> VERIFY( s == "A" );
>
> - // Problem 3: "-000nan" is not a floating point value
> - double nan = std::numeric_limits<double>::quiet_NaN();
> - try {
> - s = std::vformat("{:0=6}", std::make_format_args(nan));
> - VERIFY( false );
> - } catch (const std::format_error&) {
> - }
> -
> - s = std::format("{:06}", nan);
> - VERIFY( s == " nan" );
> + if (!std::is_constant_evaluated())
> + {
> + // Problem 3: "-000nan" is not a floating point value
> + double nan = std::numeric_limits<double>::quiet_NaN();
> + try {
> + s = std::vformat("{:0=6}", std::make_format_args(nan));
> + VERIFY( false );
> + } catch (const std::format_error&) {
> + }
> +
> + s = std::format("{:06}", nan);
> + VERIFY( s == " nan" );
> + }
>
> // Problem 4: bool needs a type format specifier
> s = std::format("{:s}", true);
> VERIFY( s == "true" );
>
> - // Problem 5: double does not roundtrip float
> - s = std::format("{}", 3.31f);
> - VERIFY( s == "3.31" );
> + if (!std::is_constant_evaluated())
> + {
> + // Problem 5: double does not roundtrip float
> + s = std::format("{}", 3.31f);
> + VERIFY( s == "3.31" );
> + }
> }
>
> -void
> +constexpr26 void
> test_pointer()
> {
> void* p = nullptr;
> @@ -477,28 +502,31 @@ test_pointer()
> s = std::format("{:o<4},{:o>5},{:o^7}", p, pc, nullptr); //
> fill+align+width
> VERIFY( s == "0x0o,oo0x0,oo0x0oo" );
>
> - pc = p = &s;
> - str_int = std::format("{:#x}", reinterpret_cast<std::uintptr_t>(p));
> - s = std::format("{} {} {}", p, pc, nullptr);
> - VERIFY( s == (str_int + ' ' + str_int + " 0x0") );
> - str_int = std::format("{:#20x}", reinterpret_cast<std::uintptr_t>(p));
> - s = std::format("{:20} {:20p}", p, pc);
> - VERIFY( s == (str_int + ' ' + str_int) );
> + if (!std::is_constant_evaluated())
> + {
> + pc = p = &s;
> + str_int = std::format("{:#x}", reinterpret_cast<std::uintptr_t>(p));
> + s = std::format("{} {} {}", p, pc, nullptr);
> + VERIFY( s == (str_int + ' ' + str_int + " 0x0") );
> + str_int = std::format("{:#20x}",
> reinterpret_cast<std::uintptr_t>(p));
> + s = std::format("{:20} {:20p}", p, pc);
> + VERIFY( s == (str_int + ' ' + str_int) );
>
> #if __cpp_lib_format >= 202304L
> - // P2510R3 Formatting pointers
> - s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0,
> nullptr);
> - VERIFY( s == "0x0000 0X00000 0x000000" );
> - str_int = std::format("{:#016x}", reinterpret_cast<std::uintptr_t>(p));
> - s = std::format("{:016} {:016}", p, pc);
> - VERIFY( s == (str_int + ' ' + str_int) );
> - str_int = std::format("{:#016X}", reinterpret_cast<std::uintptr_t>(p));
> - s = std::format("{:016P} {:016P}", p, pc);
> - VERIFY( s == (str_int + ' ' + str_int) );
> + // P2510R3 Formatting pointers
> + s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0,
> nullptr);
> + VERIFY( s == "0x0000 0X00000 0x000000" );
> + str_int = std::format("{:#016x}",
> reinterpret_cast<std::uintptr_t>(p));
> + s = std::format("{:016} {:016}", p, pc);
> + VERIFY( s == (str_int + ' ' + str_int) );
> + str_int = std::format("{:#016X}",
> reinterpret_cast<std::uintptr_t>(p));
> + s = std::format("{:016P} {:016P}", p, pc);
> + VERIFY( s == (str_int + ' ' + str_int) );
> #endif
> + }
> }
>
> -void
> +constexpr26 void
> test_bool()
> {
> std::string s;
> @@ -519,7 +547,7 @@ test_bool()
> VERIFY( s == "0 0x1 0X0" );
> }
>
> -void
> +constexpr26 void
> test_unicode()
> {
> #ifdef UNICODE
> @@ -579,13 +607,13 @@ test_unicode()
> #endif
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test_no_args();
> test_unescaped();
> test_std_examples();
> test_alternate_forms();
> - test_locale();
> test_width();
> test_char();
> test_wchar();
> @@ -594,4 +622,21 @@ int main()
> test_pointer();
> test_bool();
> test_unicode();
> +
> + if (!std::is_constant_evaluated())
> + {
> + test_infnan();
> + test_locale();
> + }
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> index 94e6262bc66..5ad64ae4061 100644
> --- a/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> +++ b/libstdc++-v3/testsuite/std/format/functions/format_to.cc
> @@ -1,5 +1,11 @@
> // { dg-do run { target c++20 } }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <format>
> #include <locale>
> #include <vector>
> @@ -11,17 +17,20 @@ struct punct : std::numpunct<char>
> std::string do_grouping() const override { return "\2"; }
> };
>
> -void
> +constexpr26 void
> test()
> {
> char buf[32] = { };
> auto out = std::format_to(buf, "test");
> VERIFY( out == buf+4 );
>
> - std::locale loc({}, new punct);
> - auto out2 = std::format_to(buf, loc, "{:Ld}", 12345);
> - VERIFY( out2 == buf+7 );
> - VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" );
> + if (!std::is_constant_evaluated())
> + {
> + std::locale loc({}, new punct);
> + auto out2 = std::format_to(buf, loc, "{:Ld}", 12345);
> + VERIFY( out2 == buf+7 );
> + VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" );
> + }
> }
>
> struct wpunct : std::numpunct<wchar_t>
> @@ -29,17 +38,20 @@ struct wpunct : std::numpunct<wchar_t>
> std::string do_grouping() const override { return "\2"; }
> };
>
> -void
> +constexpr26 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
> +constexpr26 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
> +constexpr26 void
> test_pr110917()
> {
> // PR libstdc++/110917
> @@ -90,10 +102,22 @@ test_pr110917()
> VERIFY( ! std::memcmp(buf, "abc 123", 7) );
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test();
> test_wchar();
> test_move_only();
> test_pr110917();
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/functions/size.cc
> b/libstdc++-v3/testsuite/std/format/functions/size.cc
> index 1ece4108d85..78c5ccc778a 100644
> --- a/libstdc++-v3/testsuite/std/format/functions/size.cc
> +++ b/libstdc++-v3/testsuite/std/format/functions/size.cc
> @@ -1,10 +1,16 @@
> // { dg-do run { target c++20 } }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <format>
> #include <string>
> #include <testsuite_hooks.h>
>
> -void
> +constexpr26 void
> test()
> {
> auto n = std::formatted_size("");
> @@ -24,7 +30,7 @@ test()
> VERIFY( n == 5 );
> }
>
> -void
> +constexpr26 void
> test_wchar()
> {
> auto n = std::formatted_size(L"");
> @@ -44,8 +50,19 @@ test_wchar()
> VERIFY( n == 5 );
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test();
> test_wchar();
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> index 1450fbaebc5..48795440d13 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
> @@ -1,5 +1,11 @@
> // { dg-do run { target c++23 } }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <deque>
> #include <flat_map>
> #include <flat_set>
> @@ -64,7 +70,8 @@ struct CustFormat : std::vector<T>
> template<typename T, std::range_format rf>
> constexpr auto std::format_kind<CustFormat<T, rf>> = rf;
>
> -void test_override()
> +constexpr26 bool
> +test_override()
> {
> CustFormat<int, std::range_format::disabled> disabledf;
> static_assert( !std::formattable<decltype(disabledf), char> );
> @@ -88,8 +95,14 @@ void test_override()
> VERIFY( std::format("{}", debugf) == R"("abcd")" );
> // Support precision as string do
> VERIFY( std::format("{:.3}", debugf) == R"("ab)" );
> +
> + return true;
> }
>
> +#if __cplusplus >= 202400L
> +static_assert(test_override());
> +#endif
> +
> int main()
> {
> test_override();
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> index a50c5b1033f..d732cdf66ad 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
> @@ -1,5 +1,11 @@
> // { dg-do run { target c++23 } }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <flat_map>
> #include <format>
> #include <testsuite_hooks.h>
> @@ -32,7 +38,7 @@ struct std::formatter<MyVector<T, Formatter>, CharT>
> { return _formatter.parse(pc); }
>
> template<typename Out>
> - typename std::basic_format_context<Out, CharT>::iterator
> + constexpr26 std::basic_format_context<Out, CharT>::iterator
> format(const MyVector<T, Formatter>& mv,
> std::basic_format_context<Out, CharT>& fc) const
> { return _formatter.format(mv, fc); }
> @@ -42,7 +48,7 @@ private:
> };
>
> template<typename CharT, template<typename, typename> class Formatter>
> -void
> +constexpr26 void
> test_default()
> {
> MyVector<int, Formatter> vec{1, 2, 3};
> @@ -94,7 +100,7 @@ test_default()
> }
>
> template<typename CharT, template<typename, typename> class Formatter>
> -void
> +constexpr26 void
> test_override()
> {
> MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
> @@ -115,7 +121,8 @@ test_override()
> }
>
> template<template<typename, typename> class Formatter>
> -void test_outputs()
> +constexpr26 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
> +constexpr26 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()
> +constexpr26 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()
> +constexpr26 void
> +test_nonblocking()
> {
> static_assert(!std::enable_nonlocking_formatter_optimization<
> Range<int>>);
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test_outputs<std::range_formatter>();
> test_outputs<VectorFormatter>();
> @@ -179,4 +189,15 @@ int main()
> test_nonblocking<std::span>();
> test_nonblocking<std::vector>();
> test_nonblocking<MyVector>();
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> index 7fb65f9c551..a3fd3df5099 100644
> --- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
> @@ -1,7 +1,13 @@
> // { dg-do run { target c++23 } }
> -// { dg-options "-fexec-charset=UTF-8" }
> +// { dg-options "-fexec-charset=UTF-8 -fconstexpr-ops-limit=5000000000" }
> // { dg-timeout-factor 2 }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <array>
> #include <format>
> #include <list>
> @@ -19,7 +25,7 @@
> static_assert(!std::formattable<std::vector<NotFormattable>, char>);
> static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>);
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const char* str, Args&&... args)
> {
> try {
> @@ -31,7 +37,7 @@ is_format_string_for(const char* str, Args&&... args)
> }
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const wchar_t* str, Args&&... args)
> {
> try {
> @@ -43,7 +49,8 @@ is_format_string_for(const wchar_t* str, Args&&... args)
> }
>
> template<typename Rg, typename CharT>
> -bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
> +constexpr26 bool
> +is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
> {
> using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
> std::range_formatter<V, CharT> fmt;
> @@ -56,7 +63,7 @@ bool is_range_formatter_spec_for(CharT const* spec, Rg&&
> rg)
> }
> }
>
> -void
> +constexpr26 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()
> +constexpr26 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()
> +constexpr26 void
> +test_output_cont()
> {
> test_output<char, Cont&, Cont>();
> test_output<wchar_t, Cont const&, Cont>();
> }
>
> template<typename View>
> -void test_output_view()
> +constexpr26 void
> +test_output_view()
> {
> test_output<char, View, int[3]>();
> test_output<wchar_t, View, int[3]>();
> }
>
> -void
> +constexpr26 void
> test_outputs()
> {
> using namespace __gnu_test;
> test_output_cont<std::vector<int>>();
> - test_output_cont<std::list<int>>();
> +
> + if (!std::is_constant_evaluated())
> + test_output_cont<std::list<int>>();
> +
> test_output_cont<std::array<int, 3>>();
>
> test_output_view<std::span<int>>();
> @@ -185,7 +198,7 @@ test_outputs()
> test_output_view<test_forward_range<const int>>();
> }
>
> -void
> +constexpr26 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)
> +constexpr26 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)
> +constexpr26 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)
> +constexpr26 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)
> +constexpr26 bool
> +strip_prefix(std::string_view& v, size_t n, char c)
> {
> size_t pos = v.find_first_not_of(c);
> if (pos == std::string_view::npos)
> @@ -241,7 +258,8 @@ bool strip_prefix(std::string_view& v, size_t n, char
> c)
> return true;
> }
>
> -void test_padding()
> +constexpr26 void
> +test_padding()
> {
> std::string res;
> std::string_view resv;
> @@ -323,10 +341,22 @@ void test_padding()
> VERIFY( check_elems(resv, false) );
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test_format_string();
> test_outputs();
> test_nested();
> test_padding();
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/runtime_format.cc
> b/libstdc++-v3/testsuite/std/format/runtime_format.cc
> index f2bfa5b434d..cb1c7a09bc8 100644
> --- a/libstdc++-v3/testsuite/std/format/runtime_format.cc
> +++ b/libstdc++-v3/testsuite/std/format/runtime_format.cc
> @@ -3,7 +3,7 @@
> #include <format>
> #include <testsuite_hooks.h>
>
> -void
> +constexpr void
> test_char()
> {
> std::string fmt = "{}";
> @@ -11,7 +11,7 @@ test_char()
> VERIFY( s == "123" );
> }
>
> -void
> +constexpr void
> test_wchar()
> {
> std::wstring fmt = L"{:#o}";
> @@ -19,7 +19,7 @@ test_wchar()
> VERIFY( s == L"0710" );
> }
>
> -void
> +constexpr void
> test_internal_api()
> {
> // Using _Runtime_format_string directly works even in C++20 mode.
> @@ -40,9 +40,18 @@ static_assert(
> !std::is_constructible_v<std::format_string<>,
> static_assert( !std::is_constructible_v<std::wformat_string<>,
>
> decltype(std::runtime_format(L""))&&> );
>
> -int main()
> +constexpr bool
> +test_all()
> {
> test_char();
> test_wchar();
> test_internal_api();
> + return true;
> +}
> +
> +static_assert(test_all());
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/string.cc
> b/libstdc++-v3/testsuite/std/format/string.cc
> index ee987a15ec3..684e54ad080 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" }
> +
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
>
> #include <format>
> #include <testsuite_hooks.h>
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const char* str, Args&&... args)
> {
> try {
> @@ -16,7 +23,7 @@ is_format_string_for(const char* str, Args&&... args)
> }
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const wchar_t* str, Args&&... args)
> {
> try {
> @@ -27,7 +34,7 @@ is_format_string_for(const wchar_t* str, Args&&... args)
> }
> }
>
> -void
> +constexpr26 void
> test_no_args()
> {
> VERIFY( is_format_string_for("") );
> @@ -42,7 +49,7 @@ test_no_args()
> VERIFY( ! is_format_string_for("{{{{{") );
> }
>
> -void
> +constexpr26 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
> +constexpr26 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
> +constexpr26 void
> test_pr110862()
> {
> try {
> @@ -178,7 +193,7 @@ test_pr110862()
> }
> }
>
> -void
> +constexpr26 void
> test_pr110974()
> {
> try {
> @@ -197,11 +212,23 @@ test_pr110974()
> }
> }
>
> -int main()
> +constexpr26 bool
> +test_all()
> {
> test_no_args();
> test_indexing();
> test_format_spec();
> test_pr110862();
> test_pr110974();
> +
> + return true;
> +}
> +
> +#if __cplusplus >= 202400L
> +static_assert(test_all());
> +#endif
> +
> +int main()
> +{
> + test_all();
> }
> diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc
> b/libstdc++-v3/testsuite/std/format/tuple.cc
> index eace82730f0..1bb1635d62b 100644
> --- a/libstdc++-v3/testsuite/std/format/tuple.cc
> +++ b/libstdc++-v3/testsuite/std/format/tuple.cc
> @@ -2,6 +2,12 @@
> // { dg-options "-fexec-charset=UTF-8" }
> // { dg-timeout-factor 2 }
>
> +#if __cplusplus >= 202400L
> +# define constexpr26 constexpr
> +#else
> +# define constexpr26
> +#endif
> +
> #include <format>
> #include <string>
> #include <testsuite_hooks.h>
> @@ -15,7 +21,7 @@ static_assert( !std::formattable<std::pair<int,
> NotFormattable>, char> );
> static_assert( !std::formattable<std::tuple<int, NotFormattable, int>,
> wchar_t> );
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const char* str, Args&&... args)
> {
> try {
> @@ -27,7 +33,7 @@ is_format_string_for(const char* str, Args&&... args)
> }
>
> template<typename... Args>
> -bool
> +constexpr26 bool
> is_format_string_for(const wchar_t* str, Args&&... args)
> {
> try {
> @@ -41,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
> +constexpr26 void
> test_format_string()
> {
> // invalid format stringss
> @@ -123,7 +129,8 @@ void test_multi()
> }
>
> template<typename CharT, typename Tuple>
> -void test_empty()
> +constexpr26 void
> +test_empty()
> {
> std::basic_string<CharT> res;
>
> @@ -142,7 +149,8 @@ void test_empty()
> }
>
> template<typename CharT, typename Pair>
> -void test_pair()
> +constexpr26 void
> +test_pair()
> {
> using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>;
> using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>;
> @@ -167,7 +175,8 @@ void test_pair()
> }
>
> template<typename CharT, template<typename, typename> class PairT>
> -void test_pair_e()
> +constexpr26 void
> +test_pair_e()
> {
> test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
> test_pair<CharT, PairT<int, const CharT*>>();
> @@ -196,7 +205,7 @@ struct std::formatter<MyPair<Pair>, CharT>
> { return _formatter.parse(pc); }
>
> template<typename Out>
> - typename std::basic_format_context<Out, CharT>::iterator
> + constexpr26 typename std::basic_format_context<Out, CharT>::iterator
> format(const MyPair<Pair>& mp,
> std::basic_format_context<Out, CharT>& fc) const
> { return _formatter.format(mp, fc); }
> @@ -206,7 +215,8 @@ private:
> };
>
> template<typename CharT, template<typename, typename> class PairT>
> -void test_custom()
> +constexpr26 void
> +test_custom()
> {
> std::basic_string<CharT> res;
> MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc"));
> @@ -228,9 +238,12 @@ void test_custom()
> }
>
> template<typename CharT>
> -void test_outputs()
> +constexpr26 void
> +test_outputs()
> {
> - test_multi<CharT>();
> + if (!std::is_constant_evaluated())
> + test_multi<CharT>();
> +
> test_empty<CharT, std::tuple<>>();
> test_pair_e<CharT, std::pair>();
> test_pair_e<CharT, std::tuple>();
> @@ -238,7 +251,8 @@ void test_outputs()
> test_custom<CharT, std::tuple>();
> }
>
> -void test_nested()
> +constexpr26 void
> +test_nested()
> {
> std::string res;
> std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1,
> "abc"}};
> @@ -251,7 +265,8 @@ void test_nested()
> VERIFY( res == R"((): (1, "abc"))" );
> }
>
> -bool strip_quote(std::string_view& v)
> +constexpr26 bool
> +strip_quote(std::string_view& v)
> {
> if (!v.starts_with('"'))
> return false;
> @@ -259,7 +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)
> +constexpr26 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)
> +constexpr26 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)
> +constexpr26 bool
> +strip_prefix(std::string_view& v, size_t n, char c)
> {
> size_t pos = v.find_first_not_of(c);
> if (pos == std::string_view::npos)
> @@ -291,7 +309,8 @@ bool strip_prefix(std::string_view& v, size_t n, char
> c)
> return true;
> }
>
> -void test_padding()
> +constexpr26 void
> +test_padding()
> {
> std::string res;
> std::string_view resv;
> @@ -351,13 +370,14 @@ struct std::formatter<Custom, CharT>
> { return pc.begin(); }
>
> template<typename Out>
> - typename std::basic_format_context<Out, CharT>::iterator
> + constexpr26 typename std::basic_format_context<Out, CharT>::iterator
> format(Custom, const std::basic_format_context<Out, CharT>& fc) const
> { return fc.out(); }
> };
>
> template<template<typename...> typename Tuple>
> -void test_nonblocking()
> +constexpr26 void
> +test_nonblocking()
> {
> static_assert(std::enable_nonlocking_formatter_optimization<
> Tuple<int, float>>);
> @@ -374,7 +394,8 @@ void test_nonblocking()
> Tuple<Custom&, float&>>);
> }
>
> -int main()
> +constexpr26 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;
> +}
> +
> +#if __cplusplus >= 202400L
> +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.43.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260416/14b45097/attachment-0001.htm>
More information about the Libstdc++
mailing list