[libcxx-commits] [libcxx] [libcxx] Implement C++20 std::chrono::is_clock, std::chrono::is_clock_v (PR #160607)

Yuxuan Chen via libcxx-commits libcxx-commits at lists.llvm.org
Wed Nov 5 16:02:37 PST 2025


https://github.com/yuxuanchen1997 updated https://github.com/llvm/llvm-project/pull/160607

>From 23240404e4f771a2e200932b9b5d6dd6bab7ee24 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Wed, 24 Sep 2025 11:54:36 -0700
Subject: [PATCH 01/17] [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 58e0ee9993065..33b6f571d59bb 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -48,6 +48,8 @@ Implemented Papers
 - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
 - P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
 - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
+- P0355R7: ``std::chrono::is_clock`` and ``std::chrono::is_clock_v`` (`Github <https://llvm.org/PR160607>` __)
+  (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 57032ce26d4fd..46e17b584432e 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 <class>
+struct is_clock : std::false_type {};
+
+template <class _Tp>
+  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 <class _Tp>
+_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 24a2fe761943a..f77c885da5b6a 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -973,6 +973,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 <chrono>
+#include <ratio>
+
+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<MissingRep>;
+  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<MissingPeriod>;
+  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<MissingTimePoint> now();
+};
+
+struct MissingIsSteady {
+  using rep        = long;
+  using period     = std::ratio<1>;
+  using duration   = std::chrono::seconds;
+  using time_point = std::chrono::time_point<MissingIsSteady>;
+  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<MissingNow>;
+  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<ValidSteadyClock>;
+  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<ValidSystemClock>;
+  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<std::chrono::system_clock>::value);
+  static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+
+  // Test standard clock types
+  static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+  static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
+  static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
+
+  // Test non-clock types
+  static_assert(!std::chrono::is_clock_v<EmptyStruct>);
+  static_assert(!std::chrono::is_clock_v<int>);
+  static_assert(!std::chrono::is_clock_v<void>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
+
+  // Test structs missing required members
+  static_assert(!std::chrono::is_clock_v<MissingRep>);
+  static_assert(!std::chrono::is_clock_v<MissingPeriod>);
+  static_assert(!std::chrono::is_clock_v<MissingDuration>);
+  static_assert(!std::chrono::is_clock_v<MissingTimePoint>);
+  static_assert(!std::chrono::is_clock_v<MissingIsSteady>);
+  static_assert(!std::chrono::is_clock_v<MissingNow>);
+
+  // Test valid custom clocks
+  static_assert(std::chrono::is_clock_v<ValidSteadyClock>);
+  static_assert(std::chrono::is_clock_v<ValidSystemClock>);
+
+  // cv-qualified and reference types
+  static_assert(std::chrono::is_clock_v<const std::chrono::system_clock>);
+  static_assert(std::chrono::is_clock_v<volatile std::chrono::system_clock>);
+  static_assert(std::chrono::is_clock_v<const volatile std::chrono::system_clock>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&&>);
+  static_assert(!std::chrono::is_clock_v<const std::chrono::system_clock&>);
+
+  // array and pointer types
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[]>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[10]>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock*>);
+  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock* const>);
+
+  return 0;
+}

>From 0ee43ea059e629742052bacdfd0acdea5167a4dd Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at fb.com>
Date: Wed, 24 Sep 2025 21:09:26 -0700
Subject: [PATCH 02/17] Apply suggestions in libcxx/include/__chrono/is_clock.h

Co-authored-by: A. Jiang <de34 at live.cn>
---
 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 <class>
-struct is_clock : std::false_type {};
-
 template <class _Tp>
-  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 <class _Tp>
-_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = is_clock<_Tp>::value;
+struct _LIBCPP_NO_SPECIALIZATIONS is_clock : bool_constant<is_clock_v<_Tp>> {};
 
 } // namespace chrono
 

