[gcc r13-9074] libstdc++: Fix formatting of most negative chrono::duration [PR116755]
Jonathan Wakely
redi@gcc.gnu.org
Thu Oct 3 23:20:18 GMT 2024
https://gcc.gnu.org/g:7ea30d4a5b211cc8ddda8f7f33bb2308b681be74
commit r13-9074-g7ea30d4a5b211cc8ddda8f7f33bb2308b681be74
Author: Jonathan Wakely <jwakely@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 d63f7c40d838..37ede63a53eb 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -1609,8 +1609,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 b7028a4e6c62..6a5e12a85971 100644
--- a/libstdc++-v3/testsuite/20_util/duration/io.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/io.cc
@@ -107,6 +107,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 );
}
int main()
More information about the Libstdc++-cvs
mailing list