The r16-1709-g4b3cefed1a08344495fedec4982d85168bd8173f caused `-Woverflow` in empty_spec.cc file. This warning is not cause by any issue in shipping code, and results in taking to much shortcut when implementing a test-only custom representation type Rep, where long was always used to store a value. In particular common type for Rep and long long int, was de-facto long. This is addressed by adding Under template parameter, that controls the type of stored value, and handling it properly in common_type specializations. No changes to shipping code are necessary.
Secondly, extracting _M_locale_fmt calls in r16-1712-gcaac94, resulted in __ctx format parameter no longer being used. This patch removes such parameter entirely, and replace _FormatContext template parameter, with _OutIter parameter for __out. For consistency type of the __out is decoupled from _FormatContext, for functions that still need context: * to extract locale (_M_A_a, _M_B_b, _M_c, _M_p, _M_r, _M_subsecs) * perform formatting for duration/subseconds (_M_Q, _M_T, _M_S, _M_subsecs) PR libstdc++/110739 libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (__formatter_chrono::_M_format_to): Rename _Out to _OutIter for consistency, and update calls to specifier functions. (__formatter_chrono::_M_wi, __formatter_chrono::_M_C_y_Y) (__formatter_chrono::_M_D_x, __formatter_chrono::_M_d_e) (__formatter_chrono::_M_F, __formatter_chrono::_M_g_G) (__formatter_chrono::_M_H_I, __formatter_chrono::_M_j) (__formatter_chrono::_M_m, __formatter_chrono::_M_M) (__formatter_chrono::_M_q, __formatter_chrono::_M_R_X) (__formatter_chrono::_M_u_w, __formatter_chrono::_M_U_V_W) (__formatter_chrono::_M_z, __formatter_chrono::_M_z): Remove _FormatContext parameter, and introduce _OutIter for __out type. (__formatter_chrono::_M_a_A, __formatter_chrono::_M_B_b) (__formatter_chrono::_M_p, __formatter_chrono::_M_Q) (__formatter_chrono::_M_r, __formatter_chrono::_M_S) (__formatter_chrono::_M_subsecs, __formatter_chrono::_M_T): Introduce separate _OutIter template parameter for __out. (__formatter_chrono::_M_c, __formatter_chrono::_M_T): Likewise, and adjust calls to specifiers functions. * testsuite/std/time/format/empty_spec.cc: Make underlying type for Rep configurable. --- Tested on x86_64-linux (full-suite), I have found any overflow warnings, neither warnings produced from chrono_io.h Pushed to trunk. libstdc++-v3/include/bits/chrono_io.h | 221 ++++++++---------- .../testsuite/std/time/format/empty_spec.cc | 43 ++-- 2 files changed, 129 insertions(+), 135 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index bcfd51b9866..0ffbf06a7ff 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -942,9 +942,9 @@ namespace __format return __out; } - template<typename _Out, typename _FormatContext> - _Out - _M_format_to(const _ChronoData<_CharT>& __t, _Out __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_format_to(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __fc) const { auto __first = _M_spec._M_chrono_specs.begin(); @@ -1005,7 +1005,7 @@ namespace __format { // %\0 is extension for handling weekday index case '\0': - __out = _M_wi(__t._M_weekday_index, std::move(__out), __fc); + __out = _M_wi(__t._M_weekday_index, std::move(__out)); break; case 'a': case 'A': @@ -1022,41 +1022,41 @@ namespace __format case 'C': case 'y': case 'Y': - __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc, __c); + __out = _M_C_y_Y(__t._M_year, std::move(__out), __c); break; case 'd': case 'e': - __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c); + __out = _M_d_e(__t._M_day, std::move(__out), __c); break; case 'D': case 'x': - __out = _M_D_x(__t, std::move(__out), __fc); + __out = _M_D_x(__t, std::move(__out)); break; case 'F': - __out = _M_F(__t, std::move(__out), __fc); + __out = _M_F(__t, std::move(__out)); break; case 'g': case 'G': - __out = _M_g_G(__t, std::move(__out), __fc, __c == 'G'); + __out = _M_g_G(__t, std::move(__out), __c == 'G'); break; case 'H': case 'I': - __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c); + __out = _M_H_I(__t._M_hours, __print_sign(), __c); break; case 'j': - __out = _M_j(__t, __print_sign(), __fc); + __out = _M_j(__t, __print_sign()); break; case 'm': - __out = _M_m(__t._M_month, std::move(__out), __fc); + __out = _M_m(__t._M_month, std::move(__out)); break; case 'M': - __out = _M_M(__t._M_minutes, __print_sign(), __fc); + __out = _M_M(__t._M_minutes, __print_sign()); break; case 'p': __out = _M_p(__t._M_hours, std::move(__out), __fc); break; case 'q': - __out = _M_q(__t._M_unit_suffix, std::move(__out), __fc); + __out = _M_q(__t._M_unit_suffix, std::move(__out)); break; case 'Q': __out = _M_Q(__t, __print_sign(), __fc); @@ -1066,7 +1066,7 @@ namespace __format break; case 'R': case 'X': - __out = _M_R_X(__t, __print_sign(), __fc, __c != 'R'); + __out = _M_R_X(__t, __print_sign(), __c != 'R'); break; case 'T': __out = _M_T(__t, __print_sign(), __fc); @@ -1076,18 +1076,18 @@ namespace __format break; case 'u': case 'w': - __out = _M_u_w(__t._M_weekday, std::move(__out), __fc, __c); + __out = _M_u_w(__t._M_weekday, std::move(__out), __c); break; case 'U': case 'V': case 'W': - __out = _M_U_V_W(__t, std::move(__out), __fc, __c); + __out = _M_U_V_W(__t, std::move(__out), __c); break; case 'z': - __out = _M_z(__t._M_zone_offset, std::move(__out), __fc, (bool)__mod); + __out = _M_z(__t._M_zone_offset, std::move(__out), (bool)__mod); break; case 'Z': - __out = _M_Z(__t._M_zone_abbrev, std::move(__out), __fc); + __out = _M_Z(__t._M_zone_abbrev, std::move(__out)); break; case 'n': *__out++ = __literals[0]; @@ -1128,10 +1128,9 @@ namespace __format return std::move(__out); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_wi(unsigned __wi, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter> + _OutIter + _M_wi(unsigned __wi, _OutIter __out) const { // %\0 Extension to format weekday index, used only by empty format spec _CharT __buf[3]; @@ -1142,9 +1141,9 @@ namespace __format return std::move(__out); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_a_A(chrono::weekday __wd, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_a_A(chrono::weekday __wd, _OutIter __out, _FormatContext& __ctx, bool __full) const { // %a Locale's abbreviated weekday name. @@ -1172,9 +1171,9 @@ namespace __format return _M_write(std::move(__out), __loc, __str); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_b_B(chrono::month __m, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_b_B(chrono::month __m, _OutIter __out, _FormatContext& __ctx, bool __full) const { // %b Locale's abbreviated month name. @@ -1202,9 +1201,9 @@ namespace __format return _M_write(std::move(__out), __loc, __str); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_c(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_c(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __ctx) const { // %c Locale's date and time representation, for C-locale: %a %b %e %T %Y @@ -1214,17 +1213,16 @@ namespace __format *__out = _S_space; __out = _M_b_B(__t._M_month, std::move(++__out), __ctx, false); *__out = _S_space; - __out = _M_d_e(__t._M_day, std::move(++__out), __ctx, 'e'); + __out = _M_d_e(__t._M_day, std::move(++__out), 'e'); *__out = _S_space; - __out = _M_R_X(__t, std::move(++__out), __ctx, true); + __out = _M_R_X(__t, std::move(++__out), true); *__out = _S_space; - return _M_C_y_Y(__t._M_year, std::move(++__out), __ctx, 'Y'); + return _M_C_y_Y(__t._M_year, std::move(++__out), 'Y'); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_C_y_Y(chrono::year __y, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv) const + template<typename _OutIter> + _OutIter + _M_C_y_Y(chrono::year __y, _OutIter __out, _CharT __conv) const { // %C Year divided by 100 using floored division. // %EC Locale's alternative preresentation of the century (era name). @@ -1273,10 +1271,9 @@ namespace __format return __out; } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_D_x(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext&) const + template<typename _OutIter> + _OutIter + _M_D_x(const _ChronoData<_CharT>& __t, _OutIter __out) const { // %D Equivalent to %m/%d/%y // %x Locale's date rep, for C-locale: %m/%d/%y @@ -1308,10 +1305,9 @@ namespace __format return std::move(__out); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_d_e(chrono::day __d, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv) const + template<typename _OutIter> + _OutIter + _M_d_e(chrono::day __d, _OutIter __out, _CharT __conv) const { // %d The day of month as a decimal number. // %Od Locale's alternative representation. @@ -1336,10 +1332,9 @@ namespace __format return std::move(__out); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_F(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext&) const + template<typename _OutIter> + _OutIter + _M_F(const _ChronoData<_CharT>& __t, _OutIter __out) const { auto __di = (unsigned)__t._M_day; auto __mi = (unsigned)__t._M_month; @@ -1376,10 +1371,10 @@ namespace __format return std::move(__out); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_g_G(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, bool __full) const + template<typename _OutIter> + _OutIter + _M_g_G(const _ChronoData<_CharT>& __t, _OutIter __out, + bool __full) const { // %g last two decimal digits of the ISO week-based year. // %G ISO week-based year. @@ -1389,13 +1384,12 @@ namespace __format __d -= (__t._M_weekday - Monday) - days(3); // ISO week-based year is the year that contains that Thursday: year __y = year_month_day(__d).year(); - return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]); + return _M_C_y_Y(__y, std::move(__out), "yY"[__full]); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_H_I(chrono::hours __h, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv) const + template<typename _OutIter> + _OutIter + _M_H_I(chrono::hours __h, _OutIter __out, _CharT __conv) const { // %H The hour (24-hour clock) as a decimal number. // %OH Locale's alternative representation. @@ -1416,10 +1410,9 @@ namespace __format return __format::__write(std::move(__out), _S_two_digits(__i)); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_j(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext&) const + template<typename _OutIter> + _OutIter + _M_j(const _ChronoData<_CharT>& __t, _OutIter __out) const { if (_M_spec._M_time_only) { @@ -1432,10 +1425,9 @@ namespace __format __t._M_day_of_year.count()); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_m(chrono::month __m, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter> + _OutIter + _M_m(chrono::month __m, _OutIter __out) const { // %m month as a decimal number. // %Om Locale's alternative representation. @@ -1446,10 +1438,9 @@ namespace __format return __format::__write(std::move(__out), _S_str_d2(__buf, __i)); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_M(chrono::minutes __m, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter> + _OutIter + _M_M(chrono::minutes __m, _OutIter __out) const { // %M The minute as a decimal number. // %OM Locale's alternative representation. @@ -1458,10 +1449,9 @@ namespace __format return __format::__write(std::move(__out), _S_two_digits(__i)); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_p(chrono::hours __h, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_p(chrono::hours __h, _OutIter __out, _FormatContext& __ctx) const { // %p The locale's equivalent of the AM/PM designations. auto __hi = __h.count(); @@ -1475,27 +1465,26 @@ namespace __format return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_q(__string_view __us, typename _FormatContext::iterator __out, - _FormatContext&) const + template<typename _OutIter> + _OutIter + _M_q(__string_view __us, _OutIter __out) const { // %q The duration's unit suffix return __format::__write(std::move(__out), __us); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_Q(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_Q(const _ChronoData<_CharT>& __t, _OutIter __out, + _FormatContext&) const { // %Q The duration's numeric value. return std::vformat_to(std::move(__out), _S_empty_spec, __t._M_ereps); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_r(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_r(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __ctx) const { // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p @@ -1516,10 +1505,10 @@ namespace __format return _M_p(__t._M_hours, std::move(__out), __ctx); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_R_X(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, bool __secs) const + template<typename _OutIter> + _OutIter + _M_R_X(const _ChronoData<_CharT>& __t, _OutIter __out, + bool __secs) const { // %R Equivalent to %H:%M // %X Locale's time rep, for C-locale: %H:%M:%S (without subseconds) @@ -1549,9 +1538,9 @@ namespace __format return __format::__write(std::move(__out), __sv); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_S(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_S(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __ctx, bool __subs = true) const { // %S Seconds as a decimal number. @@ -1565,10 +1554,9 @@ namespace __format return __out; } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_subsecs(const _ChronoData<_CharT>& __t, - typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __ctx) const { unsigned __prec = _M_spec._M_prec_kind != _WP_none @@ -1628,20 +1616,19 @@ namespace __format // %t handled in _M_format - template<typename _FormatContext> - typename _FormatContext::iterator - _M_T(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_T(const _ChronoData<_CharT>& __t, _OutIter __out, _FormatContext& __ctx) const { // %T Equivalent to %H:%M:%S, with subseconds - __out = _M_R_X(__t, std::move(__out), __ctx, true); + __out = _M_R_X(__t, std::move(__out), true); return _M_subsecs(__t, std::move(__out), __ctx); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_u_w(chrono::weekday __wd, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv) const + template<typename _OutIter> + _OutIter + _M_u_w(chrono::weekday __wd, _OutIter __out, _CharT __conv) const { // %u ISO weekday as a decimal number (1-7), where Monday is 1. // %Ou Locale's alternative numeric rep. @@ -1653,10 +1640,10 @@ namespace __format return __format::__write(std::move(__out), _S_str_d1(__buf, __wdi)); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_U_V_W(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv) const + template<typename _OutIter> + _OutIter + _M_U_V_W(const _ChronoData<_CharT>& __t, _OutIter __out, + _CharT __conv) const { // %U Week number of the year as a decimal number, from first Sunday. // %OU Locale's alternative numeric rep. @@ -1686,10 +1673,9 @@ namespace __format return __format::__write(std::move(__out), __sv); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_z(chrono::seconds __ts, typename _FormatContext::iterator __out, - _FormatContext&, bool __mod = false) const + template<typename _OutIter> + _OutIter + _M_z(chrono::seconds __ts, _OutIter __out, bool __mod = false) const { if (__ts == 0s) { @@ -1711,10 +1697,9 @@ namespace __format return __format::__write(std::move(__out), __sv); } - template<typename _FormatContext> - typename _FormatContext::iterator - _M_Z(__string_view __abbrev, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + template<typename _OutIter> + _OutIter + _M_Z(__string_view __abbrev, _OutIter __out) const { return __format::__write(std::move(__out), __abbrev); } // %% handled in _M_format diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc index 923df3d813c..ef1b19d688c 100644 --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc @@ -77,15 +77,18 @@ test_padding() VERIFY( res == WIDEN("==16 is not a valid month==") ); } -template<typename Ret = void> +template<typename Ret = void, typename Under = long> struct Rep { using Return = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>; - Rep(long v = 0) : val(v) {} + Rep(Under v = 0) : val(v) {} - operator long() const + template<typename ORet, typename OUnder> + Rep(Rep<ORet, OUnder> o) : val(o.val) {} + + operator Under() const { return val; } Return @@ -119,37 +122,43 @@ struct Rep operator<<(std::basic_ostream<CharT>& os, const Rep& t) { return os << t.val << WIDEN("[via <<]"); } - long val; + Under val; +}; + +template<typename Ret, typename Under1, typename Under2> +struct std::common_type<Rep<Ret, Under1>, Rep<Ret, Under2>> +{ + using type = Rep<Ret, std::common_type_t<Under1, Under2>>; }; -template<typename Ret, typename Other> +template<typename Ret, typename Under, typename Other> requires std::is_integral_v<Other> -struct std::common_type<Rep<Ret>, Other> +struct std::common_type<Rep<Ret, Under>, Other> { - using type = Rep<Ret>; + using type = Rep<Ret, std::common_type_t<Under, Other>>; }; -template<typename Ret, typename Other> +template<typename Ret, typename Under, typename Other> requires std::is_integral_v<Other> -struct std::common_type<Other, Rep<Ret>> - : std::common_type<Rep<Ret>, Other> +struct std::common_type<Other, Rep<Ret, Under>> + : std::common_type<Rep<Ret, Under>, Other> { }; -template<typename Ret> -struct std::numeric_limits<Rep<Ret>> - : std::numeric_limits<long> +template<typename Ret, typename Under> +struct std::numeric_limits<Rep<Ret, Under>> + : std::numeric_limits<Under> { }; -template<typename Ret, typename CharT> -struct std::formatter<Rep<Ret>, CharT> - : std::formatter<long, CharT> +template<typename Ret, typename Under, typename CharT> +struct std::formatter<Rep<Ret, Under>, CharT> + : std::formatter<Under, CharT> { template<typename Out> typename std::basic_format_context<Out, CharT>::iterator format(const Rep<Ret>& t, std::basic_format_context<Out, CharT>& ctx) const { constexpr std::basic_string_view<CharT> suffix = WIDEN("[via format]"); - auto out = std::formatter<long, CharT>::format(t.val, ctx); + auto out = std::formatter<Under, CharT>::format(t.val, ctx); return std::ranges::copy(suffix, out).out; } }; -- 2.49.0