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.

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}.
        * include/std/atomic: Extend pointer support for nonmember funcs.
        * testsuite/29_atomics/atomic_integral/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               | 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,
                              __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
@@ -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