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