https://gcc.gnu.org/g:ac0a04b7a254fb8e1d8d7088336bcb4375807b1e

commit r16-1099-gac0a04b7a254fb8e1d8d7088336bcb4375807b1e
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Wed Jun 4 11:05:11 2025 +0200

    libstdc++: Fix format call and test formatting with empty specs for 
durations.
    
    This patches fixes an obvious error, where the output iterator argument was
    missing for call to format_to, when duration with custom representation 
types
    are used.
    
    It's also adding the test for behavior of ostream operator and the 
formatting
    with empty chron-spec for the chrono types. Current coverage is:
     * duration and hh_mm_ss in this commit,
     * calendar types in r16-1016-g28a17985dd34b7.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/chrono_io.h (__formatter_chrono:_M_s): Add missing
            __out argument to format_to call.
            * testsuite/std/time/format/empty_spec.cc: New test.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/chrono_io.h              |   3 +-
 .../testsuite/std/time/format/empty_spec.cc        | 271 +++++++++++++++++++++
 2 files changed, 273 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h 
b/libstdc++-v3/include/bits/chrono_io.h
index 346eb8b3c33b..239f9c780094 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -1296,7 +1296,8 @@ namespace __format
                  else
                    {
                      auto __str = std::format(_S_empty_spec, __ss.count());
-                     __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),
+                     __out = std::format_to(std::move(__out),
+                                            _GLIBCXX_WIDEN("{:0>{}s}"),
                                             __str,
                                             __hms.fractional_width);
                    }
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc 
b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
index 322faa1939d9..46942dc30fc6 100644
--- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
@@ -1,7 +1,9 @@
 // { dg-do run { target c++20 } }
+// { dg-require-effective-target hosted }
 // { dg-timeout-factor 2 }
 
 #include <chrono>
+#include <ranges>
 #include <sstream>
 #include <testsuite_hooks.h>
 
@@ -49,6 +51,274 @@ void verify(const T& t, const _CharT* str)
   VERIFY( res == str );
 }
 
