https://gcc.gnu.org/g:0772974fec9d1e35c412fc6fcbe9754c7cb57eb0

commit r16-7714-g0772974fec9d1e35c412fc6fcbe9754c7cb57eb0
Author: Yuao Ma <[email protected]>
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();
+}

Reply via email to