On Tue, Apr 29, 2025 at 9:28 AM Tomasz Kamiński <tkami...@redhat.com> wrote:
> These patch makes following changes to _Pres_type values: > * _Pres_esc is replaced with separate _M_debug flag. > * _Pres_s, _Pres_p do not overlap with _Pres_none. > * hexadecimal presentation use same values for pointer, integer > and floating point types. > > Instead of `_M_reserved` and `_M_reserved2` bitfields, the members of > _Spec<_CharT> are rearranged so the class contains 16bit of tail padding. > Derived classes (like _ChronoSpec<_CharT>) can reuse the storage for > initial > members. We also add _SpecBase as the base class for _Spec<_CharT> to make > it non-C++98 POD, which allows tail padding to be reused on Itanium ABI. > > Finally, the format enumerators are defined as enum class with unsigned > char as underlying type, followed by using enum to bring names in scope. > _Term_char was adjusted for consistency. > > The '?' is changed to separate _M_debug flag, to allow debug format to be > independent from the presentation type, and applied to multiple > presentation > types. For example it could be used to trigger memberwise or reflection > based > formatting. > > The _M_format_character and _M_format_character_escaped functions are > merged > to single function that handle normal and debug presentation. In particular > this would allow future support for '?c' for printing integer types as > escaped > character. _S_character_width is also folded in the merged function. > > Decoupling _Pres_s value from _Pres_none, allows it to be used for string > presentation for range formatting, and removes the need for separate > _Pres_seq > and _Pres_str. This does not affect formatting of bool as > __formatter_int::_M_parse > overrides default value of _M_type. And with separation of the _M_debug > flag, > __formatter_str::format behavior is now agnostic to _M_type value. > > The values for integer presentation types, are arranged so textual > presentations > (_Prec_s, _Pres_c) are grouped together. For consistency floating point > hexadecimal presentation uses the same values as integer ones. > > New _Pres_p and setting for _M_alt enables using some spec to configure > formatting > of uintptr_t with __formatter_int, and const void* with __formatter_ptr. > Differentiating it from _Pres_none would allow future of formatter<T*, > _CharT> > that would require explicit presentation type to be specified. This would > allow > std::vector<T*> to be formatter directly with '{::p}' format spec. > > The constructors for __formatter_int and _formatter_ptr from _Spec<_CharT>, > now also set default presentation modes, as format functions expects them. > > libstdc++-v3/ChangeLog: > > * include/bits/chrono_io.h > (_ChronoSpec<_CharT>::_M_locale_specific): > Declare as bit filed in tail-padding.. > * include/bits/formatfwd.h (__format::_Align): Defined as enum > class > and add using enum. > * include/std/format (__format::_Pres_type, __format::_Sign) > (__format::_WidthPrec, __format::_Arg_t): Defined as enum class > and > add using enum. > (_Pres_type::_Pres_esc): Replace with _Pres_max. > (_Pres_type::_Pres_seq, _Pres_type::_Pres_str): Remove. > (__format::_Pres_type): Updated values of enumerators as described > above. > (_Spec<_CharT>): Rearranged members to have 16bits of tail-padding. > (_Spec<_CharT>::_M_debug): Defined. > (_Spec<_CharT>::_M_reserved, _Spec<_CharT>::_M_reserved2): Removed. > (_Spec<_CharT>::_M_parse_fill_and_align, > _Spec<_CharT>::_M_parse_sign) > (__format::__write_padded_as_spec): Adjusted default value checks. > (__format::_Term_char): Add using enum and rename enumertors. > (__format::__should_escape_ascii): Adjusted _Term_char uses. > (__formatter_str<_CharT>::parse): Set _Pres_s if specifed and > _M_debug > instead of _Pres_esc. > (__formatter_str<_CharT>::set_debug_format): Set _M_debug instead > of > _Pres_esc. > (__formatter_str<_CharT>::format, > __formatter_str<_CharT>::_M_format_range): > Check _M_debug instead of _Prec_esc. > (__formatter_str<_CharT>::_M_format_escaped): Adjusted _Term_char > uses. > (__formatter_int<_CharT>::__formatter_int(_Spec<_CharT>)): Set > _Pres_d if > default presentation type is not set. > (__formatter_int<_CharT>::_M_parse): Adjusted default value checks. > (__formatter_int<_CharT>::_M_do_parse): Set _M_debug instead of > _Pres_esc. > (__formatter_int<_CharT>::_M_format_character): Handle escaped > presentation. > (__formatter_int<_CharT>::_M_format_character_escaped) > (__formatter_int<_CharT>::_S_character_width): Merged into > _M_format_character. > (__formatter_ptr<_CharT>::__formatter_ptr(_Spec<_CharT>)): Set > _Pres_p if default > presentation type is not set. > (__formatter_ptr<_CharT>::parse): Add default __type parameter, > store _Pres_p, > and handle _M_alt to be consistent with meaning for integers. > (__foramtter_ptr<_CharT>::_M_set_default): Define. > (__format::__pack_arg_types, std::basic_format_args): Add > necessary casts. > (formatter<_CharT, _CharT>::set_debug_format) > (formatter<char, wchar_t>::set_debug_format): Set _M_debug instead > of _Pres_esc. > (formatter<_CharT, _CharT>::format, formatter<char, > wchar_t>::format): > Simplify calls to _M_format_character. > (range_formatter<_Rg, _CharT>::parse): Replace _Pres_str with > _Pres_s > and set _M_debug instead of _Pres_esc. > (range_formatter<_Rg, _CharT>::format): Replace _Pres_str with > _Pres_s. > --- > I think using tail-padding is the better option, so following on here. > Performed a few additional cleanups: > * _Term_char now is consitient with remaining enumerators > * __formatter_ptr/_formatter_int constructor from _Spec, now set defaults > for > _Pres_none, as format expects them. This makes using them like in > formatter<thread::id, _CharT> easier. > Testing on x86_64-linux. OK for turnk if test passes? > All test passed. OK for trunk? > > libstdc++-v3/include/bits/chrono_io.h | 18 +-- > libstdc++-v3/include/bits/formatfwd.h | 3 +- > libstdc++-v3/include/std/format | 221 ++++++++++++++------------ > 3 files changed, 123 insertions(+), 119 deletions(-) > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index b7f6f5f49e5..2b77eb2acc5 100644 > --- a/libstdc++-v3/include/bits/chrono_io.h > +++ b/libstdc++-v3/include/bits/chrono_io.h > @@ -207,21 +207,15 @@ namespace __format > template<typename _CharT> > struct _ChronoSpec : _Spec<_CharT> > { > - basic_string_view<_CharT> _M_chrono_specs; > - > - // Use one of the reserved bits in __format::_Spec<C>. > + // Placed in tail-padding of __format::_Spec<C>. > // This indicates that a locale-dependent conversion specifier such > as > // %a is used in the chrono-specs. This is not the same as the > // _Spec<C>::_M_localized member which indicates that "L" was > present > // in the format-spec, e.g. "{:L%a}" is localized and > locale-specific, > // but "{:L}" is only localized and "{:%a}" is only locale-specific. > - constexpr bool > - _M_locale_specific() const noexcept > - { return this->_M_reserved; } > + unsigned _M_locale_specific : 1; > > - constexpr void > - _M_locale_specific(bool __b) noexcept > - { this->_M_reserved = __b; } > + basic_string_view<_CharT> _M_chrono_specs; > }; > > // Represents the information provided by a chrono type. > @@ -488,7 +482,7 @@ namespace __format > _M_spec = __spec; > _M_spec._M_chrono_specs > = __string_view(__chrono_specs, __first - __chrono_specs); > - _M_spec._M_locale_specific(__locale_specific); > + _M_spec._M_locale_specific = __locale_specific; > > return __first; > } > @@ -514,7 +508,7 @@ namespace __format > // of chrono types is underspecified > if constexpr (is_same_v<_CharT, char>) > if constexpr (__unicode::__literal_encoding_is_utf8()) > - if (_M_spec._M_localized && _M_spec._M_locale_specific()) > + if (_M_spec._M_localized && _M_spec._M_locale_specific) > { > extern locale __with_encoding_conversion(const locale&); > > @@ -816,7 +810,7 @@ namespace __format > // of chrono types is underspecified > if constexpr (is_same_v<_CharT, char>) > if constexpr (__unicode::__literal_encoding_is_utf8()) > - if (_M_spec._M_localized && _M_spec._M_locale_specific() > + if (_M_spec._M_localized && _M_spec._M_locale_specific > && __loc != locale::classic()) > { > extern string_view > diff --git a/libstdc++-v3/include/bits/formatfwd.h > b/libstdc++-v3/include/bits/formatfwd.h > index 3fa01ad1eab..777e6290f74 100644 > --- a/libstdc++-v3/include/bits/formatfwd.h > +++ b/libstdc++-v3/include/bits/formatfwd.h > @@ -71,12 +71,13 @@ namespace __format > concept __char = same_as<_CharT, char>; > #endif > > - enum _Align { > + enum class _Align : unsigned char { > _Align_default, > _Align_left, > _Align_right, > _Align_centre, > }; > + using enum _Align; > > template<typename _CharT> struct _Spec; > > diff --git a/libstdc++-v3/include/std/format > b/libstdc++-v3/include/std/format > index b3794b64b59..0be214b8713 100644 > --- a/libstdc++-v3/include/std/format > +++ b/libstdc++-v3/include/std/format > @@ -472,30 +472,33 @@ namespace __format > return {0, nullptr}; > } > > - enum _Pres_type { > + enum class _Pres_type : unsigned char { > _Pres_none = 0, // Default type (not valid for integer presentation > types). > + _Pres_s = 1, // For strings, bool, ranges > // Presentation types for integral types (including bool and charT). > - _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, > - // Presentation types for floating-point types. > - _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, > _Pres_G, > - _Pres_p = 0, _Pres_P, // For pointers. > - _Pres_s = 0, // For strings, bool > - _Pres_seq = 0, _Pres_str, // For ranges > - _Pres_esc = 0xf, // For strings, charT and ranges > + /* s */ _Pres_c = 2, _Pres_x, _Pres_X, _Pres_d, _Pres_o, _Pres_b, > _Pres_B, > + // Presentation types for floating-point types > + _Pres_g = 1, _Pres_G, _Pres_a, _Pres_A, _Pres_e, _Pres_E, _Pres_f, > _Pres_F, > + // For pointers, the value are same as hexadecimal presentations for > integers > + _Pres_p = _Pres_x, _Pres_P = _Pres_X, > + _Pres_max = 0xf, > }; > + using enum _Pres_type; > > - enum _Sign { > + enum class _Sign : unsigned char { > _Sign_default, > _Sign_plus, > _Sign_minus, // XXX does this need to be distinct from _Sign_default? > _Sign_space, > }; > + using enum _Sign; > > - enum _WidthPrec { > + enum _WidthPrec : unsigned char { > _WP_none, // No width/prec specified. > _WP_value, // Fixed width/prec specified. > _WP_from_arg // Use a formatting argument for width/prec. > }; > + using enum _WidthPrec; > > template<typename _Context> > size_t > @@ -507,9 +510,17 @@ namespace __format > constexpr bool __is_xdigit(char __c) > { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } > > + // Used to make _Spec a non-C++98 POD, so the tail-padding is used. > + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod > + struct _SpecBase > + { }; > + > template<typename _CharT> > - struct _Spec > + struct _Spec : _SpecBase > { > + unsigned short _M_width; > + unsigned short _M_prec; > + char32_t _M_fill = ' '; > _Align _M_align : 2; > _Sign _M_sign : 2; > unsigned _M_alt : 1; > @@ -517,12 +528,10 @@ namespace __format > unsigned _M_zero_fill : 1; > _WidthPrec _M_width_kind : 2; > _WidthPrec _M_prec_kind : 2; > + unsigned _M_debug : 1; > _Pres_type _M_type : 4; > - unsigned _M_reserved : 1; > - unsigned _M_reserved2 : 16; > - unsigned short _M_width; > - unsigned short _M_prec; > - char32_t _M_fill = ' '; > + // This class has 16bit of tail padding, that can be used by > + // derived classes. > > using iterator = typename basic_string_view<_CharT>::iterator; > > @@ -562,7 +571,7 @@ namespace __format > char32_t __c = *__beg++; > if (__is_scalar_value(__c)) > if (auto __next = __beg.base(); __next != __last) > - if (_Align __align = _S_align(*__next)) > + if (_Align __align = _S_align(*__next); __align != > _Align_default) > { > _M_fill = __c; > _M_align = __align; > @@ -571,14 +580,14 @@ namespace __format > } > } > else if (__last - __first >= 2) > - if (_Align __align = _S_align(__first[1])) > + if (_Align __align = _S_align(__first[1]); __align != > _Align_default) > { > _M_fill = *__first; > _M_align = __align; > return __first + 2; > } > > - if (_Align __align = _S_align(__first[0])) > + if (_Align __align = _S_align(__first[0]); __align != > _Align_default) > { > _M_fill = ' '; > _M_align = __align; > @@ -603,7 +612,7 @@ namespace __format > constexpr iterator > _M_parse_sign(iterator __first, iterator) noexcept > { > - if (_Sign __sign = _S_sign(*__first)) > + if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default) > { > _M_sign = __sign; > return __first + 1; > @@ -871,7 +880,7 @@ namespace __format > > const size_t __nfill = __width - __estimated_width; > > - if (__spec._M_align) > + if (__spec._M_align != _Align_default) > __align = __spec._M_align; > > return __format::__write_padded(__fc.out(), __str, __align, __nfill, > @@ -899,9 +908,10 @@ namespace __format > > // Values are indices into _Escapes::all. > enum class _Term_char : unsigned char { > - _Tc_quote = 12, > - _Tc_apos = 15 > + _Term_quote = 12, > + _Term_apos = 15 > }; > + using enum _Term_char; > > template<typename _CharT> > struct _Escapes > @@ -991,9 +1001,9 @@ namespace __format > case _Esc::_S_bslash()[0]: > return true; > case _Esc::_S_quote()[0]: > - return __term == _Term_char::_Tc_quote; > + return __term == _Term_quote; > case _Esc::_S_apos()[0]: > - return __term == _Term_char::_Tc_apos; > + return __term == _Term_apos; > default: > return (__c >= 0 && __c < 0x20) || __c == 0x7f; > }; > @@ -1312,11 +1322,14 @@ namespace __format > return __first; > > if (*__first == 's') > - ++__first; > + { > + __spec._M_type = _Pres_s; > + ++__first; > + } > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED > else if (*__first == '?') > { > - __spec._M_type = _Pres_esc; > + __spec._M_debug = true; > ++__first; > } > #endif > @@ -1332,7 +1345,7 @@ namespace __format > format(basic_string_view<_CharT> __s, > basic_format_context<_Out, _CharT>& __fc) const > { > - if (_M_spec._M_type == _Pres_esc) > + if (_M_spec._M_debug) > return _M_format_escaped(__s, __fc); > > if (_M_spec._M_width_kind == _WP_none > @@ -1349,22 +1362,21 @@ namespace __format > _M_format_escaped(basic_string_view<_CharT> __s, > basic_format_context<_Out, _CharT>& __fc) const > { > - constexpr auto __term = __format::_Term_char::_Tc_quote; > const size_t __padwidth = _M_spec._M_get_width(__fc); > if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) > - return __format::__write_escaped(__fc.out(), __s, __term); > + return __format::__write_escaped(__fc.out(), __s, _Term_quote); > > const size_t __maxwidth = _M_spec._M_get_precision(__fc); > const size_t __width = __truncate(__s, __maxwidth); > // N.B. Escaping only increases width > if (__padwidth <= __width && _M_spec._M_prec_kind == _WP_none) > - return __format::__write_escaped(__fc.out(), __s, __term); > + return __format::__write_escaped(__fc.out(), __s, _Term_quote); > > // N.B. [tab:format.type.string] defines '?' as > // Copies the escaped string ([format.string.escaped]) to the > output, > // so precision seem to appy to escaped string. > _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, > __maxwidth); > - __format::__write_escaped(__sink.out(), __s, __term); > + __format::__write_escaped(__sink.out(), __s, _Term_quote); > return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); > } > > @@ -1388,7 +1400,7 @@ namespace __format > size_t(ranges::distance(__rg))); > return format(__str, __fc); > } > - else if (_M_spec._M_type != _Pres_esc) > + else if (!_M_spec._M_debug) > { > const size_t __padwidth = _M_spec._M_get_width(__fc); > if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) > @@ -1441,7 +1453,7 @@ namespace __format > > constexpr void > set_debug_format() noexcept > - { _M_spec._M_type = _Pres_esc; } > + { _M_spec._M_debug = true; } > #endif > > private: > @@ -1462,7 +1474,10 @@ namespace __format > constexpr > __formatter_int(_Spec<_CharT> __spec) noexcept > : _M_spec(__spec) > - { } > + { > + if (_M_spec._M_type == _Pres_none) > + _M_spec._M_type = _Pres_d; > + } > > constexpr typename basic_format_parse_context<_CharT>::iterator > _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type > __type) > @@ -1551,7 +1566,7 @@ namespace __format > case 's': > if (__type == _AsBool) > { > - __spec._M_type = _Pres_s; // same value (and meaning) as > "none" > + __spec._M_type = _Pres_s; // same meaning as "none" for > bool > ++__first; > } > break; > @@ -1559,7 +1574,7 @@ namespace __format > case '?': > if (__type == _AsChar) > { > - __spec._M_type = _Pres_esc; > + __spec._M_debug = true; > ++__first; > } > #endif > @@ -1580,7 +1595,8 @@ namespace __format > { > auto __end = _M_do_parse(__pc, _AsBool); > if (_M_spec._M_type == _Pres_s) > - if (_M_spec._M_sign || _M_spec._M_alt || > _M_spec._M_zero_fill) > + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt > + || _M_spec._M_zero_fill) > __throw_format_error("format error: format-spec contains > " > "invalid formatting options for " > "'bool'"); > @@ -1589,8 +1605,9 @@ namespace __format > else if constexpr (__char<_Tp>) > { > auto __end = _M_do_parse(__pc, _AsChar); > - if (_M_spec._M_type == _Pres_c || _M_spec._M_type == > _Pres_esc) > - if (_M_spec._M_sign || _M_spec._M_alt || > _M_spec._M_zero_fill > + if (_M_spec._M_type == _Pres_c) > + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt > + || _M_spec._M_zero_fill > /* XXX should be invalid? || _M_spec._M_localized */) > __throw_format_error("format error: format-spec contains > " > "invalid formatting options for " > @@ -1702,51 +1719,34 @@ namespace __format > _M_spec); > } > > - [[__gnu__::__always_inline__]] > - static size_t > - _S_character_width(_CharT __c) > - { > - // N.B. single byte cannot encode charcter of width greater than 1 > - if constexpr (sizeof(_CharT) > 1u && > - __unicode::__literal_encoding_is_unicode<_CharT>()) > - return __unicode::__field_width(__c); > - else > - return 1u; > - } > - > template<typename _Out> > typename basic_format_context<_Out, _CharT>::iterator > _M_format_character(_CharT __c, > - basic_format_context<_Out, _CharT>& __fc) const > + basic_format_context<_Out, _CharT>& __fc) const > { > - return __format::__write_padded_as_spec({&__c, 1u}, > - _S_character_width(__c), > - __fc, _M_spec); > - } > + basic_string_view<_CharT> __in(&__c, 1u); > + size_t __width = 1u; > + // N.B. single byte cannot encode charcter of width greater than > 1 > + if constexpr (sizeof(_CharT) > 1u && > + > __unicode::__literal_encoding_is_unicode<_CharT>()) > + __width = __unicode::__field_width(__c); > > - template<typename _Out> > - typename basic_format_context<_Out, _CharT>::iterator > - _M_format_character_escaped(_CharT __c, > - basic_format_context<_Out, _CharT>& > __fc) const > - { > - using _Esc = _Escapes<_CharT>; > - constexpr auto __term = __format::_Term_char::_Tc_apos; > - const basic_string_view<_CharT> __in(&__c, 1u); > - if (_M_spec._M_get_width(__fc) <= 3u) > - return __format::__write_escaped(__fc.out(), __in, __term); > + if (!_M_spec._M_debug) > + return __format::__write_padded_as_spec(__in, __width, > + __fc, _M_spec); > + > + __width += 2; > + if (_M_spec._M_get_width(__fc) <= __width) > + return __format::__write_escaped(__fc.out(), __in, _Term_apos); > > _CharT __buf[12]; > __format::_Fixedbuf_sink<_CharT> __sink(__buf); > - __format::__write_escaped(__sink.out(), __in, __term); > + __format::__write_escaped(__sink.out(), __in, _Term_apos); > > - const basic_string_view<_CharT> __escaped = __sink.view(); > - size_t __estimated_width; > - if (__escaped[1] == _Esc::_S_bslash()[0]) // escape sequence > - __estimated_width = __escaped.size(); > - else > - __estimated_width = 2 + _S_character_width(__c); > - return __format::__write_padded_as_spec(__escaped, > - __estimated_width, > + __in = __sink.view(); > + if (__in[1] == _Escapes<_CharT>::_S_bslash()[0]) // escape > sequence > + __width = __in.size(); > + return __format::__write_padded_as_spec(__in, __width, > __fc, _M_spec); > } > > @@ -2419,17 +2419,18 @@ namespace __format > constexpr > __formatter_ptr(_Spec<_CharT> __spec) noexcept > : _M_spec(__spec) > - { } > + { _M_set_default(_Pres_p); } > > constexpr typename basic_format_parse_context<_CharT>::iterator > - parse(basic_format_parse_context<_CharT>& __pc) > + parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type = > _Pres_p) > { > __format::_Spec<_CharT> __spec{}; > const auto __last = __pc.end(); > auto __first = __pc.begin(); > > - auto __finalize = [this, &__spec] { > + auto __finalize = [this, &__spec, __type] { > _M_spec = __spec; > + _M_set_default(__type); > }; > > auto __finished = [&] { > @@ -2457,19 +2458,23 @@ namespace __format > #endif > > __first = __spec._M_parse_width(__first, __last, __pc); > + if (__finished()) > + return __first; > > - if (__first != __last) > + if (*__first == 'p') > { > - if (*__first == 'p') > - ++__first; > + __spec._M_type = _Pres_p; > + _M_spec._M_alt = !_M_spec._M_alt; > + ++__first; > + } > #if __glibcxx_format >= 202304L > - else if (*__first == 'P') > - { > - __spec._M_type = __format::_Pres_P; > - ++__first; > - } > -#endif > + else if (*__first == 'P') > + { > + __spec._M_type = _Pres_P; > + _M_spec._M_alt = !_M_spec._M_alt; > + ++__first; > } > +#endif > > if (__finished()) > return __first; > @@ -2536,6 +2541,17 @@ namespace __format > } > > private: > + [[__gnu__::__always_inline__]] > + constexpr void > + _M_set_default(_Pres_type __type) > + { > + if (_M_spec._M_type == _Pres_none && __type != _Pres_none) > + { > + _M_spec._M_type = __type; > + _M_spec._M_alt = !_M_spec._M_alt; > + } > + } > + > __format::_Spec<_CharT> _M_spec{}; > }; > > @@ -2558,11 +2574,8 @@ namespace __format > typename basic_format_context<_Out, _CharT>::iterator > format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const > { > - if (_M_f._M_spec._M_type == __format::_Pres_none > - || _M_f._M_spec._M_type == __format::_Pres_c) > + if (_M_f._M_spec._M_type == __format::_Pres_c) > return _M_f._M_format_character(__u, __fc); > - else if (_M_f._M_spec._M_type == __format::_Pres_esc) > - return _M_f._M_format_character_escaped(__u, __fc); > else > return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), > __fc); > } > @@ -2570,7 +2583,7 @@ namespace __format > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED > constexpr void > set_debug_format() noexcept > - { _M_f._M_spec._M_type = __format::_Pres_esc; } > + { _M_f._M_spec._M_debug = true; } > #endif > > private: > @@ -2594,11 +2607,8 @@ namespace __format > typename basic_format_context<_Out, wchar_t>::iterator > format(char __u, basic_format_context<_Out, wchar_t>& __fc) const > { > - if (_M_f._M_spec._M_type == __format::_Pres_none > - || _M_f._M_spec._M_type == __format::_Pres_c) > + if (_M_f._M_spec._M_type == __format::_Pres_c) > return _M_f._M_format_character(__u, __fc); > - else if (_M_f._M_spec._M_type == __format::_Pres_esc) > - return _M_f._M_format_character_escaped(__u, __fc); > else > return _M_f.format(static_cast<unsigned char>(__u), __fc); > } > @@ -2606,7 +2616,7 @@ namespace __format > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED > constexpr void > set_debug_format() noexcept > - { _M_f._M_spec._M_type = __format::_Pres_esc; } > + { _M_f._M_spec._M_debug = true; } > #endif > > private: > @@ -3792,7 +3802,7 @@ namespace __format > } > }; > > - enum _Arg_t : unsigned char { > + enum class _Arg_t : unsigned char { > _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, > _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, > _Arg_handle, > _Arg_i128, _Arg_u128, > @@ -3806,6 +3816,7 @@ namespace __format > #endif > _Arg_max_ > }; > + using enum _Arg_t; > > template<typename _Context> > struct _Arg_value > @@ -4373,7 +4384,7 @@ namespace __format > { > __UINT64_TYPE__ __packed_types = 0; > for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) > - __packed_types = (__packed_types << _Bits) | *__i; > + __packed_types = (__packed_types << _Bits) | (unsigned)*__i; > return __packed_types; > } > } // namespace __format > @@ -4386,7 +4397,7 @@ namespace __format > static constexpr int _S_packed_type_mask = 0b11111; > static constexpr int _S_max_packed_args = 12; > > - static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) ); > + static_assert( (unsigned)__format::_Arg_max_ <= (1u << > _S_packed_type_bits) ); > > template<typename... _Args> > using _Store = __format::_Arg_store<_Context, _Args...>; > @@ -5725,7 +5736,7 @@ namespace __format > if (*__first == '?') > { > ++__first; > - __spec._M_type = __format::_Pres_esc; > + __spec._M_debug = true; > if (__finished() || *__first != 's') > __throw_format_error("format error: '?' is allowed only in" > " combination with 's'"); > @@ -5736,8 +5747,7 @@ namespace __format > ++__first; > if constexpr (same_as<_Tp, _CharT>) > { > - if (__spec._M_type != __format::_Pres_esc) > - __spec._M_type = __format::_Pres_str; > + __spec._M_type = __format::_Pres_s; > if (__finished()) > return __finalize(); > __throw_format_error("format error: element format > specifier" > @@ -5819,8 +5829,7 @@ namespace __format > _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) > const > { > if constexpr (same_as<_Tp, _CharT>) > - if (_M_spec._M_type == __format::_Pres_str > - || _M_spec._M_type == __format::_Pres_esc) > + if (_M_spec._M_type == __format::_Pres_s) > { > __format::__formatter_str __fstr(_M_spec); > return __fstr._M_format_range(__rg, __fc); > -- > 2.49.0 > >