[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 Sep 24 21:09:33 PDT 2025


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

>From 74f494a9bc8920202b31681db2ce1e61fa446730 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 1/2] [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 <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``
   is implemented in this release)
 - 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 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 <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 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 <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 5fcfd586294c01d03530bd67f8e726f93411bdac 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 2/2] 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
 



More information about the libcxx-commits mailing list