https://gcc.gnu.org/g:aeb54d0f3a9eb9363157a040beaddd4939bd4774
commit r14-10732-gaeb54d0f3a9eb9363157a040beaddd4939bd4774 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Sep 18 17:20:29 2024 +0100 libstdc++: Fix formatting of most negative chrono::duration [PR116755] When formatting chrono::duration<signed-integer-type, P>::min() we were causing undefined behaviour by trying to form the negative of the most negative value. If we convert negative durations with integer rep to the corresponding unsigned integer rep then we can safely represent all values. libstdc++-v3/ChangeLog: PR libstdc++/116755 * include/bits/chrono_io.h (formatter<duration<R,P>>::format): Cast negative integral durations to unsigned rep. * testsuite/20_util/duration/io.cc: Test the most negative integer durations. (cherry picked from commit 482e651f5750e4648ade90e32ed45b094538e7f8) Diff: --- libstdc++-v3/include/bits/chrono_io.h | 16 ++++++++++++++-- libstdc++-v3/testsuite/20_util/duration/io.cc | 8 ++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 72c66a0fef0d..f8b78daedc65 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -1608,8 +1608,20 @@ namespace __format basic_format_context<_Out, _CharT>& __fc) const { if constexpr (numeric_limits<_Rep>::is_signed) - if (__d < __d.zero()) - return _M_f._M_format(-__d, __fc, true); + if (__d < __d.zero()) [[unlikely]] + { + if constexpr (is_integral_v<_Rep>) + { + // -d is undefined for the most negative integer. + // Convert duration to corresponding unsigned rep. + using _URep = make_unsigned_t<_Rep>; + auto __ucnt = -static_cast<_URep>(__d.count()); + auto __ud = chrono::duration<_URep, _Period>(__ucnt); + return _M_f._M_format(__ud, __fc, true); + } + else + return _M_f._M_format(-__d, __fc, true); + } return _M_f._M_format(__d, __fc, false); } diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc index 6b00689672c8..57020f4f9537 100644 --- a/libstdc++-v3/testsuite/20_util/duration/io.cc +++ b/libstdc++-v3/testsuite/20_util/duration/io.cc @@ -106,6 +106,14 @@ test_format() VERIFY( s == "500ms" ); s = std::format("{:%Q %q}", u); VERIFY( s == "500 ms" ); + + // PR libstdc++/116755 extra minus sign for most negative value + auto minsec = std::chrono::seconds::min(); + s = std::format("{}", minsec); + auto expected = std::format("{}s", minsec.count()); + VERIFY( s == expected ); + s = std::format("{:%Q%q}", minsec); + VERIFY( s == expected ); } void