<div dir="ltr"><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">Am Mi., 4. Juni 2025 um 11:27 Uhr schrieb Tomasz Kamiński <<a href="mailto:tkaminsk@redhat.com">tkaminsk@redhat.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This patches fixes an obvious error, where the output iterator argument was<br>
missing for call to format_to, when duration with custom representation types<br>
are used.<br>
<br>
It's also adding the test for behavior of ostream operator and the formatting<br>
with empty chron-spec for the chrono types. Current coverage is:<br>
* duration and hh_mm_ss in this commit,<br>
* calendar types in r16-1016-g28a17985dd34b7.<br>
<br>
libstdc++-v3/ChangeLog:<br>
<br>
* include/bits/chrono_io.h (__formatter_chrono:_M_s): Add missing<br>
__out argument to format_to call.<br>
* testsuite/std/time/format/empty_spec.cc: New test.<br>
---<br>
Tested on x86_64-linux. OK for trunk?<br>
<br>
libstdc++-v3/include/bits/chrono_io.h | 3 +-<br>
.../testsuite/std/time/format/empty_spec.cc | 271 ++++++++++++++++++<br>
2 files changed, 273 insertions(+), 1 deletion(-)<br>
<br>
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h<br>
index 346eb8b3c33..239f9c78009 100644<br>
--- a/libstdc++-v3/include/bits/chrono_io.h<br>
+++ b/libstdc++-v3/include/bits/chrono_io.h<br>
@@ -1296,7 +1296,8 @@ namespace __format<br>
else<br>
{<br>
auto __str = std::format(_S_empty_spec, __ss.count());<br>
- __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),<br>
+ __out = std::format_to(std::move(__out),<br>
+ _GLIBCXX_WIDEN("{:0>{}s}"),<br>
__str,<br>
__hms.fractional_width);<br>
}<br>
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc<br>
index 322faa1939d..46942dc30fc 100644<br>
--- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc<br>
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc<br>
@@ -1,7 +1,9 @@<br>
// { dg-do run { target c++20 } }<br>
+// { dg-require-effective-target hosted }<br>
// { dg-timeout-factor 2 }<br>
<br>
#include <chrono><br>
+#include <ranges><br>
#include <sstream><br>
#include <testsuite_hooks.h><br>
<br>
@@ -49,6 +51,274 @@ void verify(const T& t, const _CharT* str)<br>
VERIFY( res == str );<br>
}<br>
<br>
+template<typename Ret = void><br>
+struct Rep<br>
+{<br>
+ using Return<br>
+ = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>;<br>
+<br>
+ Rep(long v = 0) : val(v) {}<br>
+<br>
+ operator long() const<br>
+ { return val; }<br>
+<br>
+ Return<br>
+ operator+() const<br>
+ { return val; }<br>
+<br>
+ Rep<br>
+ operator-() const<br>
+ { return -val; }<br>
+<br>
+ friend Rep<br>
+ operator+(Rep lhs, Rep rhs)<br>
+ { return lhs.val + rhs.val; }<br>
+<br>
+ friend Rep<br>
+ operator-(Rep lhs, Rep rhs)<br>
+ { return lhs.val - rhs.val; }<br>
+<br>
+ friend Rep<br>
+ operator*(Rep lhs, Rep rhs)<br>
+ { return lhs.val * rhs.val; }<br>
+<br>
+ friend Rep<br>
+ operator/(Rep lhs, Rep rhs)<br>
+ { return lhs.val / rhs.val; }<br>
+<br>
+ friend auto operator<=>(Rep, Rep) = default;<br>
+<br>
+ template<typename _CharT><br>
+ friend std::basic_ostream<_CharT>&<br>
+ operator<<(std::basic_ostream<_CharT>& os, const Rep& t)<br>
+ { return os << t.val << WIDEN("[via <<]"); }<br>
+<br>
+ long val;<br>
+};<br>
+<br>
+template<typename Ret, typename Other><br>
+ requires std::is_integral_v<Other><br>
+struct std::common_type<Rep<Ret>, Other><br>
+{<br>
+ using type = Rep<Ret>;<br>
+};<br>
+<br>
+template<typename Ret, typename Other><br>
+ requires std::is_integral_v<Other><br>
+struct std::common_type<Other, Rep<Ret>><br>
+ : std::common_type<Rep<Ret>, Other><br>
+{ };<br></blockquote><div><br></div><div>Why is this second specialization needed? It seems to me that [meta.trans.other] p5 says that it is already provided by the library implementation of
std::common_type.</div><div><br></div><div>- Daniel</div><div> </div><br></div></div>