+template<typename Ret = void>
+struct Rep
+{
+  using Return
+    = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>;
+
+  Rep(long v = 0) : val(v) {}
+
+  operator long() const
+  { return val; }
+
+  Return
+  operator+() const
+  { return val; }
+
+  Rep
+  operator-() const
+  { return -val; }
+
+  friend Rep
+  operator+(Rep lhs, Rep rhs)
+  { return lhs.val + rhs.val; }
+
+  friend Rep
+  operator-(Rep lhs, Rep rhs)
+  { return lhs.val - rhs.val; }
+
+  friend Rep
+  operator*(Rep lhs, Rep rhs)
+  { return lhs.val * rhs.val; }
+
+  friend Rep
+  operator/(Rep lhs, Rep rhs)
+  { return lhs.val / rhs.val; }
+
+  friend auto operator<=>(Rep, Rep) = default;
+
+  template<typename _CharT>
+  friend std::basic_ostream<_CharT>&
+  operator<<(std::basic_ostream<_CharT>& os, const Rep& t)
+  { return os << t.val << WIDEN("[via <<]"); }
+
+  long val;
+};
+
+template<typename Ret, typename Other>
+  requires std::is_integral_v<Other>
+struct std::common_type<Rep<Ret>, Other>
+{
+  using type = Rep<Ret>;
+};
+
+template<typename Ret, typename Other>
+  requires std::is_integral_v<Other>
+struct std::common_type<Other, Rep<Ret>>
+  : std::common_type<Rep<Ret>, Other>
+{ };
+
+template<typename Ret>
+struct std::numeric_limits<Rep<Ret>>
+  : std::numeric_limits<long>
+{ };
+
+template<typename Ret, typename _CharT>
+struct std::formatter<Rep<Ret>, _CharT>
+  : std::formatter<long, _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);
+    return std::ranges::copy(suffix, out).out;
+  }
+};
+
+using deciseconds = duration<seconds::rep, std::deci>;
+
+template<typename _CharT>
+void
+test_duration()
+{
+  std::basic_string<_CharT> res;
+
+  const milliseconds di(40);
+  verify( di, WIDEN("40ms") );
+  res = std::format(WIDEN("{:>6}"), di);
+  VERIFY( res == WIDEN("  40ms") );
+
+  verify( -di, WIDEN("-40ms") );
+  res = std::format(WIDEN("{:>6}"), -di);
+  VERIFY( res == WIDEN(" -40ms") );
+
+  const duration<double> df(11.22);
+  verify( df, WIDEN("11.22s") );
+  res = std::format(WIDEN("{:=^12}"), df);
+  VERIFY( res == WIDEN("===11.22s===") );
+
+  verify( -df, WIDEN("-11.22s") );
+  res = std::format(WIDEN("{:=^12}"), -df);
+  VERIFY( res == WIDEN("==-11.22s===") );
+}
+
+template<typename _CharT>
+void
+test_duration_cust()
+{
+  std::basic_string<_CharT> res;
+  const duration<char, std::ratio<1, 10>> charRep(123);
+  verify( charRep, WIDEN("123ds") );
+
+  // +asLong returns long, so formatted as long
+  const duration<Rep<long>> asLong(20);
+  verify( asLong, WIDEN("20s") );
+  res = std::format(WIDEN("{:>6}"), asLong);
+  VERIFY( res == WIDEN("   20s") );
+
+  verify( -asLong, WIDEN("-20s") );
+  res = std::format(WIDEN("{:>6}"), -asLong);
+  VERIFY( res == WIDEN("  -20s") );
+
+  res = std::format(WIDEN("{:%Q}"), asLong);
+  VERIFY( res == WIDEN("20") );
+  res = std::format(WIDEN("{:+<7%Q}"), asLong);
+  VERIFY( res == WIDEN("20+++++") );
+
+  // +asRep returns Rep<>, so formatted as Rep<>
+  const duration<Rep<>> asRep(10);
+  verify( asRep, WIDEN("10[via <<]s") );
+  res = std::format(WIDEN("{:=^15}"), asRep);
+  VERIFY( res == WIDEN("==10[via <<]s==") );
+
+  verify( -asRep, WIDEN("-10[via <<]s") );
+  res = std::format(WIDEN("{:=^15}"), -asRep);
+  VERIFY( res == WIDEN("=-10[via <<]s==") );
+
+  res = std::format(WIDEN("{:%Q}"), asRep);
+  VERIFY( res == WIDEN("10[via format]") );
+  res = std::format(WIDEN("{:=^18%Q}"), asRep);
+  VERIFY( res == WIDEN("==10[via format]==") );
+
+  const duration<Rep<>, std::milli> milliRep(10);
+  verify( milliRep, WIDEN("10[via <<]ms") );
+  res = std::format(WIDEN("{:=^15}"), milliRep);
+  VERIFY( res == WIDEN("=10[via <<]ms==") );
+
+  verify( -milliRep, WIDEN("-10[via <<]ms") );
+  res = std::format(WIDEN("{:=^15}"), -milliRep);
+  VERIFY( res == WIDEN("=-10[via <<]ms=") );
+
+  res = std::format(WIDEN("{:%Q}"), milliRep);
+  VERIFY( res == WIDEN("10[via format]") );
+  res = std::format(WIDEN("{:=^18%Q}"), milliRep);
+  VERIFY( res == WIDEN("==10[via format]==") );
+}
+
+template<typename Ratio, typename Rep, typename Period>
+constexpr auto
+hms(const duration<Rep, Period>& d)
+{
+  using Dur = duration<Rep, typename Ratio::period>;
+  return hh_mm_ss<Dur>(duration_cast<Dur>(d));
+}
+
+template<typename _CharT>
+void
+test_hh_mm_ss()
+{
+  auto dt = 22h + 24min + 54s + 111222333ns;
+  verify( hms<nanoseconds>(dt),
+         WIDEN("22:24:54.111222333") );
+  verify( hms<microseconds>(dt),
+         WIDEN("22:24:54.111222") );
+  verify( hms<milliseconds>(dt),
+         WIDEN("22:24:54.111") );
+  verify( hms<deciseconds>(dt),
+         WIDEN("22:24:54.1") );
+  verify( hms<seconds>(dt),
+         WIDEN("22:24:54") );
+  verify( hms<minutes>(dt),
+         WIDEN("22:24:00") );
+  verify( hms<hours>(dt),
+         WIDEN("22:00:00") );
+  verify( hms<nanoseconds>(-dt),
+         WIDEN("-22:24:54.111222333") );
+  verify( hms<microseconds>(-dt),
+         WIDEN("-22:24:54.111222") );
+  verify( hms<milliseconds>(-dt),
+         WIDEN("-22:24:54.111") );
+  verify( hms<deciseconds>(-dt),
+         WIDEN("-22:24:54.1") );
+  verify( hms<seconds>(-dt),
+         WIDEN("-22:24:54") );
+  verify( hms<minutes>(-dt),
+         WIDEN("-22:24:00") );
+  verify( hms<hours>(-dt),
+         WIDEN("-22:00:00") );
+
+  verify( hms<nanoseconds>(-dt),
+         WIDEN("-22:24:54.111222333") );
+
+  dt += 300h;
+  verify( hms<nanoseconds>(dt),
+         WIDEN("322:24:54.111222333") );
+  verify( hms<nanoseconds>(-dt),
+         WIDEN("-322:24:54.111222333") );
+
+  dt += 14000h;
+  verify( hms<nanoseconds>(dt),
+         WIDEN("14322:24:54.111222333") );
+  verify( hms<nanoseconds>(-dt),
+         WIDEN("-14322:24:54.111222333") );
+}
+
+template<typename _CharT>
+void
+test_hh_mm_ss_cust()
+{
+  const duration<char, deciseconds::period> charRep(123);
+  verify( hms<deciseconds>(charRep),
+         WIDEN("00:00:12.3") );
+  verify( hms<seconds>(charRep),
+         WIDEN("00:00:12") );
+
+  auto dt = 22h + 24min + 54s + 123ms;
+  // +plus returns long, so formatted as long
+  const duration<Rep<long>, std::milli> asLong(dt.count());
+  verify( hms<milliseconds>(asLong),
+         WIDEN("22:24:54.123[via format]") );
+  verify( hms<deciseconds>(asLong),
+         WIDEN("22:24:54.1[via format]") );
+  verify( hms<seconds>(asLong),
+         WIDEN("22:24:54") );
+  verify( hms<milliseconds>(-asLong),
+         WIDEN("-22:24:54.123[via format]") );
+  verify( hms<deciseconds>(-asLong),
+         WIDEN("-22:24:54.1[via format]") );
+  verify( hms<seconds>(-asLong),
+         WIDEN("-22:24:54") );
+
+  // +asRep returns Rep<>, so formatted as Rep<>
+  const duration<Rep<>, std::milli> asRep(dt.count());
+  verify( hms<milliseconds>(asRep),
+         WIDEN("22:24:54.123[via format]") );
+  verify( hms<deciseconds>(asRep),
+         WIDEN("22:24:54.1[via format]") );
+  verify( hms<seconds>(asLong),
+         WIDEN("22:24:54") );
+  verify( hms<milliseconds>(-asLong),
+         WIDEN("-22:24:54.123[via format]") );
+  verify( hms<deciseconds>(-asLong),
+         WIDEN("-22:24:54.1[via format]") );
+  verify( hms<seconds>(-asLong),
+         WIDEN("-22:24:54") );
+}
+
+template<typename CharT>
+void
+test_durations()
+{
+  test_duration<CharT>();
+  test_duration_cust<CharT>();
+
+  test_hh_mm_ss<CharT>();
+  test_hh_mm_ss_cust<CharT>();
+}
+
 template<typename _CharT>
 void
 test_day()
@@ -288,6 +558,7 @@ void
 test_all()
 {
   test_padding<CharT>();
+  test_durations<CharT>();
   test_calendar<CharT>();
 }

Reply via email to