https://gcc.gnu.org/g:10b8379252e91c2e129f88482240b12ca392d5e2

commit r16-2131-g10b8379252e91c2e129f88482240b12ca392d5e2
Author: Paul Keir <pk...@outlook.com>
Date:   Tue Jul 8 13:36:49 2025 +0100

    libstdc++: Add smart ptr owner_equals and owner_hash [PR117403]
    
    New structs and member functions added to C++26 by P1901R2.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/117403
            * include/bits/shared_ptr.h (shared_ptr::owner_equal)
            (shared_ptr::owner_hash, weak_ptr::owner_equal)
            (weak_ptr::owner_hash): Define new member functions.
            * include/bits/shared_ptr_base.h (owner_equal, owner_hash):
            Define new structs.
            * include/bits/version.def (smart_ptr_owner_equality): Define.
            * include/bits/version.h: Regenerate.
            * include/std/memory: Added define for
            __glibcxx_want_smart_ptr_owner_equality.
            * testsuite/20_util/owner_equal/version.cc: New test.
            * testsuite/20_util/owner_equal/cmp.cc: New test.
            * testsuite/20_util/owner_equal/noexcept.cc: New test.
            * testsuite/20_util/owner_hash/cmp.cc: New test.
            * testsuite/20_util/owner_hash/noexcept.cc: New test.
            * testsuite/20_util/shared_ptr/observers/owner_equal.cc: New
            test.
            * testsuite/20_util/shared_ptr/observers/owner_hash.cc:
            New test.
            * testsuite/20_util/weak_ptr/observers/owner_equal.cc: New test.
            * testsuite/20_util/weak_ptr/observers/owner_hash.cc: New test.
    
    Signed-off-by: Paul Keir <paul.k...@uws.ac.uk>

Diff:
---
 libstdc++-v3/include/bits/shared_ptr.h             |  58 ++++++++++++
 libstdc++-v3/include/bits/shared_ptr_base.h        |  40 ++++++++
 libstdc++-v3/include/bits/version.def              |   9 ++
 libstdc++-v3/include/bits/version.h                |  10 ++
 libstdc++-v3/include/std/memory                    |   1 +
 libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc  | 105 +++++++++++++++++++++
 .../testsuite/20_util/owner_equal/noexcept.cc      |  30 ++++++
 .../testsuite/20_util/owner_equal/version.cc       |  13 +++
 libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc   |  87 +++++++++++++++++
 .../testsuite/20_util/owner_hash/noexcept.cc       |  16 ++++
 .../20_util/shared_ptr/observers/owner_equal.cc    |  74 +++++++++++++++
 .../20_util/shared_ptr/observers/owner_hash.cc     |  71 ++++++++++++++
 .../20_util/weak_ptr/observers/owner_equal.cc      |  52 ++++++++++
 .../20_util/weak_ptr/observers/owner_hash.cc       |  50 ++++++++++
 14 files changed, 616 insertions(+)

diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
b/libstdc++-v3/include/bits/shared_ptr.h
index a196a0f1212e..f2b46015aaaf 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -909,6 +909,64 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
     { };
 
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+
+  /**
+   * @brief Provides ownership-based hashing.
+   * @headerfile memory
+   * @since C++26
+   */
+  struct owner_hash
+  {
+    template<typename _Tp>
+      size_t
+      operator()(const shared_ptr<_Tp>& __s) const noexcept
+      { return __s.owner_hash(); }
+
+    template<typename _Tp>
+      size_t
+      operator()(const weak_ptr<_Tp>& __s) const noexcept
+      { return __s.owner_hash(); }
+
+    using is_transparent = void;
+  };
+
+  /**
+   * @brief Provides ownership-based mixed equality comparisons of
+   *        shared and weak pointers.
+   * @headerfile memory
+   * @since C++26
+   */
+  struct owner_equal
+  {
+    template<typename _Tp1, typename _Tp2>
+      bool
+      operator()(const shared_ptr<_Tp1>& __lhs,
+                const shared_ptr<_Tp2>& __rhs) const noexcept
+      { return __lhs.owner_equal(__rhs); }
+
+    template<typename _Tp1, typename _Tp2>
+      bool
+      operator()(const shared_ptr<_Tp1>& __lhs,
+                const   weak_ptr<_Tp2>& __rhs) const noexcept
+      { return __lhs.owner_equal(__rhs); }
+
+    template<typename _Tp1, typename _Tp2>
+      bool
+      operator()(const   weak_ptr<_Tp1>& __lhs,
+                const shared_ptr<_Tp2>& __rhs) const noexcept
+      { return __lhs.owner_equal(__rhs); }
+
+    template<typename _Tp1, typename _Tp2>
+      bool
+      operator()(const weak_ptr<_Tp1>& __lhs,
+                const weak_ptr<_Tp2>& __rhs)   const noexcept
+      { return __lhs.owner_equal(__rhs); }
+
+    using is_transparent = void;
+  };
+#endif
+
   /**
    * @brief Base class allowing use of the member function `shared_from_this`.
    * @headerfile memory
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h 
b/libstdc++-v3/include/bits/shared_ptr_base.h
index b4be1b49e4da..fb868e7afc36 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -1122,6 +1122,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_less(const __weak_count<_Lp>& __rhs) const noexcept
       { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
 
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+      size_t
+      _M_owner_hash() const noexcept
+      { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); }
+#endif
+
       // Friend function injected into enclosing namespace and found by ADL
       friend inline bool
       operator==(const __shared_count& __a, const __shared_count& __b) noexcept
@@ -1225,6 +1231,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_less(const __shared_count<_Lp>& __rhs) const noexcept
       { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
 
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+      size_t
+      _M_owner_hash() const noexcept
+      { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); }
+#endif
+
       // Friend function injected into enclosing namespace and found by ADL
       friend inline bool
       operator==(const __weak_count& __a, const __weak_count& __b) noexcept
@@ -1715,6 +1727,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        { return _M_refcount._M_less(__rhs._M_refcount); }
       /// @}
 
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+      size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); 
}
+
+      template<typename _Tp1>
+       bool
+       owner_equal(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept
+       { return _M_refcount == __rhs._M_refcount; }
+
+      template<typename _Tp1>
+       bool
+       owner_equal(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept
+       { return _M_refcount == __rhs._M_refcount; }
+#endif
+
     protected:
       // This constructor is non-standard, it is used by allocate_shared.
       template<typename _Alloc, typename... _Args>
@@ -2098,6 +2124,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
        { return _M_refcount._M_less(__rhs._M_refcount); }
 
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+      size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); 
}
+
+      template<typename _Tp1>
+      bool
+      owner_equal(const __shared_ptr<_Tp1, _Lp> & __rhs) const noexcept
+      { return _M_refcount == __rhs._M_refcount; }
+
+      template<typename _Tp1>
+      bool
+      owner_equal(const __weak_ptr<_Tp1, _Lp> & __rhs) const noexcept
+      { return _M_refcount == __rhs._M_refcount; }
+#endif
+
       void
       reset() noexcept
       { __weak_ptr().swap(*this); }
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index f1015abdbfae..31385b53107a 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2006,6 +2006,15 @@ ftms = {
   };
 };
 
+ftms = {
+  name = smart_ptr_owner_equality;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+    hosted = yes;
+  };
+};
+
 ftms = {
   name = sstream_from_string_view;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 80f6586372d3..aa53f299848f 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2249,6 +2249,16 @@
 #endif /* !defined(__cpp_lib_polymorphic) && 
defined(__glibcxx_want_polymorphic) */
 #undef __glibcxx_want_polymorphic
 
+#if !defined(__cpp_lib_smart_ptr_owner_equality)
+# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
+#  define __glibcxx_smart_ptr_owner_equality 202306L
+#  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_smart_ptr_owner_equality)
+#   define __cpp_lib_smart_ptr_owner_equality 202306L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_smart_ptr_owner_equality) && 
defined(__glibcxx_want_smart_ptr_owner_equality) */
+#undef __glibcxx_want_smart_ptr_owner_equality
+
 #if !defined(__cpp_lib_sstream_from_string_view)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
 #  define __glibcxx_sstream_from_string_view 202306L
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 1da03b3ea6a9..763a57ee998d 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -121,6 +121,7 @@
 #define __glibcxx_want_smart_ptr_for_overwrite
 #define __glibcxx_want_to_address
 #define __glibcxx_want_transparent_operators
