On Fri, Jun 27, 2025 at 1:03 PM Tomasz Kamiński <tkami...@redhat.com> wrote:
> 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 shorcut 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 changs to shipping code are necessary. > > Secondly, extacting _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_f) > > 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: > This now says: * testsuite/std/time/format/empty_spec.cc: Make underlying type for Rep configurable. > --- > Still testing, but the warning in empty_spec.cc file disapeared when > using -m32. > > libstdc++-v3/include/bits/chrono_io.h | 219 ++++++++---------- > .../testsuite/std/time/format/empty_spec.cc | 43 ++-- > 2 files changed, 128 insertions(+), 134 deletions(-) > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index bcfd51b9866..03f58c8a264 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,9 +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, > + 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. > @@ -1475,27 +1466,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 +1506,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 +1539,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 +1555,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 +1617,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 +1641,9 @@ 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 > >