>From 62785c77a9b2e04287d0ce58eb368bbe62c0d854 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 25 Sep 2025 11:16:05 -0700
Subject: [PATCH 03/17] 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 33b6f571d59bb..58e0ee9993065 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -48,8 +48,6 @@ Implemented Papers
 - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
 - P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
 - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
-- P0355R7: ``std::chrono::is_clock`` and ``std::chrono::is_clock_v`` (`Github <https://llvm.org/PR160607>` __)
-  (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 <class ToDuration, class Rep, class Period>
 template <class ToDuration, class Rep, class Period>
     constexpr ToDuration round(const duration<Rep, Period>& d);    // C++17
 
+template <class T> struct is_clock;                                // C++20
+template <class T> inline constexpr bool is_clock_v = is_clock<T>::value;                   // C++20
+
 // duration I/O
 template<class charT, class traits, class Rep, class Period>       // C++20
   basic_ostream<charT, traits>&
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 <chrono>
+#include <ratio>
+
+namespace std::chrono {
+// try adding specializations to is_clock
+template <>
+struct is_clock<int> : std::false_type {}; // expected-error@*:* {{'is_clock' cannot be specialized}}
+
+template <>
+constexpr bool is_clock_v<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}
+
+}

>From b3141356bc5b6cbc468b2fb75f8b3fb21a8885dc Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 25 Sep 2025 11:21:46 -0700
Subject: [PATCH 04/17] 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<std::chrono::system_clock>);
+#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
   static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
+#endif
   static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
 
   // Test non-clock types
@@ -95,7 +97,9 @@ int main(int, char**) {
   static_assert(!std::chrono::is_clock_v<int>);
   static_assert(!std::chrono::is_clock_v<void>);
   static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
+#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
   static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
+#endif
   static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
   static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
 

>From 2f69de93f59dcec71e1d413330b19f774b80cbf1 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 25 Sep 2025 11:56:54 -0700
Subject: [PATCH 05/17] 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<int> : std::false_type {}; // expected-error@*:* {{'is_clock' ca
 template <>
 constexpr bool is_clock_v<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}
 
-}
+} // namespace std::chrono