+#define __glibcxx_want_smart_ptr_owner_equality
 #include <bits/version.h>
 
 #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
diff --git a/libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc 
b/libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
new file mode 100644
index 000000000000..311ddf247487
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
@@ -0,0 +1,105 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+  // test empty shared_ptr owners compare equivalent
+  std::owner_equal eq;
+  std::shared_ptr<A> p1;
+  std::shared_ptr<A> p2;
+  VERIFY( eq(p1, p2) && eq(p2, p1) );
+  std::weak_ptr<A> p3;
+  VERIFY( eq(p1, p3) && eq(p3, p1) );
+  VERIFY( eq(p1, p3) && eq(p3, p1) );
+  return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+  std::owner_equal eq;
+
+  std::shared_ptr<A> empty;
+
+  std::shared_ptr<A> a1(new A);
+  VERIFY( !eq(empty, a1) && !eq(a1, empty) );
+
+  std::shared_ptr<A> a2(new A);
+  VERIFY( !eq(a1, a2) && !eq(a2, a1) );
+
+  std::weak_ptr<A> w1(a1);
+  VERIFY( eq(a1, w1) && eq(w1, a1) );
+
+  std::weak_ptr<A> w2(a2);
+  VERIFY( !eq(w1, w2) && !eq(w2, w1) );
+
+  a1.reset();
+  VERIFY( eq(empty, a1) && eq(a1, empty) );
+  VERIFY( !eq(a1, w1) && !eq(w1, a1) );
+
+  a2.reset();
+  VERIFY( eq(a2, a1) && eq(a1, a2) );
+
+  return 0;
+}
+
+// aliasing
+int
+test03()
+{
+  std::owner_equal eq;
+
+  std::shared_ptr<B> b(new B);
+  std::shared_ptr<A> a0(b, &b->a[0]);
+  std::shared_ptr<A> a1(b, &b->a[1]);
+  // values are different but owners are equivalent:
+  VERIFY( a0 < a1 && eq(a0, a1) && eq(b, a0) && eq(b, a1) );
+
+  std::weak_ptr<A> w0(a0);
+  std::weak_ptr<A> w1(a1);
+  VERIFY( eq(w0, w1) && eq(w1, w0) );
+  VERIFY( eq(a0, w1) && eq(w1, a0) );
+  VERIFY( eq(w0, a1) && eq(a1, w0) );
+
+  return 0;
+}
+
+// as binary predicate
+int
+test04()
+{
+  std::owner_equal eq;
+
+  std::shared_ptr<B> b(new B);
+  std::shared_ptr<A> a0(b, &b->a[0]);
+  std::shared_ptr<A> a1(b, &b->a[1]);
+  std::shared_ptr<A> c(new A);
+  std::weak_ptr<A> a[3]{a0, a1, c};
+  std::weak_ptr<A>* p = std::unique(a, a+3, eq);
+  VERIFY( p == &a[2] );
+
+  return 0;
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc 
b/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
new file mode 100644
index 000000000000..fb479f60a743
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <memory>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in 
<memory>"
+#endif
+
+const std::owner_equal eq;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+static_assert( noexcept(!eq(wi, wi)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, sl)) );
+static_assert( noexcept(!eq(sl, si)) );
+static_assert( noexcept(!eq(si, wc)) );
+static_assert( noexcept(!eq(wc, si)) );
+static_assert( noexcept(!eq(wc, wi)) );
diff --git a/libstdc++-v3/testsuite/20_util/owner_equal/version.cc 
b/libstdc++-v3/testsuite/20_util/owner_equal/version.cc
new file mode 100644
index 000000000000..db29154c5785
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/version.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 17.3.2 Header <version> synopsis [version.syn]
+
+#include <version>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <version>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in 
<version>"
+#endif
+
diff --git a/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc 
b/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc
new file mode 100644
index 000000000000..c03a9266d080
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc
@@ -0,0 +1,87 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+  // test empty shared_ptr hashes compare equivalent
+  std::owner_hash oh;
+  std::shared_ptr<A> p1;
+  std::shared_ptr<A> p2;
+  VERIFY( oh(p1) == oh(p2) );
+  std::weak_ptr<A> p3;
+  VERIFY( oh(p1) == oh(p3) );
+  VERIFY( oh(p1) == oh(p3) );
+  return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+  std::owner_hash oh;
+
+  std::shared_ptr<A> empty;
+
+  std::shared_ptr<A> a1(new A);
+  VERIFY( oh(empty) != oh(a1) );
+
+  std::shared_ptr<A> a2(new A);
+  VERIFY( oh(a1) != oh(a2) );
+
+  std::weak_ptr<A> w1(a1);
+  VERIFY( oh(a1) == oh(w1) );
+
+  std::weak_ptr<A> w2(a2);
+  VERIFY( oh(w1) != oh(w2) );
+
+  a1.reset();
+  VERIFY( oh(empty) == oh(a1) );
+  VERIFY( oh(a1) != oh(w1) );
+
+  a2.reset();
+  VERIFY( oh(a2) == oh(a1) );
+
+  return 0;
+}
+
+// aliasing
+int
+test03()
+{
+  std::owner_hash oh;
+
+  std::shared_ptr<B> b(new B);
+  std::shared_ptr<A> a0(b, &b->a[0]);
+  std::shared_ptr<A> a1(b, &b->a[1]);
+  // values are different but owners are ohuivalent:
+  VERIFY( a0 < a1 && oh(a0) == oh(a1) && oh(b) == oh(a0) && oh(b) == oh(a1) );
+
+  std::weak_ptr<A> w0(a0);
+  std::weak_ptr<A> w1(a1);
+  VERIFY( oh(w0) == oh(w1) );
+  VERIFY( oh(a0) == oh(w1) );
+  VERIFY( oh(w0) == oh(a1) );
+
+  return 0;
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc 
b/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc
new file mode 100644
index 000000000000..12b2f2fd04f2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+
+const std::owner_hash oh;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!oh(si)) );
+static_assert( noexcept(!oh(wi)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!oh(sl)) );
+static_assert( noexcept(!oh(wc)) );
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc 
b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc
new file mode 100644
index 000000000000..7ec86919ccfa
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc
@@ -0,0 +1,74 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+  int i;
+  virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+  // test empty shared_ptr owners compare equivalent
+  std::shared_ptr<A> p1;
+  std::shared_ptr<B> p2;
+  VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+  std::shared_ptr<A> a0;
+
+  std::shared_ptr<A> a1(new A);
+  VERIFY( !a1.owner_equal(a0) && !a0.owner_equal(a1) );
+
+  std::shared_ptr<B> b1(new B);
+  VERIFY( !a1.owner_equal(b1) && !b1.owner_equal(a1) );
+
+  std::shared_ptr<A> a2(a1);
+  VERIFY( a1.owner_equal(a2) && a2.owner_equal(a1) );
+  a2 = b1;
+  VERIFY( b1.owner_equal(a2) && a2.owner_equal(b1) );
+
+  std::weak_ptr<A> w1(a1);
+  VERIFY( a1.owner_equal(w1) && w1.owner_equal(a1) );
+  std::weak_ptr<A> w2(a2);
+  VERIFY( b1.owner_equal(w2) && w2.owner_equal(b1) );
+
+  static_assert( noexcept(a1.owner_equal(a0)) );
+  static_assert( noexcept(a1.owner_equal(b1)) );
+  static_assert( noexcept(b1.owner_equal(a1)) );
+  static_assert( noexcept(a1.owner_equal(w1)) );
+  static_assert( noexcept(b1.owner_equal(w1)) );
+}
+
+// Aliasing
+void
+test03()
+{
+  std::shared_ptr<A> p1(new A());
+  std::shared_ptr<int> p2(p1, &p1->i);
+  VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc 
b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc
new file mode 100644
index 000000000000..8e6c02cf162c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc
@@ -0,0 +1,71 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+  int i;
+  virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+  // test empty shared_ptr hashes compare equivalent
+  std::shared_ptr<A> p1;
+  std::shared_ptr<B> p2;
+  VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+  std::shared_ptr<A> a0;
+
+  std::shared_ptr<A> a1(new A);
+  VERIFY( a1.owner_hash() != a0.owner_hash() );
+
+  std::shared_ptr<B> b1(new B);
+  VERIFY( a1.owner_hash() != b1.owner_hash() );
+
+  std::shared_ptr<A> a2(a1);
+  VERIFY( a1.owner_hash() == a2.owner_hash() );
+  a2 = b1;
+  VERIFY( b1.owner_hash() == a2.owner_hash() );
+
+  std::weak_ptr<A> w1(a1);
+  VERIFY( a1.owner_hash() == w1.owner_hash() );
+  std::weak_ptr<A> w2(a2);
+  VERIFY( b1.owner_hash() == w2.owner_hash() );
+
+  static_assert( noexcept(a1.owner_hash()) );
+  static_assert( noexcept(b1.owner_hash()) );
+}
+
+// Aliasing
+void
+test03()
+{
+  std::shared_ptr<A> p1(new A());
+  std::shared_ptr<int> p2(p1, &p1->i);
+  VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc 
b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc
new file mode 100644
index 000000000000..0217a6e5899e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc
@@ -0,0 +1,52 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+  // test empty weak_ptr owners compare equivalent
+  std::weak_ptr<A> p1;
+  std::weak_ptr<B> p2;
+  VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+
+  std::shared_ptr<B> p3;
+  VERIFY( p1.owner_equal(p3) && p3.owner_equal(p1) );
+
+  static_assert( noexcept(p1.owner_equal(p1)) );
+  static_assert( noexcept(p1.owner_equal(p2)) );
+  static_assert( noexcept(p1.owner_equal(p3)) );
+  static_assert( noexcept(p2.owner_equal(p1)) );
+}
+
+
+void
+test02()
+{
+  std::shared_ptr<A> a0;
+  std::weak_ptr<A> w0(a0);
+
+  std::shared_ptr<A> a1(new A);
+  std::weak_ptr<A> w1(a1);
+  VERIFY(  a1.owner_equal(w1) &&  w1.owner_equal(a1) );
+  VERIFY( !w1.owner_equal(w0) && !w0.owner_equal(w1) );
+  VERIFY( !w1.owner_equal(a0) && !a0.owner_equal(w1) );
+
+  std::shared_ptr<B> b1(new B);
+  VERIFY( !w1.owner_equal(b1) && !b1.owner_equal(w1) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc 
b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc
new file mode 100644
index 000000000000..148a93be0991
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc
@@ -0,0 +1,50 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+  // test empty weak_ptr hashes compare equivalent
+  std::weak_ptr<A> p1;
+  std::weak_ptr<B> p2;
+  VERIFY( p1.owner_hash() == p2.owner_hash() );
+
+  std::shared_ptr<B> p3;
+  VERIFY( p1.owner_hash() == p3.owner_hash() );
+
+  static_assert( noexcept(p1.owner_hash()) );
+  static_assert( noexcept(p2.owner_hash()) );
+}
+
+
+void
+test02()
+{
+  std::shared_ptr<A> a0;
+  std::weak_ptr<A> w0(a0);
+
+  std::shared_ptr<A> a1(new A);
+  std::weak_ptr<A> w1(a1);
+  VERIFY( a1.owner_hash() == w1.owner_hash() );
+  VERIFY( w1.owner_hash() != w0.owner_hash() );
+  VERIFY( w1.owner_hash() != a0.owner_hash() );
+
+  std::shared_ptr<B> b1(new B);
+  VERIFY( w1.owner_hash() != b1.owner_hash() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  return 0;
+}

Reply via email to