[libcxx-commits] [libcxx] [libc++] Allow internal functions from atomic_sync.h to be used in C++17 (PR #224356)

Michael G. Kazakov via libcxx-commits libcxx-commits at lists.llvm.org
Sun Oct 4 10:44:58 PDT 2026


https://github.com/mikekazakov updated https://github.com/llvm/llvm-project/pull/224356

>From 61663ffb50ace24cab7b5b006b4df51bfe6696f6 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 17 Sep 2026 17:15:08 +0100
Subject: [PATCH 1/3] Allow functions from atomic_sync.h in C++17

---
 libcxx/include/__atomic/atomic.h              |  8 +++--
 libcxx/include/__atomic/atomic_sync.h         |  4 +--
 .../include/__atomic/atomic_waitable_traits.h | 32 +++++++++++++++++--
 .../atomics.syn/wait_on_cpp17.verify.cpp      | 20 ++++++++++++
 4 files changed, 57 insertions(+), 7 deletions(-)
 create mode 100644 libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index c57b60fc2b4bb..5099dea232c15 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -217,7 +217,7 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
   _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; }
 };
 
-#if _LIBCPP_STD_VER >= 20
+#if _LIBCPP_STD_VER >= 17
 // Here we need _IsIntegral because the default template argument is not enough
 // e.g  __atomic_base<int> is __atomic_base<int, true>, which inherits from
 // __atomic_base<int, false> and the caller of the wait function is
@@ -246,7 +246,7 @@ struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
   }
 };
 
-#endif // _LIBCPP_STD_VER >= 20
+#endif // _LIBCPP_STD_VER >= 17
 
 template <typename _Tp>
 struct __check_atomic_mandates {
@@ -365,10 +365,12 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> {
   atomic& operator=(const atomic&) volatile = delete;
 };
 
-#if _LIBCPP_STD_VER >= 20
+#if _LIBCPP_STD_VER >= 17
 template <class _Tp>
 struct __atomic_waitable_traits<atomic<_Tp> > : __atomic_waitable_traits<__atomic_base<_Tp> > {};
+#endif // _LIBCPP_STD_VER >= 17
 
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp>
   requires is_floating_point_v<_Tp>
 struct atomic<_Tp> : __atomic_base<_Tp> {
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index 1aa6ffa21a8f7..16e8adb709e7b 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -23,7 +23,7 @@
 #  pragma GCC system_header
 #endif
 
-#if _LIBCPP_STD_VER >= 20
+#if _LIBCPP_STD_VER >= 17
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -261,6 +261,6 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_wait(_AtomicWaitable& __a, _Tp __val, memory
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP_STD_VER >= 20
+#endif // _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ATOMIC_ATOMIC_SYNC_H
diff --git a/libcxx/include/__atomic/atomic_waitable_traits.h b/libcxx/include/__atomic/atomic_waitable_traits.h
index ed26a60df982d..c671a30720f94 100644
--- a/libcxx/include/__atomic/atomic_waitable_traits.h
+++ b/libcxx/include/__atomic/atomic_waitable_traits.h
@@ -16,13 +16,15 @@
 #include <__type_traits/has_unique_object_representation.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_trivially_copyable.h>
+#include <__type_traits/void_t.h>
+#include <__utility/declval.h>
 #include <cstring>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
-#if _LIBCPP_STD_VER >= 20
+#if _LIBCPP_STD_VER >= 17
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -42,12 +44,26 @@ struct __atomic_waitable_traits {
   static void __atomic_contention_address(_AtomicWaitable&&) = delete;
 };
 
+#  if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 concept __atomic_waitable = requires(const _Tp __t, memory_order __order) {
   typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type;
   { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(__t, __order) };
   { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(__t) };
 };
+#  else
+template <class _Tp, class = void>
+struct __atomic_waitable_impl : false_type {};
+template <class _Tp>
+struct __atomic_waitable_impl< _Tp,
+                               __void_t<typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type,
+                                        decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(
+                                            std::declval<const _Tp&>(), std::declval<memory_order>())),
+                                        decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
+                                            std::declval<const _Tp&>())) > > : true_type {};
+template <class _Tp>
+constexpr inline bool __atomic_waitable = __atomic_waitable_impl<_Tp>::value;
+#  endif // _LIBCPP_STD_VER >= 20
 
 #  ifdef __linux__
 #    define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4)
@@ -82,20 +98,32 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl() {
   };
 }
 
+#    if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 concept __has_native_atomic_wait =
     has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> &&
     std::__has_native_atomic_wait_impl<_Tp>();
+#    else
+template <class _Tp>
+constexpr inline bool __has_native_atomic_wait =
+    has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> &&
+    std::__has_native_atomic_wait_impl<_Tp>();
+#    endif // _LIBCPP_STD_VER >= 20
 
 #  else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
 
+#    if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
+#    else
+template <class _Tp>
+constexpr inline bool __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
+#    endif // _LIBCPP_STD_VER >= 20
 
 #  endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP_STD_VER >= 20