>From 37475152690731f969f4c63e48a863baa6ecbda9 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 25 Sep 2025 12:02:39 -0700
Subject: [PATCH 06/17] 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 _Rep, class _Period>
+class duration;
+
+template <class _Clock, class _Duration>
+class time_point;
+
+template <class _TimePoint, class _Clock>
+constexpr bool __is_valid_clock_time_point_v = false;
+
+template <class _Clock, class _Duration, class _ClockType>
+constexpr bool __is_valid_clock_time_point_v<time_point<_Clock, _Duration>, _ClockType> =
+    _IsSame<time_point<_Clock, _Duration>, 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 <class _Tp>
 _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires {
   typename _Tp::rep;
+  requires is_arithmetic_v<typename _Tp::rep>;
+
   typename _Tp::period;
+  requires __is_ratio_v<typename _Tp::period>;
+
   typename _Tp::duration;
+  requires _IsSame<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>::value;
+
   typename _Tp::time_point;
+  requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;
+
   _Tp::is_steady;
+  requires _IsSame<decltype(_Tp::is_steady), const bool>::value;
+
   _Tp::now();
+  requires _IsSame<decltype(_Tp::now()), typename _Tp::time_point>::value;
 };
 
 template <class _Tp>
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<ValidSystemClock>;
@@ -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<WrongIsSteadyType>;
+  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<WrongIsSteadyNonBool>;
+  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<WrongNowReturnType>;
+  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<WrongPeriodType>;
+  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<EmptyStruct>;
+  using time_point                = std::chrono::time_point<InvalidRepType, duration>;
+  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<long, ratio<1>>
+  using time_point                = std::chrono::time_point<WrongDurationType>;
+  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<long, std::ratio<1>>;
+  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<long, std::ratio<1>>;
+  using time_point                = std::chrono::time_point<ValidSystemClock>; // 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<int, std::milli>;
+  using time_point                = std::chrono::time_point<ValidSystemClock, duration>; // 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<std::chrono::system_clock>::value);
@@ -114,6 +202,27 @@ int main(int, char**) {
   // Test valid custom clocks
   static_assert(std::chrono::is_clock_v<ValidSteadyClock>);
   static_assert(std::chrono::is_clock_v<ValidSystemClock>);
+  static_assert(std::chrono::is_clock_v<ValidClockWithDurationMatch>);
+
+  // Test clocks with invalid is_steady type
+  static_assert(!std::chrono::is_clock_v<WrongIsSteadyType>);    // is_steady not const bool
+  static_assert(!std::chrono::is_clock_v<WrongIsSteadyNonBool>); // is_steady not bool type
+
+  // Test clocks with invalid now() return type
+  static_assert(!std::chrono::is_clock_v<WrongNowReturnType>); // now() doesn't return time_point
+
+  // Test clocks with invalid period type
+  static_assert(!std::chrono::is_clock_v<WrongPeriodType>); // period is not a ratio
+
+  // Test clocks with invalid rep type
+  static_assert(!std::chrono::is_clock_v<InvalidRepType>); // rep is not arithmetic and no numeric_limits
+
+  // Test clocks with wrong duration type
+  static_assert(!std::chrono::is_clock_v<WrongDurationType>); // duration doesn't match duration<rep, period>
+
+  // Test clocks with wrong time_point type
+  static_assert(!std::chrono::is_clock_v<WrongTimePointType>);  // time_point is not a time_point
+  static_assert(!std::chrono::is_clock_v<WrongTimePointClock>); // time_point has wrong clock and wrong duration
 
   // cv-qualified and reference types
   static_assert(std::chrono::is_clock_v<const std::chrono::system_clock>);

>From ad50c302346990e8239d3c5564ee20597d4413bc Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Fri, 26 Sep 2025 10:47:59 -0700
Subject: [PATCH 07/17] 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 <chrono>
 #include <ratio>
 
+#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<std::chrono::system_clock>::value);
-  static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+// Test both is_clock and is_clock_v
+static_assert(std::chrono::is_clock<std::chrono::system_clock>::value);
+static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
 
-  // Test standard clock types
-  static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+// Test standard clock types
+static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
 #ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
-  static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
+static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
 #endif
-  static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
+static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
 
-  // Test non-clock types
-  static_assert(!std::chrono::is_clock_v<EmptyStruct>);
-  static_assert(!std::chrono::is_clock_v<int>);
-  static_assert(!std::chrono::is_clock_v<void>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
+// Test non-clock types
+static_assert(!std::chrono::is_clock_v<EmptyStruct>);
+static_assert(!std::chrono::is_clock_v<int>);
+static_assert(!std::chrono::is_clock_v<void>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
 #ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
-  static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
+static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
 #endif
-  static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
-
-  // Test structs missing required members
-  static_assert(!std::chrono::is_clock_v<MissingRep>);
-  static_assert(!std::chrono::is_clock_v<MissingPeriod>);
-  static_assert(!std::chrono::is_clock_v<MissingDuration>);
-  static_assert(!std::chrono::is_clock_v<MissingTimePoint>);
-  static_assert(!std::chrono::is_clock_v<MissingIsSteady>);
-  static_assert(!std::chrono::is_clock_v<MissingNow>);
-
-  // Test valid custom clocks
-  static_assert(std::chrono::is_clock_v<ValidSteadyClock>);
-  static_assert(std::chrono::is_clock_v<ValidSystemClock>);
-  static_assert(std::chrono::is_clock_v<ValidClockWithDurationMatch>);
-
-  // Test clocks with invalid is_steady type
-  static_assert(!std::chrono::is_clock_v<WrongIsSteadyType>);    // is_steady not const bool
-  static_assert(!std::chrono::is_clock_v<WrongIsSteadyNonBool>); // is_steady not bool type
-
-  // Test clocks with invalid now() return type
-  static_assert(!std::chrono::is_clock_v<WrongNowReturnType>); // now() doesn't return time_point
-
-  // Test clocks with invalid period type
-  static_assert(!std::chrono::is_clock_v<WrongPeriodType>); // period is not a ratio
-
-  // Test clocks with invalid rep type
-  static_assert(!std::chrono::is_clock_v<InvalidRepType>); // rep is not arithmetic and no numeric_limits
-
-  // Test clocks with wrong duration type
-  static_assert(!std::chrono::is_clock_v<WrongDurationType>); // duration doesn't match duration<rep, period>
-
-  // Test clocks with wrong time_point type
-  static_assert(!std::chrono::is_clock_v<WrongTimePointType>);  // time_point is not a time_point
-  static_assert(!std::chrono::is_clock_v<WrongTimePointClock>); // time_point has wrong clock and wrong duration
-
-  // cv-qualified and reference types
-  static_assert(std::chrono::is_clock_v<const std::chrono::system_clock>);
-  static_assert(std::chrono::is_clock_v<volatile std::chrono::system_clock>);
-  static_assert(std::chrono::is_clock_v<const volatile std::chrono::system_clock>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&&>);
-  static_assert(!std::chrono::is_clock_v<const std::chrono::system_clock&>);
-
-  // array and pointer types
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[]>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[10]>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock*>);
-  static_assert(!std::chrono::is_clock_v<std::chrono::system_clock* const>);
-
-  return 0;
-}
+static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
+static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
+
+// Test structs missing required members
+static_assert(!std::chrono::is_clock_v<MissingRep>);
+static_assert(!std::chrono::is_clock_v<MissingPeriod>);
+static_assert(!std::chrono::is_clock_v<MissingDuration>);
+static_assert(!std::chrono::is_clock_v<MissingTimePoint>);
+static_assert(!std::chrono::is_clock_v<MissingIsSteady>);
+static_assert(!std::chrono::is_clock_v<MissingNow>);
+
+// Test valid custom clocks
+static_assert(std::chrono::is_clock_v<ValidSteadyClock>);
+static_assert(std::chrono::is_clock_v<ValidSystemClock>);
+static_assert(std::chrono::is_clock_v<ValidClockWithDurationMatch>);
+
+// cv-qualified and reference types
+static_assert(std::chrono::is_clock_v<const std::chrono::system_clock>);
+static_assert(std::chrono::is_clock_v<volatile std::chrono::system_clock>);
+static_assert(std::chrono::is_clock_v<const volatile std::chrono::system_clock>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&&>);
+static_assert(!std::chrono::is_clock_v<const std::chrono::system_clock&>);
+
+// array and pointer types
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[]>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[10]>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock*>);
+static_assert(!std::chrono::is_clock_v<std::chrono::system_clock* const>);
+
+// 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<WrongIsSteadyType>);    // is_steady not const bool
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongIsSteadyNonBool>); // is_steady not bool type
+
+// Test clocks with invalid now() return type
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongNowReturnType>); // now() doesn't return time_point
+
+// Test clocks with invalid period type
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongPeriodType>); // period is not a ratio
+
+// Test clocks with invalid rep type
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<InvalidRepType>); // rep is not arithmetic and no numeric_limits
+
+// Test clocks with wrong duration type
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongDurationType>); // duration doesn't match duration<rep, period>
+
+// Test clocks with wrong time_point type
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongTimePointType>);  // time_point is not a time_point
+LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongTimePointClock>); // time_point has wrong clock and wrong duration

