https://gcc.gnu.org/g:36058be77f4c684350047adfe7c82aec91f3b72e
commit r16-4073-g36058be77f4c684350047adfe7c82aec91f3b72e Author: Tomasz Kamiński <tkami...@redhat.com> Date: Tue Sep 23 11:09:08 2025 +0200 libstdc++: Use basic_format_parse_context<_CharT> in internal chrono formatters. libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (__formatter_chrono::_M_parse): Replace _ParseContext with basic_format_parse_context<_CharT> and make it non-template. (__formatter_duration::_M_parse): Replace _ParseContext with basic_format_parse_context<_CharT> and remove unused default argument. Reviewed-by: Jonathan Wakely <jwak...@redhat.com> Signed-off-by: Tomasz Kamiński <tkami...@redhat.com> Diff: --- libstdc++-v3/include/bits/chrono_io.h | 520 +++++++++++++++++----------------- 1 file changed, 259 insertions(+), 261 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 85b2013cf704..0a6a3a5ce5a2 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -559,282 +559,281 @@ namespace __format __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept : _M_spec(__spec) { } + + constexpr typename basic_format_parse_context<_CharT>::iterator + _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts, + const _ChronoSpec<_CharT>& __def) + { + auto __first = __pc.begin(); + auto __last = __pc.end(); - template<typename _ParseContext> - constexpr typename _ParseContext::iterator - _M_parse(_ParseContext& __pc, _ChronoParts __parts, - const _ChronoSpec<_CharT>& __def) - { - auto __first = __pc.begin(); - auto __last = __pc.end(); - - _ChronoSpec<_CharT> __spec = __def; - - auto __finalize = [this, &__spec, &__def] { - using enum _ChronoParts; - _ChronoParts __checked - = __spec._M_debug ? _YearMonthDay|_IndexedWeekday - : _Month|_Weekday; - // n.b. for calendar types __def._M_needed contains only parts - // copied from the input, remaining ones are computed, and thus ok - __spec._M_needs_ok_check - = __spec._M_needs(__def._M_needed & __checked); - _M_spec = __spec; - }; - - auto __finished = [&] { - if (__first == __last || *__first == '}') - { - __finalize(); - return true; - } - return false; - }; - - if (__finished()) - return __first; - - __first = __spec._M_parse_fill_and_align(__first, __last); - if (__finished()) - return __first; + _ChronoSpec<_CharT> __spec = __def; - __first = __spec._M_parse_width(__first, __last, __pc); - if (__finished()) - return __first; + auto __finalize = [this, &__spec, &__def] { + using enum _ChronoParts; + _ChronoParts __checked + = __spec._M_debug ? _YearMonthDay|_IndexedWeekday + : _Month|_Weekday; + // n.b. for calendar types __def._M_needed contains only parts + // copied from the input, remaining ones are computed, and thus ok + __spec._M_needs_ok_check + = __spec._M_needs(__def._M_needed & __checked); + _M_spec = __spec; + }; - if (*__first == '.') + auto __finished = [&] { + if (__first == __last || *__first == '}') { - if ((__parts & _ChronoParts::_EpochUnits) == 0 - || !__spec._M_floating_point_rep) - __throw_format_error("format error: invalid precision for duration"); - - // Precision is allowed, but value is ignored. - __first = _Spec<_CharT>()._M_parse_precision(__first, __last, __pc); - // Still inditate that there was user supplied precision. - __spec._M_prec_kind = _WP_value; - if (__finished()) - return __first; + __finalize(); + return true; } + return false; + }; + + if (__finished()) + return __first; + + __first = __spec._M_parse_fill_and_align(__first, __last); + if (__finished()) + return __first; - __spec._M_localized = false; - __first = __spec._M_parse_locale(__first, __last); - if (__finished()) - return __first; + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __first; - // Everything up to the end of the string or the first '}' is a - // chrono-specs string. Check it is valid. + if (*__first == '.') { - __string_view __str(__first, __last - __first); - auto __end = __str.find('}'); - if (__end != __str.npos) - { - __str.remove_suffix(__str.length() - __end); - __last = __first + __end; - } - if (__str.find('{') != __str.npos) - __throw_format_error("chrono format error: '{' in chrono-specs"); + if ((__parts & _ChronoParts::_EpochUnits) == 0 + || !__spec._M_floating_point_rep) + __throw_format_error("format error: invalid precision for duration"); + + // Precision is allowed, but value is ignored. + __first = _Spec<_CharT>()._M_parse_precision(__first, __last, __pc); + // Still inditate that there was user supplied precision. + __spec._M_prec_kind = _WP_value; + if (__finished()) + return __first; } - // Parse chrono-specs in [first,last), checking each conversion-spec - // against __parts (so fail for %Y if no year in parts). - // Save range in __spec._M_chrono_specs. - __spec._M_debug = false; - __spec._M_locale_specific = false; - __spec._M_needed = _ChronoParts::_None; - __spec._M_chrono_specs = __string_view(); - - const auto __chrono_specs = __first++; // Skip leading '%' - if (*__chrono_specs != '%') - __throw_format_error("chrono format error: no '%' at start of " - "chrono-specs"); + __spec._M_localized = false; + __first = __spec._M_parse_locale(__first, __last); + if (__finished()) + return __first; - _CharT __mod{}; - bool __conv = true; - while (__first != __last) + // Everything up to the end of the string or the first '}' is a + // chrono-specs string. Check it is valid. + { + __string_view __str(__first, __last - __first); + auto __end = __str.find('}'); + if (__end != __str.npos) { - enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O }; - _Mods __allowed_mods = _Mod_none; + __str.remove_suffix(__str.length() - __end); + __last = __first + __end; + } + if (__str.find('{') != __str.npos) + __throw_format_error("chrono format error: '{' in chrono-specs"); + } - _ChronoParts __needed = _ChronoParts::_None; - bool __locale_specific = false; + // Parse chrono-specs in [first,last), checking each conversion-spec + // against __parts (so fail for %Y if no year in parts). + // Save range in __spec._M_chrono_specs. + __spec._M_debug = false; + __spec._M_locale_specific = false; + __spec._M_needed = _ChronoParts::_None; + __spec._M_chrono_specs = __string_view(); + + const auto __chrono_specs = __first++; // Skip leading '%' + if (*__chrono_specs != '%') + __throw_format_error("chrono format error: no '%' at start of " + "chrono-specs"); + + _CharT __mod{}; + bool __conv = true; + while (__first != __last) + { + enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O }; + _Mods __allowed_mods = _Mod_none; - _CharT __c = *__first++; - switch (__c) - { - using enum _ChronoParts; - case 'a': - case 'A': - __needed = _Weekday; - __locale_specific = true; - break; - case 'b': - case 'h': - case 'B': - __needed = _Month; - __locale_specific = true; - break; - case 'c': - __needed = _Date|_HoursMinutesSeconds; - __allowed_mods = _Mod_E; - __locale_specific = true; - break; - case 'C': - __needed = _Year; - __allowed_mods = _Mod_E; - break; - case 'd': - case 'e': - __needed = _Day; - __allowed_mods = _Mod_O; - break; - case 'D': - case 'F': - __needed = _YearMonthDay; - break; - case 'g': - case 'G': - case 'V': - __needed = _LocalDays|_Year|_DayOfYear|_Weekday; - break; - case 'H': - case 'I': - __needed = _HoursMinutesSeconds; - __allowed_mods = _Mod_O; - break; - case 'j': - __needed = __parts & _DayOfYear; - // If we do not know day-of-year then we must have a duration, - // which is to be formatted as decimal number of days. - if (__needed == _None) - __needed = _HoursMinutesSeconds; - break; - case 'm': - __needed = _Month; - __allowed_mods = _Mod_O; - break; - case 'M': - __needed = _HoursMinutesSeconds; - __allowed_mods = _Mod_O; - break; - case 'p': - case 'r': - __locale_specific = true; - [[fallthrough]]; - case 'R': - __needed = _HoursMinutesSeconds; - break; - case 'T': - __needed = _TimeOfDay; - break; - case 'q': - __needed = _UnitSuffix; - break; - case 'Q': - __needed = _EpochUnits; - break; - case 'S': - __needed = _TimeOfDay; - __allowed_mods = _Mod_O; - break; - case 'u': - case 'w': - __needed = _Weekday; - __allowed_mods = _Mod_O; - break; - case 'U': - case 'W': - __needed = _DayOfYear|_Weekday; - __allowed_mods = _Mod_O; - break; - case 'x': - __needed = _Date; - __locale_specific = true; - __allowed_mods = _Mod_E; - break; - case 'X': - __needed = _HoursMinutesSeconds; - __locale_specific = true; - __allowed_mods = _Mod_E; - break; - case 'y': - __needed = _Year; - __allowed_mods = _Mod_E_O; - break; - case 'Y': - __needed = _Year; - __allowed_mods = _Mod_E; - break; - case 'z': - __needed = _ZoneOffset; - __allowed_mods = _Mod_E_O; - break; - case 'Z': - __needed = _ZoneAbbrev; - break; - case 'n': - case 't': - case '%': - break; - case 'O': - case 'E': - if (__mod) [[unlikely]] - { - __allowed_mods = _Mod_none; - break; - } - __mod = __c; - continue; - default: - __throw_format_error("chrono format error: invalid " - " specifier in chrono-specs"); - } + _ChronoParts __needed = _ChronoParts::_None; + bool __locale_specific = false; - if ((__mod == 'E' && !(__allowed_mods & _Mod_E)) - || (__mod == 'O' && !(__allowed_mods & _Mod_O))) - __throw_format_error("chrono format error: invalid " - " modifier in chrono-specs"); - if (__mod && __c != 'z') + _CharT __c = *__first++; + switch (__c) + { + using enum _ChronoParts; + case 'a': + case 'A': + __needed = _Weekday; __locale_specific = true; - __mod = _CharT(); - - // localized formats do not include subseconds - if (__locale_specific) - __needed -= _ChronoParts::_Subseconds; - - if ((__parts & __needed) != __needed) - __throw_format_error("chrono format error: format argument " - "does not contain the information " - "required by the chrono-specs"); - __spec._M_needed |= __needed; - __spec._M_locale_specific |= __locale_specific; - - // Scan for next '%', ignoring literal-chars before it. - size_t __pos = __string_view(__first, __last - __first).find('%'); - if (__pos == 0) - ++__first; - else - { - if (__pos == __string_view::npos) - { - __first = __last; - __conv = false; - } - else - __first += __pos + 1; - } + break; + case 'b': + case 'h': + case 'B': + __needed = _Month; + __locale_specific = true; + break; + case 'c': + __needed = _Date|_HoursMinutesSeconds; + __allowed_mods = _Mod_E; + __locale_specific = true; + break; + case 'C': + __needed = _Year; + __allowed_mods = _Mod_E; + break; + case 'd': + case 'e': + __needed = _Day; + __allowed_mods = _Mod_O; + break; + case 'D': + case 'F': + __needed = _YearMonthDay; + break; + case 'g': + case 'G': + case 'V': + __needed = _LocalDays|_Year|_DayOfYear|_Weekday; + break; + case 'H': + case 'I': + __needed = _HoursMinutesSeconds; + __allowed_mods = _Mod_O; + break; + case 'j': + __needed = __parts & _DayOfYear; + // If we do not know day-of-year then we must have a duration, + // which is to be formatted as decimal number of days. + if (__needed == _None) + __needed = _HoursMinutesSeconds; + break; + case 'm': + __needed = _Month; + __allowed_mods = _Mod_O; + break; + case 'M': + __needed = _HoursMinutesSeconds; + __allowed_mods = _Mod_O; + break; + case 'p': + case 'r': + __locale_specific = true; + [[fallthrough]]; + case 'R': + __needed = _HoursMinutesSeconds; + break; + case 'T': + __needed = _TimeOfDay; + break; + case 'q': + __needed = _UnitSuffix; + break; + case 'Q': + __needed = _EpochUnits; + break; + case 'S': + __needed = _TimeOfDay; + __allowed_mods = _Mod_O; + break; + case 'u': + case 'w': + __needed = _Weekday; + __allowed_mods = _Mod_O; + break; + case 'U': + case 'W': + __needed = _DayOfYear|_Weekday; + __allowed_mods = _Mod_O; + break; + case 'x': + __needed = _Date; + __locale_specific = true; + __allowed_mods = _Mod_E; + break; + case 'X': + __needed = _HoursMinutesSeconds; + __locale_specific = true; + __allowed_mods = _Mod_E; + break; + case 'y': + __needed = _Year; + __allowed_mods = _Mod_E_O; + break; + case 'Y': + __needed = _Year; + __allowed_mods = _Mod_E; + break; + case 'z': + __needed = _ZoneOffset; + __allowed_mods = _Mod_E_O; + break; + case 'Z': + __needed = _ZoneAbbrev; + break; + case 'n': + case 't': + case '%': + break; + case 'O': + case 'E': + if (__mod) [[unlikely]] + { + __allowed_mods = _Mod_none; + break; + } + __mod = __c; + continue; + default: + __throw_format_error("chrono format error: invalid specifier " + "in chrono-specs"); } - // Check for a '%' conversion-spec without a type. - if (__conv || __mod != _CharT()) - __throw_format_error("chrono format error: unescaped '%' in " - "chrono-specs"); + if ((__mod == 'E' && !(__allowed_mods & _Mod_E)) + || (__mod == 'O' && !(__allowed_mods & _Mod_O))) + __throw_format_error("chrono format error: invalid modifier " + "in chrono-specs"); + if (__mod && __c != 'z') + __locale_specific = true; + __mod = _CharT(); + + // localized formats do not include subseconds + if (__locale_specific) + __needed -= _ChronoParts::_Subseconds; + + if ((__parts & __needed) != __needed) + __throw_format_error("chrono format error: format argument does " + "not contain the information required by the " + "chrono-specs"); + __spec._M_needed |= __needed; + __spec._M_locale_specific |= __locale_specific; + + // Scan for next '%', ignoring literal-chars before it. + size_t __pos = __string_view(__first, __last - __first).find('%'); + if (__pos == 0) + ++__first; + else + { + if (__pos == __string_view::npos) + { + __first = __last; + __conv = false; + } + else + __first += __pos + 1; + } + } - __spec._M_chrono_specs - = __string_view(__chrono_specs, __first - __chrono_specs); + // Check for a '%' conversion-spec without a type. + if (__conv || __mod != _CharT()) + __throw_format_error("chrono format error: unescaped '%' in " + "chrono-specs"); - __finalize(); - return __first; - } + __spec._M_chrono_specs + = __string_view(__chrono_specs, __first - __chrono_specs); + + __finalize(); + return __first; + } // pre: !_M_spec._M_chrono_specs.empty() template<typename _FormatContext> @@ -869,7 +868,6 @@ namespace __format return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); } - _ChronoSpec<_CharT> _M_spec; protected: @@ -1934,10 +1932,10 @@ namespace __format using __formatter_chrono<_CharT>::__formatter_chrono; using __formatter_chrono<_CharT>::_M_spec; - template<typename _Duration, typename _ParseContext> - constexpr typename _ParseContext::iterator - _M_parse(_ParseContext& __pc, _ChronoParts __parts, - const _ChronoSpec<_CharT>& __def = {}) + template<typename _Duration> + constexpr typename basic_format_parse_context<_CharT>::iterator + _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts, + const _ChronoSpec<_CharT>& __def) { using _Rep = typename _Duration::rep; using enum _ChronoParts;