[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