From 74f494a9bc8920202b31681db2ce1e61fa446730 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Wed, 24 Sep 2025 11:54:36 -0700 Subject: [PATCH 01/13] [libcxx] Implement C++20 std::chrono::is_clock, std::chrono::is_clock_v --- libcxx/docs/ReleaseNotes/22.rst | 2 + libcxx/include/CMakeLists.txt | 1 + libcxx/include/__chrono/is_clock.h | 49 +++++++ libcxx/include/chrono | 1 + libcxx/include/module.modulemap.in | 4 + libcxx/modules/std/chrono.inc | 4 +- .../trait.is.clock.pass.cpp | 129 ++++++++++++++++++ 7 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 libcxx/include/__chrono/is_clock.h create mode 100644 libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index 509ead64ee525..b4261e474a27b 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -41,6 +41,8 @@ Implemented Papers - P2321R2: ``zip`` (`Github `__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release) - P3168R2: Give ``std::optional`` Range Support (`Github `__) +- P0355R7: ``std::chrono::is_clock`` and ``std::chrono::is_clock_v`` (`Github ` __) + (The paper is partially implemented. ``is_clock`` and ``is_clock_v`` is implemented in this release) Improvements and New Features ----------------------------- diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index e050362abb658..cb52105ab0ebd 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -262,6 +262,7 @@ set(files __chrono/gps_clock.h __chrono/hh_mm_ss.h __chrono/high_resolution_clock.h + __chrono/is_clock.h __chrono/leap_second.h __chrono/literals.h __chrono/local_info.h diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h new file mode 100644 index 0000000000000..877d31ad31176 --- /dev/null +++ b/libcxx/include/__chrono/is_clock.h @@ -0,0 +1,49 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_IS_CLOCK_H +#define _LIBCPP___CHRONO_IS_CLOCK_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +# include <__type_traits/integral_constant.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +template +struct is_clock : std::false_type {}; + +template + requires requires { + typename _Tp::rep; + typename _Tp::period; + typename _Tp::duration; + typename _Tp::time_point; + _Tp::is_steady; + _Tp::now(); + } +struct is_clock<_Tp> : std::true_type {}; + +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = is_clock<_Tp>::value; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER +#endif // _LIBCPP___CHRONO_IS_CLOCK_H diff --git a/libcxx/include/chrono b/libcxx/include/chrono index 82e99a31bcc9f..f3bb08ef386c9 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -1057,6 +1057,7 @@ constexpr chrono::year operator ""y(unsigned lo # include <__chrono/day.h> # include <__chrono/exception.h> # include <__chrono/hh_mm_ss.h> +# include <__chrono/is_clock.h> # include <__chrono/literals.h> # include <__chrono/local_info.h> # include <__chrono/month.h> diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index dc1933324ef79..e94384cbe338b 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -970,6 +970,10 @@ module std [system] { header "__chrono/high_resolution_clock.h" export * } + module is_clock { + header "__chrono/is_clock.h" + export std_core.type_traits.integral_constant + } module leap_second { header "__chrono/leap_second.h" } diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc index 66eccd8d290ad..db405d482bf9e 100644 --- a/libcxx/modules/std/chrono.inc +++ b/libcxx/modules/std/chrono.inc @@ -25,8 +25,8 @@ export namespace std { using std::chrono::duration_values; - // using std::chrono::is_clock; - // using std::chrono::is_clock_v; + using std::chrono::is_clock; + using std::chrono::is_clock_v; // [time.duration.nonmember], duration arithmetic using std::chrono::operator+; diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp new file mode 100644 index 0000000000000..1abdf255054b3 --- /dev/null +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +#include +#include + +struct EmptyStruct {}; + +// Test structs missing required members +struct MissingRep { + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +struct MissingPeriod { + using rep = long; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +struct MissingDuration { + using rep = long; + using time_point = long; + static constexpr bool is_steady = false; + static time_point now(); +}; + +struct MissingTimePoint { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + static constexpr bool is_steady = false; + static std::chrono::time_point now(); +}; + +struct MissingIsSteady { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static time_point now(); +}; + +struct MissingNow { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; +}; + +// Valid clock types +struct ValidSteadyClock { + using rep = long long; + using period = std::nano; + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = true; + static time_point now(); +}; + +struct ValidSystemClock { + using rep = int64_t; + using period = std::micro; + using duration = std::chrono::microseconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +int main(int, char**) { + // Test both is_clock and is_clock_v + static_assert(std::chrono::is_clock::value); + static_assert(std::chrono::is_clock_v); + + // Test standard clock types + static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + + // Test non-clock types + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + + // Test structs missing required members + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + + // Test valid custom clocks + static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + + // cv-qualified and reference types + static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + + // array and pointer types + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + static_assert(!std::chrono::is_clock_v); + + return 0; +} From 5fcfd586294c01d03530bd67f8e726f93411bdac Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Wed, 24 Sep 2025 21:09:26 -0700 Subject: [PATCH 02/13] Apply suggestions in libcxx/include/__chrono/is_clock.h Co-authored-by: A. Jiang --- libcxx/include/__chrono/is_clock.h | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index 877d31ad31176..fcebbf48a64c4 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -24,22 +24,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { -template -struct is_clock : std::false_type {}; - template - requires requires { - typename _Tp::rep; - typename _Tp::period; - typename _Tp::duration; - typename _Tp::time_point; - _Tp::is_steady; - _Tp::now(); - } -struct is_clock<_Tp> : std::true_type {}; +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { + typename _Tp::rep; + typename _Tp::period; + typename _Tp::duration; + typename _Tp::time_point; + _Tp::is_steady; + _Tp::now(); +}; template -_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = is_clock<_Tp>::value; +struct _LIBCPP_NO_SPECIALIZATIONS is_clock : bool_constant> {}; } // namespace chrono From 5c09a5d812019c776e95d18d60b1e4916a4e0689 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Thu, 25 Sep 2025 11:16:05 -0700 Subject: [PATCH 03/13] address comments --- libcxx/docs/ReleaseNotes/22.rst | 2 -- libcxx/include/__chrono/is_clock.h | 3 +-- libcxx/include/chrono | 3 +++ ...ss.cpp => trait.is.clock.compile.pass.cpp} | 0 .../trait.is.clock.compile.verify.cpp | 22 +++++++++++++++++++ 5 files changed, 26 insertions(+), 4 deletions(-) rename libcxx/test/std/time/time.traits.is.clock/{trait.is.clock.pass.cpp => trait.is.clock.compile.pass.cpp} (100%) create mode 100644 libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index b4261e474a27b..509ead64ee525 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -41,8 +41,6 @@ Implemented Papers - P2321R2: ``zip`` (`Github `__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release) - P3168R2: Give ``std::optional`` Range Support (`Github `__) -- P0355R7: ``std::chrono::is_clock`` and ``std::chrono::is_clock_v`` (`Github ` __) - (The paper is partially implemented. ``is_clock`` and ``is_clock_v`` is implemented in this release) Improvements and New Features ----------------------------- diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index fcebbf48a64c4..da65788af8a3a 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -11,6 +11,7 @@ #define _LIBCPP___CHRONO_IS_CLOCK_H #include <__config> +#include <__type_traits/integral_constant.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -18,8 +19,6 @@ #if _LIBCPP_STD_VER >= 20 -# include <__type_traits/integral_constant.h> - _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { diff --git a/libcxx/include/chrono b/libcxx/include/chrono index f3bb08ef386c9..aa4fc6218f962 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -218,6 +218,9 @@ template template constexpr ToDuration round(const duration& d); // C++17 +template struct is_clock; // C++20 +template inline constexpr bool is_clock_v = is_clock::value; // C++20 + // duration I/O template // C++20 basic_ostream& diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp similarity index 100% rename from libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp rename to libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp new file mode 100644 index 0000000000000..f902f7423032a --- /dev/null +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +#include +#include + +namespace std::chrono { +// try adding specializations to is_clock +template <> +struct is_clock : std::false_type {}; // expected-error@*:* {{'is_clock' cannot be specialized}} + +template <> +constexpr bool is_clock_v = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}} + +} From 7f1ad78a0f6d82822d1215176b6957c534b243c7 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Thu, 25 Sep 2025 11:21:46 -0700 Subject: [PATCH 04/13] only test steady_clock if a macro is set --- .../time/time.traits.is.clock/trait.is.clock.compile.pass.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp index 1abdf255054b3..78473808a00e4 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp @@ -87,7 +87,9 @@ int main(int, char**) { // Test standard clock types static_assert(std::chrono::is_clock_v); +#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK static_assert(std::chrono::is_clock_v); +#endif static_assert(std::chrono::is_clock_v); // Test non-clock types @@ -95,7 +97,9 @@ int main(int, char**) { static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); +#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK static_assert(!std::chrono::is_clock_v); +#endif static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); From 11329c13affdf825e68735ffaca67d462fbef585 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Thu, 25 Sep 2025 11:56:54 -0700 Subject: [PATCH 05/13] format in test --- .../time/time.traits.is.clock/trait.is.clock.compile.verify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp index f902f7423032a..fff9941844ee5 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp @@ -19,4 +19,4 @@ struct is_clock : std::false_type {}; // expected-error@*:* {{'is_clock' ca template <> constexpr bool is_clock_v = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}} -} +} // namespace std::chrono From bd7ca123e6e2b118242ed59919104760f49bcfc0 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Thu, 25 Sep 2025 12:02:39 -0700 Subject: [PATCH 06/13] more strict checks --- libcxx/include/__chrono/is_clock.h | 28 +++++ .../trait.is.clock.compile.pass.cpp | 111 +++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index da65788af8a3a..e6020700a297e 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -12,6 +12,8 @@ #include <__config> #include <__type_traits/integral_constant.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,14 +25,40 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { +template +class duration; + +template +class time_point; + +template +constexpr bool __is_valid_clock_time_point_v = false; + +template +constexpr bool __is_valid_clock_time_point_v, _ClockType> = + _IsSame, time_point<_ClockType>>::value || + _IsSame<_Duration, typename _ClockType::duration>::value; + +// Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req] template _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { typename _Tp::rep; + requires is_arithmetic_v; + typename _Tp::period; + requires __is_ratio_v; + typename _Tp::duration; + requires _IsSame>::value; + typename _Tp::time_point; + requires __is_valid_clock_time_point_v; + _Tp::is_steady; + requires _IsSame::value; + _Tp::now(); + requires _IsSame::value; }; template diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp index 78473808a00e4..f6e73bd288d0b 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp @@ -72,7 +72,7 @@ struct ValidSteadyClock { }; struct ValidSystemClock { - using rep = int64_t; + using rep = long long; using period = std::micro; using duration = std::chrono::microseconds; using time_point = std::chrono::time_point; @@ -80,6 +80,94 @@ struct ValidSystemClock { static time_point now(); }; +// Test clocks with invalid is_steady type +struct WrongIsSteadyType { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static bool is_steady; // Not const bool + static time_point now(); +}; + +struct WrongIsSteadyNonBool { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr int is_steady = 1; // Not bool + static time_point now(); +}; + +// Test clocks with invalid now() return type +struct WrongNowReturnType { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static int now(); // Wrong return type +}; + +// Test clocks with invalid period type +struct WrongPeriodType { + using rep = long; + using period = int; // Not a ratio + using duration = std::chrono::seconds; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +// Test clocks with invalid rep type (neither arithmetic nor numeric_limits specialized) +struct InvalidRepType { + using rep = EmptyStruct; // Not arithmetic, no numeric_limits specialization + using period = std::ratio<1>; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +// Test clocks with wrong duration type +struct WrongDurationType { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::milliseconds; // Should be duration> + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + static time_point now(); +}; + +// Test clocks with wrong time_point type +struct WrongTimePointType { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::duration>; + using time_point = int; // Not a time_point + static constexpr bool is_steady = false; + static time_point now(); +}; + +struct WrongTimePointClock { + using rep = long; + using period = std::ratio<1>; + using duration = std::chrono::duration>; + using time_point = std::chrono::time_point; // Wrong clock type + static constexpr bool is_steady = false; + static time_point now(); +}; + +// Valid clock with time_point that has matching duration instead of matching clock +struct ValidClockWithDurationMatch { + using rep = int; + using period = std::milli; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; // Valid: matches duration + static constexpr bool is_steady = false; + static time_point now(); +}; + int main(int, char**) { // Test both is_clock and is_clock_v static_assert(std::chrono::is_clock::value); @@ -114,6 +202,27 @@ int main(int, char**) { // Test valid custom clocks static_assert(std::chrono::is_clock_v); static_assert(std::chrono::is_clock_v); + static_assert(std::chrono::is_clock_v); + + // Test clocks with invalid is_steady type + static_assert(!std::chrono::is_clock_v); // is_steady not const bool + static_assert(!std::chrono::is_clock_v); // is_steady not bool type + + // Test clocks with invalid now() return type + static_assert(!std::chrono::is_clock_v); // now() doesn't return time_point + + // Test clocks with invalid period type + static_assert(!std::chrono::is_clock_v); // period is not a ratio + + // Test clocks with invalid rep type + static_assert(!std::chrono::is_clock_v); // rep is not arithmetic and no numeric_limits + + // Test clocks with wrong duration type + static_assert(!std::chrono::is_clock_v); // duration doesn't match duration + + // Test clocks with wrong time_point type + static_assert(!std::chrono::is_clock_v); // time_point is not a time_point + static_assert(!std::chrono::is_clock_v); // time_point has wrong clock and wrong duration // cv-qualified and reference types static_assert(std::chrono::is_clock_v); From 12a38fb1a2abdbcd63f708466cee39cb81ab94da Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Fri, 26 Sep 2025 10:47:59 -0700 Subject: [PATCH 07/13] apply suggestions to test file --- .../trait.is.clock.compile.pass.cpp | 134 +++++++++--------- 1 file changed, 68 insertions(+), 66 deletions(-) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp index f6e73bd288d0b..a918abed882cf 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp @@ -11,6 +11,8 @@ #include #include +#include "test_macros.h" + struct EmptyStruct {}; // Test structs missing required members @@ -168,75 +170,75 @@ struct ValidClockWithDurationMatch { static time_point now(); }; -int main(int, char**) { - // Test both is_clock and is_clock_v - static_assert(std::chrono::is_clock::value); - static_assert(std::chrono::is_clock_v); +// Test both is_clock and is_clock_v +static_assert(std::chrono::is_clock::value); +static_assert(std::chrono::is_clock_v); - // Test standard clock types - static_assert(std::chrono::is_clock_v); +// Test standard clock types +static_assert(std::chrono::is_clock_v); #ifdef _LIBCPP_HAS_MONOTONIC_CLOCK - static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); #endif - static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); - // Test non-clock types - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); +// Test non-clock types +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); #ifdef _LIBCPP_HAS_MONOTONIC_CLOCK - static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); #endif - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - - // Test structs missing required members - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - - // Test valid custom clocks - static_assert(std::chrono::is_clock_v); - static_assert(std::chrono::is_clock_v); - static_assert(std::chrono::is_clock_v); - - // Test clocks with invalid is_steady type - static_assert(!std::chrono::is_clock_v); // is_steady not const bool - static_assert(!std::chrono::is_clock_v); // is_steady not bool type - - // Test clocks with invalid now() return type - static_assert(!std::chrono::is_clock_v); // now() doesn't return time_point - - // Test clocks with invalid period type - static_assert(!std::chrono::is_clock_v); // period is not a ratio - - // Test clocks with invalid rep type - static_assert(!std::chrono::is_clock_v); // rep is not arithmetic and no numeric_limits - - // Test clocks with wrong duration type - static_assert(!std::chrono::is_clock_v); // duration doesn't match duration - - // Test clocks with wrong time_point type - static_assert(!std::chrono::is_clock_v); // time_point is not a time_point - static_assert(!std::chrono::is_clock_v); // time_point has wrong clock and wrong duration - - // cv-qualified and reference types - static_assert(std::chrono::is_clock_v); - static_assert(std::chrono::is_clock_v); - static_assert(std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - - // array and pointer types - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - static_assert(!std::chrono::is_clock_v); - - return 0; -} +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); + +// Test structs missing required members +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); + +// Test valid custom clocks +static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); + +// cv-qualified and reference types +static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); +static_assert(std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); + +// array and pointer types +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); +static_assert(!std::chrono::is_clock_v); + +// The Standard defined a minimum set of checks and allowed implementation to perform stricter checks. The following +// static asserts are implementation specific and a conforming standard library implementation doesn't have to produce +// the same outcome. + +// Test clocks with invalid is_steady type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // is_steady not const bool +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // is_steady not bool type + +// Test clocks with invalid now() return type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // now() doesn't return time_point + +// Test clocks with invalid period type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // period is not a ratio + +// Test clocks with invalid rep type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // rep is not arithmetic and no numeric_limits + +// Test clocks with wrong duration type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // duration doesn't match duration + +// Test clocks with wrong time_point type +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // time_point is not a time_point +LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v); // time_point has wrong clock and wrong duration From 3af9f2dced94652e35fa4575a74bad7322a52ce4 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Fri, 26 Sep 2025 11:05:03 -0700 Subject: [PATCH 08/13] simplify time_point checks --- libcxx/include/__chrono/is_clock.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index e6020700a297e..463369a65e9db 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -31,14 +31,6 @@ class duration; template class time_point; -template -constexpr bool __is_valid_clock_time_point_v = false; - -template -constexpr bool __is_valid_clock_time_point_v, _ClockType> = - _IsSame, time_point<_ClockType>>::value || - _IsSame<_Duration, typename _ClockType::duration>::value; - // Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req] template _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { @@ -52,7 +44,7 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { requires _IsSame>::value; typename _Tp::time_point; - requires __is_valid_clock_time_point_v; + requires _IsSame::value; _Tp::is_steady; requires _IsSame::value; From 5340360c850a8274a494b7a913f6e02706970398 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Fri, 26 Sep 2025 11:28:03 -0700 Subject: [PATCH 09/13] include --- libcxx/include/__chrono/is_clock.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index 463369a65e9db..235c6004ef253 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -14,6 +14,7 @@ #include <__type_traits/integral_constant.h> #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_same.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From 4afb48af7018316ffc749b1a77167d8cb0e70798 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Fri, 26 Sep 2025 12:05:42 -0700 Subject: [PATCH 10/13] fix AIX CI --- .../time.traits.is.clock/trait.is.clock.compile.verify.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp index fff9941844ee5..963ba34667416 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp @@ -11,6 +11,10 @@ #include #include +#if !__has_warning("-Winvalid-specializations") +// expected-no-diagnostics +#else + namespace std::chrono { // try adding specializations to is_clock template <> @@ -20,3 +24,5 @@ template <> constexpr bool is_clock_v = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}} } // namespace std::chrono + +#endif From 4a01d77a04aefc109487b3ffd08b9944c7e64120 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Mon, 29 Sep 2025 09:13:54 -0700 Subject: [PATCH 11/13] fix monotonic clock check --- .../time/time.traits.is.clock/trait.is.clock.compile.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp index a918abed882cf..e62dbffa08349 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp @@ -176,7 +176,7 @@ static_assert(std::chrono::is_clock_v); // Test standard clock types static_assert(std::chrono::is_clock_v); -#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK +#if _LIBCPP_HAS_MONOTONIC_CLOCK static_assert(std::chrono::is_clock_v); #endif static_assert(std::chrono::is_clock_v); From 89223a8cd4a6fd9482b7f86c437da4e21c0861e5 Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Mon, 29 Sep 2025 09:30:35 -0700 Subject: [PATCH 12/13] still check for specialization --- libcxx/include/__chrono/is_clock.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h index 235c6004ef253..7afc7aa861d05 100644 --- a/libcxx/include/__chrono/is_clock.h +++ b/libcxx/include/__chrono/is_clock.h @@ -32,6 +32,14 @@ class duration; template class time_point; +// Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>. +template +constexpr bool __is_valid_clock_time_point_v = false; + +template +constexpr bool __is_valid_clock_time_point_v, _ClockType> = + true; + // Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req] template _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { @@ -45,7 +53,7 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { requires _IsSame>::value; typename _Tp::time_point; - requires _IsSame::value; + requires __is_valid_clock_time_point_v; _Tp::is_steady; requires _IsSame::value; From 6f7a8a66502884b6c0bd167e616e080bfaef3b9e Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Tue, 30 Sep 2025 10:43:37 -0700 Subject: [PATCH 13/13] fix if _LIBCPP_HAS_MONOTONIC_CLOCK --- .../time/time.traits.is.clock/trait.is.clock.compile.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp index e62dbffa08349..76c3249626fcb 100644 --- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp +++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp @@ -186,7 +186,7 @@ static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); static_assert(!std::chrono::is_clock_v); -#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK +#if _LIBCPP_HAS_MONOTONIC_CLOCK static_assert(!std::chrono::is_clock_v); #endif static_assert(!std::chrono::is_clock_v);