diff mbox series

[committed] libstdc++: Define and use chrono::is_clock for C++20

Message ID 20200325221923.GA233061@redhat.com
State New
Headers show
Series [committed] libstdc++: Define and use chrono::is_clock for C++20 | expand

Commit Message

Li, Pan2 via Gcc-patches March 25, 2020, 10:19 p.m. UTC
For C++20 the wait_until members of mutexes and condition variables are
required to be ill-formed if given a clock that doesn't meet the
requirements for a clock type. To implement that requirement this patch
adds static assertions using the chrono::is_clock trait, and defines
that trait.

To avoid expensive checks for the common cases, the trait (and
associated variable template) are explicitly specialized for the
standard clock types.

This also moves the filesystem::__file_clock type from <filesystem> to
<chrono>, so that chrono::file_clock and chrono::file_time can be
defined in <chrono> as required.

	* include/bits/fs_fwd.h (filesystem::__file_clock): Move to ...
	* include/std/chrono (filesystem::__file_clock): Here.
	(filesystem::__file_clock::from_sys, filesystem::__file_clock::to_sys):
	Define public member functions for C++20.
	(is_clock, is_clock_v): Define traits for C++20.
	* include/std/condition_variable (condition_variable::wait_until): Add
	check for valid clock.
	* include/std/future (_State_baseV2::wait_until): Likewise.
	* include/std/mutex (__timed_mutex_impl::_M_try_lock_until): Likewise.
	* include/std/shared_mutex (shared_timed_mutex::try_lock_shared_until):
	Likewise.
	* include/std/thread (this_thread::sleep_until): Likewise.
	* testsuite/30_threads/condition_variable/members/2.cc: Qualify
	slow_clock with new namespace.
	* testsuite/30_threads/condition_variable/members/clock_neg.cc: New
	test.
	* testsuite/30_threads/condition_variable_any/members/clock_neg.cc:
	New test.
	* testsuite/30_threads/future/members/clock_neg.cc: New test.
	* testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc:
	Qualify slow_clock with new namespace.
	* testsuite/30_threads/recursive_timed_mutex/try_lock_until/
	clock_neg.cc: New test.
	* testsuite/30_threads/shared_future/members/clock_neg.cc: New
	test.
	* testsuite/30_threads/shared_lock/locking/clock_neg.cc: New test.
	* testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc:
	New test.
	* testsuite/30_threads/timed_mutex/try_lock_until/3.cc: Qualify
	slow_clock with new namespace.
	* testsuite/30_threads/timed_mutex/try_lock_until/4.cc: Likewise.
	* testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc: New
	test.
	* testsuite/30_threads/unique_lock/locking/clock_neg.cc: New test.
	* testsuite/std/time/traits/is_clock.cc: New test.
	* testsuite/util/slow_clock.h (slow_clock): Move to __gnu_test
	namespace.

