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

Reply via email to