[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 Sep 20 10:38:27 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] 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
+}
More information about the libcxx-commits
mailing list