Tested powerpc64le-linux. Committed to master.
commit bf1fc37bb4a3cab851e2acec811427d5243a22e9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Mar 25 22:07:02 2020 +0000

    libstdc++: Define and use chrono::is_clock for C++20
    
    For C++20 the wait_until members of mutexes and condition variables are
    required to be ill-formed if given a clock that doesn't meet the
    requirements for a clock type. To implement that requirement this patch
    adds static assertions using the chrono::is_clock trait, and defines
    that trait.
    
    To avoid expensive checks for the common cases, the trait (and
    associated variable template) are explicitly specialized for the
    standard clock types.
    
    This also moves the filesystem::__file_clock type from <filesystem> to
    <chrono>, so that chrono::file_clock and chrono::file_time can be
    defined in <chrono> as required.
    
            * include/bits/fs_fwd.h (filesystem::__file_clock): Move to ...
            * include/std/chrono (filesystem::__file_clock): Here.
            (filesystem::__file_clock::from_sys, filesystem::__file_clock::to_sys):
            Define public member functions for C++20.
            (is_clock, is_clock_v): Define traits for C++20.
            * include/std/condition_variable (condition_variable::wait_until): Add
            check for valid clock.
            * include/std/future (_State_baseV2::wait_until): Likewise.
            * include/std/mutex (__timed_mutex_impl::_M_try_lock_until): Likewise.
            * include/std/shared_mutex (shared_timed_mutex::try_lock_shared_until):
            Likewise.
            * include/std/thread (this_thread::sleep_until): Likewise.
            * testsuite/30_threads/condition_variable/members/2.cc: Qualify
            slow_clock with new namespace.
            * testsuite/30_threads/condition_variable/members/clock_neg.cc: New
            test.
            * testsuite/30_threads/condition_variable_any/members/clock_neg.cc:
            New test.
            * testsuite/30_threads/future/members/clock_neg.cc: New test.
            * testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc:
            Qualify slow_clock with new namespace.
            * testsuite/30_threads/recursive_timed_mutex/try_lock_until/
            clock_neg.cc: New test.
            * testsuite/30_threads/shared_future/members/clock_neg.cc: New
            test.
            * testsuite/30_threads/shared_lock/locking/clock_neg.cc: New test.
            * testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc:
            New test.
            * testsuite/30_threads/timed_mutex/try_lock_until/3.cc: Qualify
            slow_clock with new namespace.
            * testsuite/30_threads/timed_mutex/try_lock_until/4.cc: Likewise.
            * testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc: New
            test.
            * testsuite/30_threads/unique_lock/locking/clock_neg.cc: New test.
            * testsuite/std/time/traits/is_clock.cc: New test.
            * testsuite/util/slow_clock.h (slow_clock): Move to __gnu_test
            namespace.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/fs_fwd.h b/libstdc++-v3/include/bits/fs_fwd.h
index 1d7495825d6..6363eca867c 100644
--- a/libstdc++-v3/include/bits/fs_fwd.h
+++ b/libstdc++-v3/include/bits/fs_fwd.h
@@ -291,48 +291,6 @@  _GLIBCXX_END_NAMESPACE_CXX11
   operator^=(directory_options& __x, directory_options __y) noexcept
   { return __x = __x ^ __y; }
 
-  struct __file_clock
-  {
-    using duration                  = chrono::nanoseconds;
-    using rep                       = duration::rep;
-    using period                    = duration::period;
-    using time_point                = chrono::time_point<__file_clock>;
-    static constexpr bool is_steady = false;
-
-    static time_point
-    now() noexcept
-    { return _S_from_sys(chrono::system_clock::now()); }
-
-  private:
-    using __sys_clock = chrono::system_clock;
-
-    // This clock's (unspecified) epoch is 2174-01-01 00:00:00 UTC.
-    // A signed 64-bit duration with nanosecond resolution gives roughly
-    // +/- 292 years, which covers the 1901-2446 date range for ext4.
-    static constexpr chrono::seconds _S_epoch_diff{6437664000};
-
-  protected:
-    // For internal use only
-    template<typename _Dur>
-      static
-      chrono::time_point<__file_clock, _Dur>
-      _S_from_sys(const chrono::time_point<__sys_clock, _Dur>& __t) noexcept
-      {
-	using __file_time = chrono::time_point<__file_clock, _Dur>;
-	return __file_time{__t.time_since_epoch()} - _S_epoch_diff;
-      }
-
-    // For internal use only
-    template<typename _Dur>
-      static
-      chrono::time_point<__sys_clock, _Dur>
-      _S_to_sys(const chrono::time_point<__file_clock, _Dur>& __t) noexcept
-      {
-	using __sys_time = chrono::time_point<__sys_clock, _Dur>;
-	return __sys_time{__t.time_since_epoch()} + _S_epoch_diff;
-      }
-  };
-
   using file_time_type = __file_clock::time_point;
 
   // operational functions
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 477d50854b0..b1fa5b83295 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -41,11 +41,18 @@ 
 #include <limits>
 #include <ctime>
 #include <bits/parse_numbers.h> // for literals support.