>From 4dae87cb76b07d1e6398c640d7af6fe49e72b197 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Fri, 26 Sep 2025 11:05:03 -0700
Subject: [PATCH 08/17] 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 _Clock, class _Duration>
 class time_point;
 
-template <class _TimePoint, class _Clock>
-constexpr bool __is_valid_clock_time_point_v = false;
-
-template <class _Clock, class _Duration, class _ClockType>
-constexpr bool __is_valid_clock_time_point_v<time_point<_Clock, _Duration>, _ClockType> =
-    _IsSame<time_point<_Clock, _Duration>, 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 <class _Tp>
 _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<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>::value;
 
   typename _Tp::time_point;
-  requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;
+  requires _IsSame<typename _Tp::time_point::duration, typename _Tp::duration>::value;
 
   _Tp::is_steady;
   requires _IsSame<decltype(_Tp::is_steady), const bool>::value;

>From 88ac3606c302e87e2759de34df3f20322a7f821e Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Fri, 26 Sep 2025 11:28:03 -0700
Subject: [PATCH 09/17] include <ratio>

---
 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 <ratio>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header

>From 68cb26e759fa225ba1b75a8d292e75435e065a05 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Fri, 26 Sep 2025 12:05:42 -0700
Subject: [PATCH 10/17] 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 <chrono>
 #include <ratio>
 
