Skip to content

Conversation

@yuxuanchen1997
Copy link
Member

@yuxuanchen1997 yuxuanchen1997 commented Sep 24, 2025

Implemented [time.traits.is.clock] from P0355R7.

This patch implements the C++20 feature is_clock and is_clock_v based on the documentation on cppreference

Fixes #166049.

@yuxuanchen1997 yuxuanchen1997 requested a review from a team as a code owner September 24, 2025 21:32
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 24, 2025

@llvm/pr-subscribers-libcxx

Author: Yuxuan Chen (yuxuanchen1997)

Changes

Implemented [time.traits.is.clock] from P0355.


Full diff: https://github.com/llvm/llvm-project/pull/160607.diff

5 Files Affected:

  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (added) libcxx/include/__chrono/is_clock.h (+45)
  • (modified) libcxx/include/chrono (+1)
  • (modified) libcxx/modules/std/chrono.inc (+2-2)
  • (added) libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.cpp (+22)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index e050362abb658..210ea8be4a69d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -261,6 +261,7 @@ set(files
   __chrono/formatter.h
   __chrono/gps_clock.h
   __chrono/hh_mm_ss.h
+  __chrono/is_clock.h
   __chrono/high_resolution_clock.h
   __chrono/leap_second.h
   __chrono/literals.h
diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
new file mode 100644
index 0000000000000..dc64c9eacd80b
--- /dev/null
+++ b/libcxx/include/__chrono/is_clock.h
@@ -0,0 +1,45 @@
+// -*- 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 _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/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..b15e91c48b0be
--- /dev/null
+++ b/libcxx/test/std/time/time.traits.is.clock/trait.is.clock.pass.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>
+
+struct NotAClock {};
+
+int main(int, char**) {
+  static_assert(!std::chrono::is_clock_v<NotAClock>, "should not be treated as a clock");
+
+  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>);
+  return 0;
+}

@yuxuanchen1997 yuxuanchen1997 force-pushed the users/yuxuanchen1997/libcxx-is-clock branch from d25ec00 to ec64186 Compare September 24, 2025 21:35
@yuxuanchen1997 yuxuanchen1997 self-assigned this Sep 24, 2025
@yuxuanchen1997 yuxuanchen1997 force-pushed the users/yuxuanchen1997/libcxx-is-clock branch from ec64186 to 977db81 Compare September 24, 2025 22:25
@yuxuanchen1997 yuxuanchen1997 force-pushed the users/yuxuanchen1997/libcxx-is-clock branch from 977db81 to 74f494a Compare September 24, 2025 22:58
@H-G-Hristov
Copy link
Contributor

Implemented [time.traits.is.clock] from P0355R7.

This patch implements the C++20 feature is_clock and is_clock_v based on the documentation on cppreference

It doesn't seem like we track this particular feature in #99982, but it's necessary to implement.

Would it make sense to create a sub-task to track this item in #99982?

@github-actions
Copy link

github-actions bot commented Sep 25, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,inc,h,cpp -- libcxx/include/__chrono/is_clock.h libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.pass.cpp libcxx/test/std/time/time.traits.is.clock/trait.is.clock.compile.verify.cpp libcxx/include/chrono libcxx/modules/std/chrono.inc --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxx/include/__chrono/is_clock.h b/libcxx/include/__chrono/is_clock.h
index 543181bf2..c064d14f9 100644
--- a/libcxx/include/__chrono/is_clock.h
+++ b/libcxx/include/__chrono/is_clock.h
@@ -37,8 +37,8 @@ template <class _TimePoint, class _ClockType>
 inline constexpr bool __is_valid_clock_time_point_v = false;
 
 template <class _TimePointClock, class _ClockType>
-inline constexpr bool __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> =
-    true;
+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]
 template <class _Tp>

@yuxuanchen1997
Copy link
Member Author

After some feedback, we decided to implement more checks based on the Cpp17Clock requirement. The standard underspecifies what checks need to be done.

For the purposes of the specification of this trait, the extent to which an implementation determines that a type cannot meet the Cpp17Clock requirements is unspecified

The set of requirements for is_clock_v has updated as a result.

@yuxuanchen1997 yuxuanchen1997 force-pushed the users/yuxuanchen1997/libcxx-is-clock branch from 8a6adc0 to bd7ca12 Compare September 25, 2025 22:36
@frederick-vs-ja

This comment was marked as resolved.

Copy link
Contributor

@frederick-vs-ja frederick-vs-ja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. CC @philnik777

@frederick-vs-ja
Copy link
Contributor

Implemented [time.traits.is.clock] from P0355R7.
This patch implements the C++20 feature is_clock and is_clock_v based on the documentation on cppreference
It doesn't seem like we track this particular feature in #99982, but it's necessary to implement.

Would it make sense to create a sub-task to track this item in #99982?

@H-G-Hristov I've just created the corresponding subtask.

@yuxuanchen1997 I modified the PR description to associate this PR with the corresponding subtask. Please double-check.

template <class _Tp>
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires {
typename _Tp::rep;
requires is_arithmetic_v<typename _Tp::rep>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong. Cpp17Clock requires the type to be "an arithmetic type or a class emulating an arithmetic type". I don't think "a class emulating an arithmetic type" is defined anywhere, but IMO we should rather be permissive here than strict.

Copy link
Member Author

@yuxuanchen1997 yuxuanchen1997 Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify what a permissive outcome might be? Do we want to drop this requires? Or do we want a different check based on https://eel.is/c++draft/time.clock.req#:~:text=a%20class%20emulating%20an%20arithmetic%20type ?

Comment on lines +29 to +33
template <class _Rep, class _Period>
class duration;

template <class _Clock, class _Duration>
class time_point;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't forward declare classes in random places. Either include the appropriate header or make a forward declaring header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should introduce a forward declaring header here.


// Test standard clock types
static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
#if _LIBCPP_HAS_MONOTONIC_CLOCK
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't use libc++-internal macros to guard against this stuff. More generally, do we really need to test this? I don't think this adds much value while making things definitely more complicated.

@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a standard test, so it should live inside test/libcxx.

Comment on lines +14 to +17
#if !__has_warning("-Winvalid-specializations")
// expected-no-diagnostics
#else

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still required? The minimum supported Clang version is 20 now, where the attribute has been implemented already.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I added it for some CI failures. I can try removing.

// expected-no-diagnostics
#else

namespace std::chrono {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid opening namespace std.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[libc++] P0355R7: std::chrono::is_clock and std::chrono::is_clock_v

6 participants