No problem. That should be it included below. Github diff for convenience: 
https://github.com/gcc-mirror/gcc/compare/e37eb85...pkeir:gcc:1b7c7c1a

Signed-off-by: Paul Keir <paul.k...@uws.ac.uk>

Tested on x86_64-linux.

libstdc++-v3/ChangeLog:

        * include/bits/shared_ptr.h: Added owner_equal and owner_hash members 
to shared_ptr and weak_ptr.
        * include/bits/shared_ptr_base.h: Added owner_equal and owner_hash 
structs.
        * include/bits/version.def: Added __cpp_lib_smart_ptr_owner_equality 
feature macro.
        * include/bits/version.h: Update generated for 
__cpp_lib_smart_ptr_owner_equality feature macro.
        * 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.

---

 include/bits/shared_ptr.h                          |  57 +++++++++++
 include/bits/shared_ptr_base.h                     |  40 ++++++++
 include/bits/version.def                           |   9 ++
 include/bits/version.h                             |  10 ++
 include/std/memory                                 |   1 +
 testsuite/20_util/owner_equal/cmp.cc               | 105 +++++++++++++++++++++
 testsuite/20_util/owner_equal/noexcept.cc          |  30 ++++++
 testsuite/20_util/owner_equal/version.cc           |  13 +++
 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 ++++++++++
 testsuite/20_util/weak_ptr/observers/owner_hash.cc |  50 ++++++++++
 14 files changed, 615 insertions(+)

diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
b/libstdc++-v3/include/bits/shared_ptr.h
index a196a0f1212..dd02ab16e59 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -909,6 +909,63 @@ _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 b4be1b49e4d..f820d31e56b 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 9ab22cc519f..971bbebd54e 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1995,6 +1995,15 @@ ftms = {
   };
 };

+ftms = {
+  name = smart_ptr_owner_equality;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+    hosted = yes;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 371a7ba3b1a..b395baa612e 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2233,4 +2233,14 @@
 #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
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 1da03b3ea6a..763a57ee998 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 00000000000..311ddf24748
--- /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 00000000000..fb479f60a74
--- /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 00000000000..db29154c578
--- /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 00000000000..c03a9266d08
--- /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 00000000000..12b2f2fd04f
--- /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 00000000000..7ec86919ccf
--- /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 00000000000..8e6c02cf162
--- /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 00000000000..0217a6e5899
--- /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 00000000000..148a93be099
--- /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;
+}

________________________________________
From: Jonathan Wakely <jwak...@redhat.com>
Sent: 06 June 2025 12:27 PM
To: Paul Keir
Cc: gcc-patches@gcc.gnu.org; libstd...@gcc.gnu.org
Subject: Re: [PATCH] libstdc++: Add smart ptr owner_equals and owner_hash 
structs and members for P1901R2



Warning: Do not open attachments or click on links unless you trust the sender



On 23/05/25 17:55 +0000, Paul Keir wrote:
>This patch implements C++26 "Enabling the Use of weak_ptr as Keys in Unordered 
>Associative Containers", as specified in P1901R2.
>
>I don't have write access.
>
>Signed-off-by: Paul Keir <paul.k...@uws.ac.uk>
>
>Tested on x86_64-linux.
>
>libstdc++-v3/ChangeLog:
>
>        * include/bits/shared_ptr.h: Added owner_equal and owner_hash members 
> to shared_ptr and weak_ptr
>        * include/bits/shared_ptr_base.h: Added owner_equal and owner_hash 
> structs
>        * 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.
>
>---
>
> libstdc++-v3/include/bits/shared_ptr.h             |  57 ++++++++++
> libstdc++-v3/include/bits/shared_ptr_base.h        |  40 +++++++
> libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc  | 122 +++++++++++++++++++++
> .../testsuite/20_util/owner_equal/noexcept.cc      |  39 +++++++
> libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc   | 104 ++++++++++++++++++
> .../testsuite/20_util/owner_hash/noexcept.cc       |  31 ++++++
> .../20_util/shared_ptr/observers/owner_equal.cc    |  93 ++++++++++++++++
> .../20_util/shared_ptr/observers/owner_hash.cc     |  90 +++++++++++++++
> .../20_util/weak_ptr/observers/owner_equal.cc      |  71 ++++++++++++
> .../20_util/weak_ptr/observers/owner_hash.cc       |  69 ++++++++++++
> 10 files changed, 716 insertions(+)
>
>diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
>b/libstdc++-v3/include/bits/shared_ptr.h
>index a196a0f1212..9f25f6ccc23 100644
>--- a/libstdc++-v3/include/bits/shared_ptr.h
>+++ b/libstdc++-v3/include/bits/shared_ptr.h
>@@ -909,6 +909,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
>     { };
>
>+#if __cplusplus > 202302L

All these preprocessor checks should now use the new macro you've
defined in bits/version.h

#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26

(the __glibcxx_smart_ptr_owner_equality macro is the internal one
that's always defined after including bits/version.h, whereas the
__cpp_lib_xxx one will only be defined by <memory> and <version>).

Apart from that, the current diff at
https://github.com/gcc-mirror/gcc/compare/97e8cd9...pkeir:gcc:4f699d8
looks good for trunk.

If you can change those #if checks and send a new patch to the list,
I'll get it pushed to trunk.

Thanks!




Please consider the environment and think before you print.

The University of the West of Scotland is a registered Scottish charity. 
Charity number SC002520.

This e-mail and any attachment is for authorised use by the intended 
recipient(s) only. It may contain proprietary material, confidential 
information and/or be subject to legal privilege. It should not be copied, 
disclosed to, retained or used by, any other party. If you are not an intended 
recipient then please promptly delete this e-mail and any attachment and all 
copies and inform the sender.

Please note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of the University of the 
West of Scotland.

As a public body, the University of the West of Scotland may be required to 
make available emails as well as other written forms of information as a result 
of a request made under the Freedom of Information (Scotland) Act 2002.

Reply via email to