diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 362bb5aa9e98df8d5fd217daff589cb299eaa1a3..a337007266e936cdcd77a0f5c32b7881e5e9a4db 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -150,7 +150,9 @@ namespace __detail __s.flags(__os.flags()); __s.imbue(__os.getloc()); __s.precision(__os.precision()); - __s << __d.count(); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4118. How should duration formatters format custom rep types? + __s << +__d.count(); __detail::__fmt_units_suffix<period, _CharT>(_Out(__s)); __os << std::move(__s).str(); return __os; @@ -635,8 +637,10 @@ namespace __format case 'Q': // %Q The duration's numeric value. if constexpr (chrono::__is_duration_v<_Tp>) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4118. How should duration formatters format custom rep? __out = std::format_to(__print_sign(), _S_empty_spec, - __t.count()); + +__t.count()); else __throw_format_error("chrono format error: argument is " "not a duration"); @@ -1703,6 +1707,7 @@ namespace __format /// @endcond template<typename _Rep, typename _Period, typename _CharT> + requires __format::__formattable_impl<_Rep, _CharT> struct formatter<chrono::duration<_Rep, _Period>, _CharT> { constexpr typename basic_format_parse_context<_CharT>::iterator diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc index 57020f4f953767bf1fad7eca88d3caf9bb464834..383fb60afe2abff51575d296aa3263bf95b07dba 100644 --- a/libstdc++-v3/testsuite/20_util/duration/io.cc +++ b/libstdc++-v3/testsuite/20_util/duration/io.cc @@ -23,6 +23,24 @@ test01() VERIFY( s == "3[2]s" ); std::getline(ss, s); VERIFY( s == "9[2/3]s" ); + + // LWG 4118. How should duration formatters format custom rep types? + ss.str(""); + ss << duration<char>(121) << ' '; + ss << duration<wchar_t>(122) << ' '; + ss << duration<signed char>(123) << ' '; + ss << duration<unsigned char>(124) << ' '; + ss << duration<char8_t>(125) << ' '; + ss << duration<char16_t>(126) << ' '; + ss << duration<char32_t>(127) << ' '; + VERIFY( ss.str() == "121s 122s 123s 124s 125s 126s 127s " ); + + ss.str(""); + ss << std::hex << std::uppercase << duration<const char>(0x1A) << ' '; + ss << std::hex << std::uppercase << duration<const wchar_t>(0x2A) << ' '; + ss << std::hex << std::uppercase << duration<signed char>(0x3A) << ' '; + ss << std::scientific << duration<const double>(4.5) << ' '; + VERIFY( ss.str() == "1As 2As 3As 4.500000E+00s " ); } void @@ -44,6 +62,24 @@ test02() VERIFY( s == L"3[2]s" ); std::getline(ss, s); VERIFY( s == L"9[2/3]s" ); + + // LWG 4118. How should duration formatters format custom rep types? + ss.str(L""); + ss << duration<char>(121) << ' '; + ss << duration<wchar_t>(122) << ' '; + ss << duration<signed char>(123) << ' '; + ss << duration<unsigned char>(124) << ' '; + ss << duration<char8_t>(125) << ' '; + ss << duration<char16_t>(126) << ' '; + ss << duration<char32_t>(127) << ' '; + VERIFY( ss.str() == L"121s 122s 123s 124s 125s 126s 127s " ); + + ss.str(L""); + ss << std::hex << std::uppercase << duration<const char>(0x1A) << ' '; + ss << std::hex << std::uppercase << duration<const wchar_t>(0x2A) << ' '; + ss << std::hex << std::uppercase << duration<signed char>(0x3A) << ' '; + ss << std::scientific << duration<const double>(4.5) << ' '; + VERIFY( ss.str() == L"1As 2As 3As 4.500000E+00s " ); #endif } @@ -114,6 +150,36 @@ test_format() VERIFY( s == expected ); s = std::format("{:%Q%q}", minsec); VERIFY( s == expected ); + + // LWG 4118. How should duration formatters format custom rep types? + s = std::format("{}", std::chrono::duration<char>(100)); + VERIFY( s == "100s" ); + s = std::format("{:%Q}", std::chrono::duration<char>(101)); + VERIFY( s == "101" ); +#ifdef _GLIBCXX_USE_WCHAR_T + ws = std::format(L"{}", std::chrono::duration<char>(102)); + VERIFY( ws == L"102s" ); + ws = std::format(L"{}", std::chrono::duration<wchar_t>(103)); + VERIFY( ws == L"103s" ); +#endif + s = std::format("{}", std::chrono::duration<signed char>(50)); + VERIFY( s == "50s" ); + s = std::format("{:%Q}", std::chrono::duration<signed char>(51)); + VERIFY( s == "51" ); + s = std::format("{}", std::chrono::duration<unsigned char>(52)); + VERIFY( s == "52s" ); + s = std::format("{:%Q}", std::chrono::duration<unsigned char>(53)); + VERIFY( s == "53" ); + +#if __cplusplus > 202002L + static_assert( ! std::formattable<std::chrono::duration<wchar_t>, char> ); + static_assert( ! std::formattable<std::chrono::duration<char8_t>, char> ); + static_assert( ! std::formattable<std::chrono::duration<char16_t>, char> ); + static_assert( ! std::formattable<std::chrono::duration<char32_t>, char> ); + static_assert( ! std::formattable<std::chrono::duration<char8_t>, wchar_t> ); + static_assert( ! std::formattable<std::chrono::duration<char16_t>, wchar_t> ); + static_assert( ! std::formattable<std::chrono::duration<char32_t>, wchar_t> ); +#endif } void