-
Notifications
You must be signed in to change notification settings - Fork 11.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++][chrono] Fixes (sys|local)_time formatters. #76456
Conversation
2bda353
to
f15db9f
Compare
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) Changes
Patch is 29.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76456.diff 7 Files Affected:
diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h
index f171944b5cab3d..b687ef8059d5f5 100644
--- a/libcxx/include/__chrono/ostream.h
+++ b/libcxx/include/__chrono/ostream.h
@@ -42,11 +42,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace chrono {
template <class _CharT, class _Traits, class _Duration>
+ requires(!treat_as_floating_point_v<typename _Duration::rep> && _Duration{1} < days{1})
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
-operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration> __tp) {
+operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration>& __tp) {
return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
}
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) {
+ return __os << year_month_day{__dp};
+}
+
template <class _CharT, class _Traits, class _Duration>
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const file_time<_Duration> __tp) {
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index b3ed9acc5e5deb..c80fa78a56ba1b 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -296,6 +296,10 @@ template<class charT, class traits, class Duration> // C++20
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const sys_time<Duration>& tp);
+template<class charT, class traits> // C++20
+ basic_ostream<charT, traits>&
+ operator<<(basic_ostream<charT, traits>& os, const sys_days& dp);
+
class file_clock // C++20
{
public:
diff --git a/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
index 4f4fd3f40e23bc..9fdef8d5adc782 100644
--- a/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
@@ -75,9 +75,11 @@ static void test_c() {
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::minutes>{20'576'131min}) ==
SV("2009-02-13 23:31:00"));
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::hours>{342'935h}) == SV("2009-02-13 23:00:00"));
- assert(stream_c_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13 00:00:00"));
+
+ // These switch to sys_day formatter, which omits the time.
+ assert(stream_c_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13"));
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::weeks>{std::chrono::weeks{2041}}) ==
- SV("2009-02-12 00:00:00"));
+ SV("2009-02-12"));
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
@@ -89,13 +91,6 @@ static void test_c() {
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01.1"));
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:30.10"));
-
- assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::duration<float, std::ratio<1, 1>>>{
- std::chrono::duration<float, std::ratio<1, 1>>{123.456}}) == SV("1970-01-01 00:02:03"));
- assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::duration<double, std::ratio<1, 10>>>{
- std::chrono::duration<double, std::ratio<1, 10>>{123.456}}) == SV("1970-01-01 00:00:12.3"));
- assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::duration<long double, std::ratio<1, 100>>>{
- std::chrono::duration<long double, std::ratio<1, 100>>{123.456}}) == SV("1970-01-01 00:00:01.23"));
}
template <class CharT>
@@ -114,9 +109,11 @@ static void test_fr_FR() {
SV("2009-02-13 23:31:00"));
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::hours>{342'935h}) ==
SV("2009-02-13 23:00:00"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13 00:00:00"));
+
+ // These switch to sys_day formatter, which omits the time.
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13"));
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::weeks>{std::chrono::weeks{2041}}) ==
- SV("2009-02-12 00:00:00"));
+ SV("2009-02-12"));
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
@@ -128,13 +125,6 @@ static void test_fr_FR() {
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01,1"));
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:30,10"));
-
- assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::duration<float, std::ratio<1, 1>>>{
- std::chrono::duration<float, std::ratio<1, 1>>{123.456}}) == SV("1970-01-01 00:02:03"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::duration<double, std::ratio<1, 10>>>{
- std::chrono::duration<double, std::ratio<1, 10>>{123.456}}) == SV("1970-01-01 00:00:12,3"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::duration<long double, std::ratio<1, 100>>>{
- std::chrono::duration<long double, std::ratio<1, 100>>{123.456}}) == SV("1970-01-01 00:00:01,23"));
}
template <class CharT>
@@ -153,9 +143,11 @@ static void test_ja_JP() {
SV("2009-02-13 23:31:00"));
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::hours>{342'935h}) ==
SV("2009-02-13 23:00:00"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13 00:00:00"));
+
+ // These switch to sys_day formatter, which omits the time.
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_days{std::chrono::days{14'288}}) == SV("2009-02-13"));
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::weeks>{std::chrono::weeks{2041}}) ==
- SV("2009-02-12 00:00:00"));
+ SV("2009-02-12"));
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
@@ -167,13 +159,6 @@ static void test_ja_JP() {
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01.1"));
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:30.10"));
-
- assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::duration<float, std::ratio<1, 1>>>{
- std::chrono::duration<float, std::ratio<1, 1>>{123.456}}) == SV("1970-01-01 00:02:03"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::duration<double, std::ratio<1, 10>>>{
- std::chrono::duration<double, std::ratio<1, 10>>{123.456}}) == SV("1970-01-01 00:00:12.3"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::duration<long double, std::ratio<1, 100>>>{
- std::chrono::duration<long double, std::ratio<1, 100>>{123.456}}) == SV("1970-01-01 00:00:01.23"));
}
template <class CharT>
diff --git a/libcxx/test/std/time/time.clock/time.clock.local/ostream.verify.cpp b/libcxx/test/std/time/time.clock/time.clock.local/ostream.verify.cpp
new file mode 100644
index 00000000000000..a3051c2f3ddedc
--- /dev/null
+++ b/libcxx/test/std/time/time.clock/time.clock.local/ostream.verify.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-localization
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// TODO FMT This test should not require std::to_chars(floating-point)
+// XFAIL: availability-fp_to_chars-missing
+
+// <chrono>
+
+// class system_clock;
+
+// template<class charT, class traits, class Duration>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const local_time<Duration>& tp);
+
+// The function uses the system_clock which has two overloads
+
+// template<class charT, class traits, class Duration>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const sys_time<Duration>& tp);
+// Constraints: treat_as_floating_point_v<typename Duration::rep> is false, and Duration{1} < days{1} is true.
+
+// template<class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const sys_days& dp);
+
+#include <chrono>
+#include <ratio>
+#include <sstream>
+#include <type_traits>
+
+void test() {
+ std::stringstream sstr;
+
+ // floating-point values
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::duration<float, std::ratio<1, 1>>>{
+ std::chrono::duration<float, std::ratio<1, 1>>{0}};
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::duration<double, std::ratio<1, 1>>>{
+ std::chrono::duration<double, std::ratio<1, 1>>{0}};
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::duration<long double, std::ratio<1, 1>>>{
+ std::chrono::duration<long double, std::ratio<1, 1>>{0}};
+
+ // duration >= day
+
+ sstr << // valid since day has its own formatter
+ std::chrono::local_days{std::chrono::days{0}};
+
+ using rep = std::conditional_t<std::is_same_v<std::chrono::days::rep, int>, long, int>;
+ sstr << // a different rep does not matter,
+ std::chrono::local_time<std::chrono::duration<rep, std::ratio<86400>>>{
+ std::chrono::duration<rep, std::ratio<86400>>{0}};
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::duration<typename std::chrono::days::rep, std::ratio<86401>>>{
+ std::chrono::duration<typename std::chrono::days::rep, std::ratio<86401>>{0}};
+
+ sstr << // These are considered days.
+ std::chrono::local_time<std::chrono::weeks>{std::chrono::weeks{3}};
+
+ sstr << // These too.
+ std::chrono::local_time<std::chrono::duration<rep, std::ratio<20 * 86400>>>{
+ std::chrono::duration<rep, std::ratio<20 * 86400>>{0}};
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::months>{std::chrono::months{0}};
+
+ sstr << // expected-error@*:* {{invalid operands to binary expression}}
+ std::chrono::local_time<std::chrono::years>{std::chrono::years{0}};
+}
diff --git a/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp
new file mode 100644
index 00000000000000..7af3ebf7768072
--- /dev/null
+++ b/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp
@@ -0,0 +1,175 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-localization
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// TODO FMT This test should not require std::to_chars(floating-point)
+// XFAIL: availability-fp_to_chars-missing
+
+// TODO FMT Investigate Windows issues.
+// XFAIL: msvc
+
+// REQUIRES: locale.fr_FR.UTF-8
+// REQUIRES: locale.ja_JP.UTF-8
+
+// <chrono>
+
+// class system_Clock;
+
+// template<class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const sys_days& dp);
+
+#include <cassert>
+#include <chrono>
+#include <ratio>
+#include <sstream>
+
+#include "make_string.h"
+#include "platform_support.h" // locale name macros
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+
+#define TEST_EQUAL(OUT, EXPECTED) \
+ TEST_REQUIRE(OUT == EXPECTED, \
+ TEST_WRITE_CONCATENATED( \
+ "\nExpression ", #OUT, "\nExpected output ", EXPECTED, "\nActual output ", OUT, '\n'));
+
+template <class CharT>
+static std::basic_string<CharT> stream_c_locale(const std::chrono::sys_days& dp) {
+ std::basic_stringstream<CharT> sstr;
+ sstr << dp;
+ return sstr.str();
+}
+
+template <class CharT>
+static std::basic_string<CharT> stream_fr_FR_locale(const std::chrono::sys_days& dp) {
+ std::basic_stringstream<CharT> sstr;
+ const std::locale locale(LOCALE_fr_FR_UTF_8);
+ sstr.imbue(locale);
+ sstr << dp;
+ return sstr.str();
+}
+
+template <class CharT>
+static std::basic_string<CharT> stream_ja_JP_locale(const std::chrono::sys_days& dp) {
+ std::basic_stringstream<CharT> sstr;
+ const std::locale locale(LOCALE_ja_JP_UTF_8);
+ sstr.imbue(locale);
+ sstr << dp;
+ return sstr.str();
+}
+
+template <class CharT>
+static void test() {
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{-32'768}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("-32768-01-01 is not a valid date"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("1970-01-01"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
+ SV("2000-02-29"));
+
+#if defined(_AIX)
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("+32767-12-31"));
+#elif defined(_WIN32) // defined(_AIX)
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV(""));
+#else // defined(_AIX)
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("32767-12-31"));
+#endif // defined(_AIX)
+
+ // multiples of days are considered days.
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
+ SV("1970-01-22"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::duration<int, std::ratio<30 * 86400>>>{
+ std::chrono::duration<int, std::ratio<30 * 86400>>{1}}),
+ SV("1970-01-31"));
+
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{-32'768}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("-32768-01-01 is not a valid date"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("1970-01-01"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
+ SV("2000-02-29"));
+#if defined(_AIX)
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("+32767-12-31"));
+#elif defined(_WIN32) // defined(_AIX)
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV(""));
+#else // defined(_AIX)
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("32767-12-31"));
+#endif // defined(_AIX)
+
+ // multiples of days are considered days.
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
+ SV("1970-01-22"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::duration<int, std::ratio<30 * 86400>>>{
+ std::chrono::duration<int, std::ratio<30 * 86400>>{1}}),
+ SV("1970-01-31"));
+
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{-32'768}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("-32768-01-01 is not a valid date"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{1}, std::chrono::day{1}}}),
+ SV("1970-01-01"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
+ SV("2000-02-29"));
+#if defined(_AIX)
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("+32767-12-31"));
+#elif defined(_WIN32) // defined(_AIX)
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV(""));
+#else // defined(_AIX)
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
+ std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
+ SV("32767-12-31"));
+#endif // defined(_AIX)
+
+ // multiples of days are considered days.
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
+ SV("1970-01-22"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::duration<int, std::ratio<30 * 86400>>>{
+ std::chrono::duration<int, std::ratio<30 * 86400>>{1}}),
+ SV("1970-01-31"));
+}
+
+int main(int, char**) {
+ test<char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/s...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM w/ comments!
#include <sstream> | ||
#include <type_traits> | ||
|
||
void test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to test that operator<<
has the appropriate constraints, which means that it needs to be SFINAE friendly. In other words, you want to test this via something like
template <class T>
concept is_ostreamable = requires (std::stringstream& sstr, T const& val) {
{ sstr << val; }
};
static_assert(!is_ostreamable<decltype(your-expression)>);
And at that point, this can be moved to ostream.pass.cpp
or to a separate ostream.compile.pass.cpp
(but really I think I'd leave it in the existing .pass.cpp
as nothing more than an additional test case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually that won't work. The operator<<
is not constrained. For sys_time
the operator<<
is constrained. But this operator is defined as
Effects: os << sys_time<Duration>{lt.time_since_epoch()};
Note the wording is Effects:
not Effects: Equivalent to
, the latter would constrain the function, the former doesn't. Both MSVC STL and libstdc++ agree; local_time can not be SFINAE tested, system_time can. I'll leave a comment in the code instead.
At the LWG reflector Jonathan brought up a discussion about this issue and I've added this information. For now I want to see how that discussion pans out and whether an LWG issue should be filed.
TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{ | ||
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}), | ||
SV("+32767-12-31")); | ||
#elif defined(_WIN32) // defined(_AIX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, but I find these defined (_AIX)
comments kinda confusing since only the first block pertains to _AIX
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not disagreeing, but this seems the style quite often used in libc++.
|
||
// class system_clock; | ||
|
||
// template<class charT, class traits, class Duration> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here for using SFINAE. I see that for a few expressions, you ensure that they work instead of not working. For those, we should also test them positively in static_assert(is_ostreamable<expression>)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll SFINAE these, this function is indeed constrained.
- The sys_time formatter is constrained, which was not implemented. - There is a sys_days formatter which was not implemented. - The local_time formatter uses the sys_time formatter in its implementation so "inherited" the same issues. Fixes: llvm#73849 Fixes: llvm#67983
f15db9f
to
58f229a
Compare
Can we merge this into |
|
AFAIK It already is in 18.x. |
There will be no new LLVM 17 releases anymore. The LLVM project only maintains 1 release branch. |
Fixes: #73849
Fixes: #67983