+#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<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}
 
 } // namespace std::chrono
+
+#endif

>From cd6d2ae8ee1848ec7eb3125d1bc658cc48f21b76 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Mon, 29 Sep 2025 09:13:54 -0700
Subject: [PATCH 11/17] 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<std::chrono::system_clock>);
 
 // Test standard clock types
 static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
-#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
+#if _LIBCPP_HAS_MONOTONIC_CLOCK
 static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
 #endif
 static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);

>From 8d08d63ce5f77adf29af94777927ba92e2d9f1fd Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Mon, 29 Sep 2025 09:30:35 -0700
Subject: [PATCH 12/17] 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 _Clock, class _Duration>
 class time_point;
 
+// Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>.
+template <class _TimePoint, class _ClockType>
+constexpr bool __is_valid_clock_time_point_v = false;
+
+template <class _TimePointClock, class _ClockType>
+constexpr bool __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> =
+    true;
+
 // Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req]
 template <class _Tp>
 _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<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>::value;
 
   typename _Tp::time_point;
-  requires _IsSame<typename _Tp::time_point::duration, typename _Tp::duration>::value;
+  requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;
 
   _Tp::is_steady;
   requires _IsSame<decltype(_Tp::is_steady), const bool>::value;

>From 94ede351d8d23d8f9a10fe6694f6ab728ec6d36d Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Tue, 30 Sep 2025 10:43:37 -0700
Subject: [PATCH 13/17] 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<EmptyStruct>);
 static_assert(!std::chrono::is_clock_v<int>);
 static_assert(!std::chrono::is_clock_v<void>);
 static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
-#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
+#if _LIBCPP_HAS_MONOTONIC_CLOCK
 static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
 #endif
 static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);

>From 1ddf5762504affa87c1206378b25e92b2ddd69e9 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at fb.com>
Date: Wed, 5 Nov 2025 06:33:06 -1000
Subject: [PATCH 14/17] Apply suggestion from @philnik777

Co-authored-by: Nikolas Klauser <nikolasklauser at berlin.de>
---
 libcxx/include/__chrono/is_clock.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
index 7afc7aa861d05..7600ad0407bb5 100644
--- a/libcxx/include/__chrono/is_clock.h
+++ b/libcxx/include/__chrono/is_clock.h
@@ -34,10 +34,10 @@ class time_point;
 
 // Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>.
 template <class _TimePoint, class _ClockType>
-constexpr bool __is_valid_clock_time_point_v = false;
+inline constexpr bool __is_valid_clock_time_point_v = false;
 
 template <class _TimePointClock, class _ClockType>
-constexpr bool __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> =
+inline constexpr bool __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> =
     true;
 
 // Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req]

>From 3acb6d8a67c6b827add581f8ed0d293a0c510e01 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at fb.com>
Date: Wed, 5 Nov 2025 06:41:31 -1000
Subject: [PATCH 15/17] Apply suggestion from @frederick-vs-ja

Co-authored-by: A. Jiang <de34 at live.cn>
---
 libcxx/include/__chrono/is_clock.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
