On Wed, Feb 25, 2026 at 4:19 AM Jonathan Wakely <[email protected]> wrote:
>
> On Mon, 23 Feb 2026 at 15:26 +0800, Yuao Ma wrote:
> >Hi,
> >
> >Previous implementations of fetch_min/max(r16-7097-g68a1218c189cce)
> >only supported integrals, not handling pointers. To complete the paper
> >P0493R5, we need to implement support for pointers as well. This patch
> >adds the missing functionality and test cases.
>
> Oh well spotted.
>
> >Regression tested on x86_64-linux, ok for trunk?
>
>
> >Thanks,
> >Yuao
>
> >From 1fc8439ab78a6695fd67263ce31f452e1e12a356 Mon Sep 17 00:00:00 2001
> >From: Yuao Ma <[email protected]>
> >Date: Mon, 23 Feb 2026 15:15:56 +0800
> >Subject: [PATCH] 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: Extend pointer support for atomic{,
> > _ref}.
>
> Please say what you actually changed. The GNU ChangeLog format is
> documented here:
> https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html
>
> For this change it should be something like:
>
> * include/bits/atomic_base.h (__atomic_base<T*>::fetch_min)
> (__atomic_base<T*>::fetch_max): Define new functions.
> (__atomic_ref<P, false, false, true>::fetch_min): Likewise.
> (__atomic_ref<P, false, false, true>::fetch_max): Likewise.
>
> > * include/std/atomic: Extend pointer support for nonmember funcs.
>
> Again, this doesn't tell us what actually changed.
>
> * include/std/atomic (atomic_fetch_min_explicit): Change
> parameter from __atomic_base<I>* to atomic<I>*.
> (atomic_fetch_max_explicit, atomic_fetch_min)
> (atomic_fetch_max): Likewise.
>
> > * testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc: New
> > test.
> > * testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc: New test.
>
> These lines are too long, please add line breaks to keep them to
> around 72 chars or less (when that's possible):
>
> * testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc:
> New test.
> * testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc: New
> test.
>
Thanks for the detailed guidance about the commit msg! Current version
is more detailed and has proper line wrap.
> >---
> > libstdc++-v3/include/bits/atomic_base.h | 34 +++++++++
> > libstdc++-v3/include/std/atomic | 38 +++++++---
> > .../atomic_integral/pointer_fetch_minmax.cc | 53 ++++++++++++++
> > .../atomic_ref/pointer_fetch_minmax.cc | 71 +++++++++++++++++++
> > 4 files changed, 188 insertions(+), 8 deletions(-)
> > create mode 100644
> > libstdc++-v3/testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc
> > create mode 100644
> > libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
> >
> >diff --git a/libstdc++-v3/include/bits/atomic_base.h
> >b/libstdc++-v3/include/bits/atomic_base.h
> >index 79c1b31ccc4..6c5b83a0818 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 306667e3c63..07c422d6e82 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
> > };
> >
> >
> >@@ -1576,28 +1598,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > #ifdef __cpp_lib_atomic_min_max
> > template<typename _ITp>
> > inline _ITp
> >- atomic_fetch_min_explicit(__atomic_base<_ITp>* __a,
> >+ atomic_fetch_min_explicit(atomic<_ITp>* __a,
>
> I thought that maybe we need to constrain this to only be valid for
> integer and pointer types, but actually the standard just says "If no
> such member function exists, the program is ill-formed." in
> [atomics.nonmembers].
>
> Could you please change the _ITp parameter to _Tp in all these
> atomic_fetch_{min,max}{,_explicit} functions though? Now that they're
> not specific to integer types, _ITp is misleading.
>
That makes sense. Done.
> > __atomic_val_t<_ITp> __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_fetch_min_explicit(volatile atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __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_fetch_max_explicit(atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __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_fetch_max_explicit(volatile atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __i,
> > memory_order __m) noexcept
> > { return __a->fetch_max(__i, __m); }
> >@@ -1666,25 +1688,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > #ifdef __cpp_lib_atomic_min_max
> > template<typename _ITp>
> > inline _ITp
> >- atomic_fetch_min(__atomic_base<_ITp>* __a,
> >+ atomic_fetch_min(atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __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_fetch_min(volatile atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __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_fetch_max(atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __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_fetch_max(volatile atomic<_ITp>* __a,
> > __atomic_val_t<_ITp> __i) noexcept
> > { return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
> > #endif
> >diff --git
> >a/libstdc++-v3/testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc
> >b/libstdc++-v3/testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc
> >new file mode 100644
> >index 00000000000..aca0c3157e0
> >--- /dev/null
> >+++
> >b/libstdc++-v3/testsuite/29_atomics/atomic_integral/pointer_fetch_minmax.cc
>
> The 29_atomics/atomic_integral directory is for the integer
> specializations, please put this new test file in 29_atomics/atomic
> instead (we don't have a directory for atomic<T*> specializations,
> maybe we should).
>
Moved to atomic/ folder.
> >@@ -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 00000000000..25eef63ba99
> >--- /dev/null
> >+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
>
> This directory is fine though.
>
> >@@ -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();
> >+}
> >--
> >2.53.0
> >
>
From 2c3af4f09120c16bd3bcfcaaf56200158dbc636e Mon Sep 17 00:00:00 2001
From: Yuao Ma <[email protected]>
Date: Wed, 25 Feb 2026 20:44:07 +0800
Subject: [PATCH] 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.
---
libstdc++-v3/include/bits/atomic_base.h | 34 ++++++++
libstdc++-v3/include/std/atomic | 86 ++++++++++++-------
.../29_atomics/atomic/pointer_fetch_minmax.cc | 53 ++++++++++++
.../atomic_ref/pointer_fetch_minmax.cc | 71 +++++++++++++++
4 files changed, 212 insertions(+), 32 deletions(-)
create mode 100644
libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc
create mode 100644
libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
diff --git a/libstdc++-v3/include/bits/atomic_base.h
b/libstdc++-v3/include/bits/atomic_base.h
index 79c1b31ccc4..6c5b83a0818 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 306667e3c63..3ec218afa09 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 00000000000..aca0c3157e0
--- /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 00000000000..25eef63ba99
--- /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();
+}
--
2.53.0