+#endif // _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ATOMIC_ATOMIC_WAITABLE_TRAITS_H
diff --git a/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp b/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp
new file mode 100644
index 0000000000000..ef754869c4eb5
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++17
+// UNSUPPORTED: no-threads
+
+#include <atomic>
+
+// This compile-only test checks that __atomic_wait, __atomic_notify_one, and __atomic_notify_all are available in C++17
+
+void test_atomic_wait(std::atomic<int>& val) {
+  std::__atomic_wait(val, 0, std::memory_order_seq_cst); // expected-no-diagnostics
+  std::__atomic_notify_one(val);                         // expected-no-diagnostics
+  std::__atomic_notify_all(val);                         // expected-no-diagnostics
+}

>From 786b7c1158f7f71b3e059722305bc75e226caea4 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 21 Sep 2026 20:23:18 +0100
Subject: [PATCH 2/3] Specialize __atomic_waitable directly in C++17 mode

---
 .../include/__atomic/atomic_waitable_traits.h   | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/libcxx/include/__atomic/atomic_waitable_traits.h b/libcxx/include/__atomic/atomic_waitable_traits.h
index c671a30720f94..10f60045c539b 100644
--- a/libcxx/include/__atomic/atomic_waitable_traits.h
+++ b/libcxx/include/__atomic/atomic_waitable_traits.h
@@ -53,16 +53,15 @@ concept __atomic_waitable = requires(const _Tp __t, memory_order __order) {
 };
 #  else
 template <class _Tp, class = void>
-struct __atomic_waitable_impl : false_type {};
+constexpr inline bool __atomic_waitable = false;
 template <class _Tp>
-struct __atomic_waitable_impl< _Tp,
-                               __void_t<typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type,
-                                        decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(
-                                            std::declval<const _Tp&>(), std::declval<memory_order>())),
-                                        decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
-                                            std::declval<const _Tp&>())) > > : true_type {};
-template <class _Tp>
-constexpr inline bool __atomic_waitable = __atomic_waitable_impl<_Tp>::value;
+constexpr inline bool __atomic_waitable<
+    _Tp,
+    __void_t<typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type,
+             decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(
+                 std::declval<const _Tp&>(), std::declval<memory_order>())),
+             decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
+                 std::declval<const _Tp&>())) > > = true;
 #  endif // _LIBCPP_STD_VER >= 20
 
 #  ifdef __linux__

>From 19a2c7110aeb1ae8d05fb40e95a451fb65edea6e Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 4 Oct 2026 18:44:42 +0100
Subject: [PATCH 3/3] Removed the test, removed the duplication

---
 .../include/__atomic/atomic_waitable_traits.h | 21 -------------------
 .../atomics.syn/wait_on_cpp17.verify.cpp      | 20 ------------------
 2 files changed, 41 deletions(-)
 delete mode 100644 libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp

diff --git a/libcxx/include/__atomic/atomic_waitable_traits.h b/libcxx/include/__atomic/atomic_waitable_traits.h
index 10f60045c539b..91a1e2cbd19ad 100644
--- a/libcxx/include/__atomic/atomic_waitable_traits.h
+++ b/libcxx/include/__atomic/atomic_waitable_traits.h
@@ -44,14 +44,6 @@ struct __atomic_waitable_traits {
   static void __atomic_contention_address(_AtomicWaitable&&) = delete;
 };
 
-#  if _LIBCPP_STD_VER >= 20
-template <class _Tp>
-concept __atomic_waitable = requires(const _Tp __t, memory_order __order) {
-  typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type;
-  { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(__t, __order) };
-  { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(__t) };
-};
-#  else
 template <class _Tp, class = void>
 constexpr inline bool __atomic_waitable = false;
 template <class _Tp>
@@ -62,7 +54,6 @@ constexpr inline bool __atomic_waitable<
                  std::declval<const _Tp&>(), std::declval<memory_order>())),
              decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
                  std::declval<const _Tp&>())) > > = true;
-#  endif // _LIBCPP_STD_VER >= 20
 
 #  ifdef __linux__
 #    define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4)
@@ -97,27 +88,15 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl() {
   };
 }
 
-#    if _LIBCPP_STD_VER >= 20
-template <class _Tp>
-concept __has_native_atomic_wait =
-    has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> &&
-    std::__has_native_atomic_wait_impl<_Tp>();
-#    else
 template <class _Tp>
 constexpr inline bool __has_native_atomic_wait =
     has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> &&
     std::__has_native_atomic_wait_impl<_Tp>();
-#    endif // _LIBCPP_STD_VER >= 20
 
 #  else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
 
-#    if _LIBCPP_STD_VER >= 20
-template <class _Tp>
-concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
-#    else
 template <class _Tp>
 constexpr inline bool __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
-#    endif // _LIBCPP_STD_VER >= 20
 
 #  endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
 
diff --git a/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp b/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp
deleted file mode 100644
index ef754869c4eb5..0000000000000
--- a/libcxx/test/libcxx/atomics/atomics.syn/wait_on_cpp17.verify.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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++17
-// UNSUPPORTED: no-threads
-
-#include <atomic>
-
-// This compile-only test checks that __atomic_wait, __atomic_notify_one, and __atomic_notify_all are available in C++17
-
-void test_atomic_wait(std::atomic<int>& val) {
-  std::__atomic_wait(val, 0, std::memory_order_seq_cst); // expected-no-diagnostics
-  std::__atomic_notify_one(val);                         // expected-no-diagnostics
-  std::__atomic_notify_all(val);                         // expected-no-diagnostics
-}



More information about the libcxx-commits mailing list