index 7600ad0407bb5..11a98c2578ab8 100644
--- a/libcxx/include/__chrono/is_clock.h
+++ b/libcxx/include/__chrono/is_clock.h
@@ -56,7 +56,7 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires {
   requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;
 
   _Tp::is_steady;
-  requires _IsSame<decltype(_Tp::is_steady), const bool>::value;
+  requires same_as<decltype((_Tp::is_steady)), const bool&>;
 
   _Tp::now();
   requires _IsSame<decltype(_Tp::now()), typename _Tp::time_point>::value;

>From 9578700fa9304206a94110ff1a36c4ad543b1d28 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at fb.com>
Date: Wed, 5 Nov 2025 06:42:14 -1000
Subject: [PATCH 16/17] Apply suggestion from @philnik777

Co-authored-by: Nikolas Klauser <nikolasklauser at berlin.de>
---
 libcxx/include/__chrono/is_clock.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
index 11a98c2578ab8..543181bf262b7 100644
--- a/libcxx/include/__chrono/is_clock.h
+++ b/libcxx/include/__chrono/is_clock.h
@@ -50,7 +50,7 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires {
   requires __is_ratio_v<typename _Tp::period>;
 
   typename _Tp::duration;
-  requires _IsSame<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>::value;
+  requires same_as<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>;
 
   typename _Tp::time_point;
   requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;

>From 8349c642b52d42b7b8d23704c97d90ad8e4f3194 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Wed, 5 Nov 2025 16:02:11 -0800
Subject: [PATCH 17/17] fix include and tests

---
 libcxx/include/__chrono/is_clock.h                 | 10 ++++------
 .../trait.is.clock.compile.verify.cpp              | 14 ++------------
 .../trait.is.clock.compile.pass.cpp                |  6 ------
 3 files changed, 6 insertions(+), 24 deletions(-)
 rename libcxx/test/{std => libcxx}/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp (54%)

diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
index 543181bf262b7..add28ff4ec92d 100644
--- a/libcxx/include/__chrono/is_clock.h
+++ b/libcxx/include/__chrono/is_clock.h
@@ -11,6 +11,10 @@
 #define _LIBCPP___CHRONO_IS_CLOCK_H
 
 #include <__config>
+
+#include <__chrono/duration.h>
+#include <__chrono/time_point.h>
+#include <__concepts/same_as.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_same.h>
@@ -26,12 +30,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace chrono {
 
-template <class _Rep, class _Period>
-class duration;
-
-template <class _Clock, class _Duration>
-class time_point;
-
 // Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>.
 template <class _TimePoint, class _ClockType>
 inline constexpr bool __is_valid_clock_time_point_v = false;
diff --git a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp b/libcxx/test/libcxx/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp
similarity index 54%
rename from libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp
rename to libcxx/test/libcxx/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp
index 963ba34667416..3114300b0afae 100644
--- a/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp
+++ b/libcxx/test/libcxx/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp
@@ -11,18 +11,8 @@
 #include <chrono>
 #include <ratio>
 
-#if !__has_warning("-Winvalid-specializations")
-// expected-no-diagnostics
-#else
-
-namespace std::chrono {
-// try adding specializations to is_clock
 template <>
-struct is_clock<int> : std::false_type {}; // expected-error@*:* {{'is_clock' cannot be specialized}}
+struct std::chrono::is_clock<int> : std::false_type {}; // expected-error@*:* {{'is_clock' cannot be specialized}}
 
 template <>
-constexpr bool is_clock_v<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}
-
-} // namespace std::chrono
-
-#endif
+constexpr bool std::chrono::is_clock_v<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}
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 76c3249626fcb..4b54deb02dcf6 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,9 +176,6 @@ static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
 
 // Test standard clock types
 static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
-#if _LIBCPP_HAS_MONOTONIC_CLOCK
-static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
-#endif
 static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
 
 // Test non-clock types
@@ -186,9 +183,6 @@ static_assert(!std::chrono::is_clock_v<EmptyStruct>);
 static_assert(!std::chrono::is_clock_v<int>);
 static_assert(!std::chrono::is_clock_v<void>);
 static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
-#if _LIBCPP_HAS_MONOTONIC_CLOCK
-static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
-#endif
 static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
 static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
 



More information about the libcxx-commits mailing list