+#if __cplusplus > 201703L
+# include <concepts>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus >= 201703L
+  namespace filesystem { struct __file_clock; };
+#endif
+
   /**
    * @defgroup chrono Time
    * @ingroup utilities
@@ -237,6 +244,60 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         treat_as_floating_point<_Rep>::value;
 #endif // C++17
 
+#if __cplusplus > 201703L
+    template<typename _Tp>
+      struct is_clock;
+
+    template<typename _Tp>
+      inline constexpr bool is_clock_v = is_clock<_Tp>::value;
+
+#if __cpp_lib_concepts
+    template<typename _Tp>
+      struct is_clock : false_type
+      { };
+
+    template<typename _Tp>
+      requires requires {
+	typename _Tp::rep;
+	typename _Tp::period;
+	typename _Tp::duration;
+	typename _Tp::time_point::clock;
+	typename _Tp::time_point::duration;
+	{ &_Tp::is_steady } -> same_as<const bool*>;
+	{ _Tp::now() } -> same_as<typename _Tp::time_point>;
+	requires same_as<typename _Tp::duration,
+			 duration<typename _Tp::rep, typename _Tp::period>>;
+	requires same_as<typename _Tp::time_point::duration,
+			 typename _Tp::duration>;
+      }
+      struct is_clock<_Tp> : true_type
+      { };
+#else
+    template<typename _Tp, typename = void>
+      struct __is_clock_impl : false_type
+      { };
+
+    template<typename _Tp>
+      struct __is_clock_impl<_Tp,
+			     void_t<typename _Tp::rep, typename _Tp::period,
+				    typename _Tp::duration,
+				    typename _Tp::time_point::duration,
+				    decltype(_Tp::is_steady),
+				    decltype(_Tp::now())>>
+      : __and_<is_same<typename _Tp::duration,
+		       duration<typename _Tp::rep, typename _Tp::period>>,
+	       is_same<typename _Tp::time_point::duration,
+		       typename _Tp::duration>,
+	       is_same<decltype(&_Tp::is_steady), const bool*>,
+	       is_same<decltype(_Tp::now()), typename _Tp::time_point>>::type
+      { };
+
+    template<typename _Tp>
+      struct is_clock : __is_clock_impl<_Tp>::type
+      { };
+#endif
+#endif // C++20
+
 #if __cplusplus >= 201703L
 # define __cpp_lib_chrono 201611
 
@@ -948,6 +1009,26 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     using high_resolution_clock = system_clock;
 
     } // end inline namespace _V2
+
+#if __cplusplus > 201703L
+    template<typename _Duration>
+      using sys_time = time_point<system_clock, _Duration>;
+    using sys_seconds = sys_time<seconds>;
+
+    using file_clock = ::std::filesystem::__file_clock;
+
+    template<typename _Duration>
+      using file_time = time_point<file_clock, _Duration>;
+
+    template<> struct is_clock<system_clock> : true_type { };
+    template<> struct is_clock<steady_clock> : true_type { };
+    template<> struct is_clock<file_clock> : true_type { };
+
+    template<> inline constexpr bool is_clock_v<system_clock> = true;
+    template<> inline constexpr bool is_clock_v<steady_clock> = true;
+    template<> inline constexpr bool is_clock_v<file_clock> = true;
+#endif // C++20
+
     // @}
   } // namespace chrono
 
@@ -1071,6 +1152,67 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     using namespace literals::chrono_literals;
   } // namespace chrono
 
+#if __cplusplus >= 201703L
+  namespace filesystem
+  {
+    struct __file_clock
+    {
+      using duration                  = chrono::nanoseconds;
+      using rep                       = duration::rep;
+      using period                    = duration::period;
+      using time_point                = chrono::time_point<__file_clock>;
+      static constexpr bool is_steady = false;
+
+      static time_point
+      now() noexcept
+      { return _S_from_sys(chrono::system_clock::now()); }
+
+#if __cplusplus > 201703L
+      template<typename _Dur>
+	static
+	chrono::file_time<_Dur>
+	from_sys(const chrono::sys_time<_Dur>& __t) noexcept
+	{ return _S_from_sys(__t); }
+
+      // For internal use only
+      template<typename _Dur>
+	static
+	chrono::sys_time<_Dur>
+	to_sys(const chrono::file_time<_Dur>& __t) noexcept
+	{ return _S_to_sys(__t); }
+#endif // C++20
+
+    private:
+      using __sys_clock = chrono::system_clock;
+
+      // This clock's (unspecified) epoch is 2174-01-01 00:00:00 UTC.
+      // A signed 64-bit duration with nanosecond resolution gives roughly
+      // +/- 292 years, which covers the 1901-2446 date range for ext4.
+      static constexpr chrono::seconds _S_epoch_diff{6437664000};
+
+    protected:
+      // For internal use only
+      template<typename _Dur>
+	static
+	chrono::time_point<__file_clock, _Dur>
+	_S_from_sys(const chrono::time_point<__sys_clock, _Dur>& __t) noexcept
+	{
+	  using __file_time = chrono::time_point<__file_clock, _Dur>;
+	  return __file_time{__t.time_since_epoch()} - _S_epoch_diff;
+	}
+
+      // For internal use only
+      template<typename _Dur>
+	static
+	chrono::time_point<__sys_clock, _Dur>
+	_S_to_sys(const chrono::time_point<__file_clock, _Dur>& __t) noexcept
+	{
+	  using __sys_time = chrono::time_point<__sys_clock, _Dur>;
+	  return __sys_time{__t.time_since_epoch()} + _S_epoch_diff;
+	}
+    };
+  } // namespace filesystem
+#endif // C++17
 #endif // C++14
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable
index 5e98d1b0a6c..cc7f99f6921 100644
--- a/libstdc++-v3/include/std/condition_variable
+++ b/libstdc++-v3/include/std/condition_variable
@@ -131,6 +131,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       wait_until(unique_lock<mutex>& __lock,
 		 const chrono::time_point<_Clock, _Duration>& __atime)
       {
+#if __cplusplus > 201703L
+	static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	const typename _Clock::time_point __c_entry = _Clock::now();
 	const __clock_t::time_point __s_entry = __clock_t::now();
 	const auto __delta = __atime - __c_entry;
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index 59aa981261b..97506a27e37 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -371,6 +371,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         future_status
         wait_until(const chrono::time_point<_Clock, _Duration>& __abs)
         {
+#if __cplusplus > 201703L
+	  static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	  // First, check if the future has been made ready.  Use acquire MO
 	  // to synchronize with the thread that made it ready.
 	  if (_M_status._M_load(memory_order_acquire) == _Status::__ready)
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index a4a8df07f03..12b7e548d17 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -189,6 +189,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	bool
 	_M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
 	{
+#if __cplusplus > 201703L
+	  static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	  // The user-supplied clock may not tick at the same rate as
 	  // steady_clock, so we must loop in order to guarantee that
 	  // the timeout has expired before returning false.
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 9b597e76299..414dce3a1b7 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -554,6 +554,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       bool
       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
       {
+#if __cplusplus > 201703L
+	static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	// The user-supplied clock may not tick at the same rate as
 	// steady_clock, so we must loop in order to guarantee that
 	// the timeout has expired before returning false.
@@ -639,6 +642,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       try_lock_shared_until(const chrono::time_point<_Clock,
 						     _Duration>& __atime)
       {
+#if __cplusplus > 201703L
+	static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	// The user-supplied clock may not tick at the same rate as
 	// steady_clock, so we must loop in order to guarantee that
 	// the timeout has expired before returning false.
diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread
index 1f9c13ff7d1..e1bba0cb29b 100644
--- a/libstdc++-v3/include/std/thread
+++ b/libstdc++-v3/include/std/thread
@@ -414,6 +414,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       inline void
       sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
       {
+#if __cplusplus > 201703L
+	static_assert(chrono::is_clock_v<_Clock>);
+#endif
 	auto __now = _Clock::now();
 	if (_Clock::is_steady)
 	  {
diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
index baa10375cf9..c671804b406 100644
--- a/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
@@ -55,6 +55,8 @@  void test01()
 
 void test01_alternate_clock()
 {
+  using __gnu_test::slow_clock;
+
   try
     {
       std::condition_variable c1;
diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/members/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/clock_neg.cc
new file mode 100644
index 00000000000..11b540f58c8
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/clock_neg.cc
@@ -0,0 +1,61 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <condition_variable>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::mutex m;
+  std::unique_lock<std::mutex> l(m);
+  std::condition_variable cv;
+  cv.wait_until(l, clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::mutex m;
+  std::unique_lock<std::mutex> l(m);
+  std::condition_variable cv;
+  cv.wait_until(l, cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable_any/members/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable_any/members/clock_neg.cc
new file mode 100644
index 00000000000..4302363f407
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable_any/members/clock_neg.cc
@@ -0,0 +1,61 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <condition_variable>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::mutex m;
+  std::unique_lock<std::mutex> l(m);
+  std::condition_variable_any cv;
+  cv.wait_until(l, clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::mutex m;
+  std::unique_lock<std::mutex> l(m);
+  std::condition_variable_any cv;
+  cv.wait_until(l, cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/future/members/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/future/members/clock_neg.cc
new file mode 100644
index 00000000000..a94d770fb62
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/future/members/clock_neg.cc
@@ -0,0 +1,59 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <future>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::promise<void> p;
+  std::future<void> f = p.get_future();
+  f.wait_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::promise<void> p;
+  std::future<void> f = p.get_future();
+  f.wait_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
index b85381de46c..120655ceb65 100644
--- a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
@@ -72,5 +72,5 @@  int main()
 {
   test<std::chrono::system_clock>();
   test<std::chrono::steady_clock>();
-  test<slow_clock>();
+  test<__gnu_test::slow_clock>();
 }
diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc
new file mode 100644
index 00000000000..499e6675545
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <mutex>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::recursive_timed_mutex m;
+  m.try_lock_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::recursive_timed_mutex m;
+  m.try_lock_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/shared_future/members/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_future/members/clock_neg.cc
new file mode 100644
index 00000000000..59f63cc1cf4
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_future/members/clock_neg.cc
@@ -0,0 +1,59 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <future>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::promise<void> p;
+  std::shared_future<void> f = p.get_future();
+  f.wait_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::promise<void> p;
+  std::shared_future<void> f = p.get_future();
+  f.wait_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc
new file mode 100644
index 00000000000..9a21a88ed60
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc
@@ -0,0 +1,59 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <shared_mutex>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::shared_timed_mutex m;
+  std::shared_lock<std::shared_timed_mutex> l(m, std::defer_lock);
+  l.try_lock_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::shared_timed_mutex m;
+  std::shared_lock<std::shared_timed_mutex> l(m, std::defer_lock);
+  l.try_lock_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc
new file mode 100644
index 00000000000..23d4b9d9bbf
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <shared_mutex>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::shared_timed_mutex m;
+  m.try_lock_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::shared_timed_mutex m;
+  m.try_lock_shared_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
index 32c84ef6286..ed5a6b0b8b7 100644
--- a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
@@ -72,5 +72,5 @@  int main()
 {
   test<std::chrono::system_clock>();
   test<std::chrono::steady_clock>();
-  test<slow_clock>();
+  test<__gnu_test::slow_clock>();
 }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/4.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/4.cc
index 037e4086f97..a7a77d2294d 100644
--- a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/4.cc
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/4.cc
@@ -64,5 +64,5 @@  int main()
 {
   test<std::chrono::system_clock>();
   test<std::chrono::steady_clock>();
-  test<slow_clock>();
+  test<__gnu_test::slow_clock>();
 }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc
new file mode 100644
index 00000000000..a9c0132d99b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <mutex>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::timed_mutex m;
+  m.try_lock_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::timed_mutex m;
+  m.try_lock_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc
new file mode 100644
index 00000000000..c7ac9cdc466
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc
@@ -0,0 +1,59 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <mutex>
+
+struct clok
+{
+  // no clok::rep or clok::period defined
+  using duration = std::chrono::milliseconds;
+  using time_point = std::chrono::time_point<clok>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test01()
+{
+  std::timed_mutex m;
+  std::unique_lock<std::timed_mutex> l(m, std::defer_lock);
+  l.try_lock_until(clok::now()); // { dg-error "here" }
+}
+
+struct cloc
+{
+  using duration = std::chrono::milliseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  // cloc::time_point::duration should be the same as cloc::duration:
+  using time_point = std::chrono::time_point<cloc, std::chrono::seconds>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+void
+test02()
+{
+  std::recursive_timed_mutex m;
+  std::unique_lock<std::recursive_timed_mutex> l(m, std::defer_lock);
+  l.try_lock_until(cloc::now()); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/time/traits/is_clock.cc b/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
new file mode 100644
index 00000000000..85f118253c3
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/traits/is_clock.cc
@@ -0,0 +1,124 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <chrono>
+#include <slow_clock.h>
+
+namespace chrono = std::chrono;
+
+static_assert( chrono::is_clock<chrono::system_clock>::value );
+static_assert( chrono::is_clock_v<chrono::system_clock> );
+
+static_assert( chrono::is_clock<chrono::high_resolution_clock>::value );
+static_assert( chrono::is_clock_v<chrono::high_resolution_clock> );
+
+static_assert( chrono::is_clock<chrono::steady_clock>::value );
+static_assert( chrono::is_clock_v<chrono::steady_clock> );
+
+static_assert(chrono::is_clock<chrono::file_clock>::value);
+static_assert(chrono::is_clock_v<chrono::file_clock>);
+
+static_assert( chrono::is_clock<__gnu_test::slow_clock>::value );
+static_assert( chrono::is_clock_v<__gnu_test::slow_clock> );
+
+static_assert( ! chrono::is_clock<int>::value );
+static_assert( ! chrono::is_clock_v<int> );
+
+static_assert( ! chrono::is_clock<void>::value );
+static_assert( ! chrono::is_clock_v<void> );
+
+struct not_a_clock_1
+{
+  using rep = int;
+  using period = std::ratio<4, 2>;
+  using duration = chrono::duration<long, period>; // different rep
+  using time_point = chrono::time_point<not_a_clock_1>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_1>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_1> );
+
+struct not_a_clock_2
+{
+  using rep = int;
+  using period = int; // not a std::ratio
+  using duration = chrono::duration<rep>;
+  using time_point = chrono::time_point<not_a_clock_2>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_2>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_2> );
+
+struct not_a_clock_3
+{
+  using rep = int;
+  using period = std::ratio<1>;
+  using duration = chrono::duration<rep>;
+  // wrong duration:
+  using time_point = chrono::time_point<not_a_clock_3, chrono::duration<long>>;
+  static constexpr bool is_steady = false;
+  static time_point now();
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_3>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_3> );
+
+struct not_a_clock_4
+{
+  using rep = int;
+  using period = std::ratio<1>;
+  using duration = chrono::duration<rep>;
+  using time_point = chrono::time_point<not_a_clock_4>;
+  static constexpr int is_steady = 0; // not a const bool
+  static time_point now();
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_4>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_4> );
+
+struct not_a_clock_5
+{
+  using rep = int;
+  using period = std::ratio<1>;
+  using duration = chrono::duration<rep>;
+  using time_point = chrono::time_point<not_a_clock_5>;
+  static constexpr bool is_steady = false;
+  static int now(); // wrong return type
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_5>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_5> );
+
+struct not_a_clock_6
+{
+  using rep = int;
+  using period = std::ratio<1>;
+  using duration = chrono::duration<rep>;
+  using time_point = chrono::time_point<not_a_clock_6>;
+  const bool is_steady = false; // not static
+  static time_point now();
+};
+
+static_assert( ! chrono::is_clock<not_a_clock_6>::value );
+static_assert( ! chrono::is_clock_v<not_a_clock_6> );
diff --git a/libstdc++-v3/testsuite/util/slow_clock.h b/libstdc++-v3/testsuite/util/slow_clock.h
index bae734f76c8..d1f4bbba851 100644
--- a/libstdc++-v3/testsuite/util/slow_clock.h
+++ b/libstdc++-v3/testsuite/util/slow_clock.h
@@ -22,6 +22,8 @@ 
 
 #include <chrono>
 
+namespace __gnu_test
+{
 struct slow_clock
 {
   using rep = std::chrono::system_clock::rep;
@@ -36,3 +38,4 @@  struct slow_clock
     return time_point{real.time_since_epoch() / 3};
   }
 };
+}