[gcc r16-7714] libstdc++: complete P0493R5 with pointer support
Yuao Ma
yuao@gcc.gnu.org
Thu Feb 26 13:11:40 GMT 2026
https://gcc.gnu.org/g:0772974fec9d1e35c412fc6fcbe9754c7cb57eb0
commit r16-7714-g0772974fec9d1e35c412fc6fcbe9754c7cb57eb0
Author: Yuao Ma <c8ef@outlook.com>
Date: Wed Feb 25 20:44:07 2026 +0800
libstdc++: complete P0493R5 with pointer support
Previous implementations of fetch_min/max only supported integers, not
handling pointers. To complete the paper, we need to implement support
for pointers as well. This patch adds the missing functionality and
test cases.
libstdc++-v3/ChangeLog:
* include/bits/atomic_base.h (__atomic_base<_PTp*>::fetch_min,
__atomic_base<_PTp*>::fetch_max,
__atomic_ref<_Pt, false, false, true>::fetch_min,
__atomic_ref<_Pt, false, false, true>::fetch_max): Define new
functions.
* include/std/atomic (atomic<_Tp*>::fetch_min,
atomic<_Tp*>::fetch_max): Likewise.
(atomic_fetch_min_explicit, atomic_fetch_max_explicit,
atomic_fetch_min, atomic_fetch_max): Change parameter from
__atomic_base<_ITp>* to atomic<_Tp>*.
* testsuite/29_atomics/atomic/pointer_fetch_minmax.cc: New test.
* testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc: New
test.
Diff:
---
libstdc++-v3/include/bits/atomic_base.h | 34 +++++++++
libstdc++-v3/include/std/atomic | 86 ++++++++++++++--------
.../29_atomics/atomic/pointer_fetch_minmax.cc | 53 +++++++++++++
.../29_atomics/atomic_ref/pointer_fetch_minmax.cc | 71 ++++++++++++++++++
4 files changed, 212 insertions(+), 32 deletions(-)
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 79c1b31ccc41..6c5b83a08182 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -983,6 +983,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
fetch_sub(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_fetch_sub(&_M_p, _S_type_size(__d), int(__m)); }
+
+#if __glibcxx_atomic_min_max
+ _GLIBCXX_ALWAYS_INLINE __pointer_type
+ fetch_min(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
+
+ _GLIBCXX_ALWAYS_INLINE __pointer_type
+ fetch_min(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
+
+ _GLIBCXX_ALWAYS_INLINE __pointer_type
+ fetch_max(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
+
+ _GLIBCXX_ALWAYS_INLINE __pointer_type
+ fetch_max(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
+#endif
};
namespace __atomic_impl
@@ -1976,6 +1998,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::fetch_sub(this->_M_ptr, _S_type_size(__d), __m); }
+#if __glibcxx_atomic_min_max
+ _GLIBCXX_ALWAYS_INLINE value_type
+ fetch_min(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); }
+
+ _GLIBCXX_ALWAYS_INLINE value_type
+ fetch_max(value_type __i,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ { return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); }
+#endif
+
value_type
operator++(int) const noexcept
{ return fetch_add(1); }
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 306667e3c633..3ec218afa096 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -718,6 +718,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
return _M_b.fetch_sub(__d, __m);
}
+
+#if __glibcxx_atomic_min_max
+ __pointer_type
+ fetch_min(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return _M_b.fetch_min(__p, __m); }
+
+ __pointer_type
+ fetch_min(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return _M_b.fetch_min(__p, __m); }
+
+ __pointer_type
+ fetch_max(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { return _M_b.fetch_max(__p, __m); }
+
+ __pointer_type
+ fetch_max(__pointer_type __p,
+ memory_order __m = memory_order_seq_cst) volatile noexcept
+ { return _M_b.fetch_max(__p, __m); }
+#endif
};
@@ -1574,31 +1596,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __a->fetch_xor(__i, __m); }
#ifdef __cpp_lib_atomic_min_max
- template<typename _ITp>
- inline _ITp
- atomic_fetch_min_explicit(__atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i,
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_min_explicit(atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_min(__i, __m); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_min_explicit(volatile __atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i,
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_min_explicit(volatile atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_min(__i, __m); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_max_explicit(__atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i,
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_max_explicit(atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_max(__i, __m); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_max_explicit(volatile __atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i,
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_max_explicit(volatile atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_max(__i, __m); }
#endif
@@ -1664,28 +1686,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
#ifdef __cpp_lib_atomic_min_max
- template<typename _ITp>
- inline _ITp
- atomic_fetch_min(__atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i) noexcept
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_min(atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_min(volatile __atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i) noexcept
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_min(volatile atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_max(__atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i) noexcept
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_max(atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
- template<typename _ITp>
- inline _ITp
- atomic_fetch_max(volatile __atomic_base<_ITp>* __a,
- __atomic_val_t<_ITp> __i) noexcept
+ template<typename _Tp>
+ inline _Tp
+ atomic_fetch_max(volatile atomic<_Tp>* __a,
+ __atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
#endif
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc
new file mode 100644
index 000000000000..aca0c3157e0c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+// { dg-require-atomic-cmpxchg-word "" }
+// { dg-add-options libatomic }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01() {
+ long arr[10] = {};
+
+ const auto mo = std::memory_order_relaxed;
+ std::atomic<long *> a(arr);
+
+ auto v = atomic_fetch_max(&a, arr + 5);
+ VERIFY(v == arr);
+ VERIFY(a == arr + 5);
+ v = atomic_fetch_max_explicit(&a, arr + 2, mo);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 5);
+
+ v = atomic_fetch_min(&a, arr + 3);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 3);
+ v = atomic_fetch_min_explicit(&a, arr + 5, mo);
+ VERIFY(v == arr + 3);
+ VERIFY(a == arr + 3);
+}
+
+void test02() {
+ char arr[10] = {};
+
+ const auto mo = std::memory_order_relaxed;
+ std::atomic<char *> a(arr);
+
+ auto v = atomic_fetch_max(&a, arr + 5);
+ VERIFY(v == arr);
+ VERIFY(a == arr + 5);
+ v = atomic_fetch_max_explicit(&a, arr + 2, mo);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 5);
+
+ v = atomic_fetch_min(&a, arr + 3);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 3);
+ v = atomic_fetch_min_explicit(&a, arr + 5, mo);
+ VERIFY(v == arr + 3);
+ VERIFY(a == arr + 3);
+}
+
+int main() {
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
new file mode 100644
index 000000000000..25eef63ba992
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
@@ -0,0 +1,71 @@
+// { dg-do run { target c++26 } }
+// { dg-require-atomic-cmpxchg-word "" }
+// { dg-add-options libatomic }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01() {
+ long arr[10] = {};
+ long *value;
+
+ {
+ const auto mo = std::memory_order_relaxed;
+ std::atomic_ref<long *> a(value);
+ bool ok = a.is_lock_free();
+ if constexpr (std::atomic_ref<long *>::is_always_lock_free)
+ VERIFY(ok);
+ a = arr;
+
+ auto v = a.fetch_max(arr + 5);
+ VERIFY(v == arr);
+ VERIFY(a == arr + 5);
+ v = a.fetch_max(arr + 2, mo);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 5);
+
+ v = a.fetch_min(arr + 3);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 3);
+ v = a.fetch_min(arr + 5, mo);
+ VERIFY(v == arr + 3);
+ VERIFY(a == arr + 3);
+ }
+
+ VERIFY(value == arr + 3);
+}
+
+void test02() {
+ char arr[10] = {};
+ char *value;
+
+ {
+ const auto mo = std::memory_order_relaxed;
+ std::atomic_ref<char *> a(value);
+ bool ok = a.is_lock_free();
+ if constexpr (std::atomic_ref<char *>::is_always_lock_free)
+ VERIFY(ok);
+ a = arr;
+
+ auto v = a.fetch_max(arr + 5);
+ VERIFY(v == arr);
+ VERIFY(a == arr + 5);
+ v = a.fetch_max(arr + 2, mo);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 5);
+
+ v = a.fetch_min(arr + 3);
+ VERIFY(v == arr + 5);
+ VERIFY(a == arr + 3);
+ v = a.fetch_min(arr + 5, mo);
+ VERIFY(v == arr + 3);
+ VERIFY(a == arr + 3);
+ }
+
+ VERIFY(value == arr + 3);
+}
+
+int main() {
+ test01();
+ test02();
+}
More information about the Libstdc++-cvs
mailing list