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? 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