]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Add smart ptr owner_equals and owner_hash [PR117403]
authorPaul Keir <pkeir@outlook.com>
Tue, 8 Jul 2025 12:36:49 +0000 (13:36 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 9 Jul 2025 11:14:40 +0000 (12:14 +0100)
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.keir@uws.ac.uk>
14 files changed:
libstdc++-v3/include/bits/shared_ptr.h
libstdc++-v3/include/bits/shared_ptr_base.h
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/include/std/memory
libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/owner_equal/version.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc [new file with mode: 0644]

index a196a0f1212e66e09115f8b76f513b73184e54c8..f2b46015aaafcdc64e004b87480c24dec065219b 100644 (file)
@@ -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
index b4be1b49e4da51cbafd9b8868dbd5777ad21380d..fb868e7afc3677f0f2cfee4790bb217e9b1aabfd 100644 (file)
@@ -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); }
index f1015abdbfaed68f23fd50ea86ec4e926d2bf5a9..31385b53107a10c98d6a905e470c928b748eacf3 100644 (file)
@@ -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 = {
index 80f6586372d3a18daaacd7e3077596e7fe9ced1b..aa53f299848f13f58d3e090988f61958c1e76bcc 100644 (file)
 #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
index 1da03b3ea6a9fb4037906574349d4d92f29acce5..763a57ee998d0ca27e376ce570ef3ee19dd9ff2d 100644 (file)
 #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 (file)
index 0000000..311ddf2
--- /dev/null
@@ -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 (file)
index 0000000..fb479f6
--- /dev/null
@@ -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 (file)
index 0000000..db29154
--- /dev/null
@@ -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 (file)
index 0000000..c03a926
--- /dev/null
@@ -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 (file)
index 0000000..12b2f2f
--- /dev/null
@@ -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 (file)
index 0000000..7ec8691
--- /dev/null
@@ -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 (file)
index 0000000..8e6c02c
--- /dev/null
@@ -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 (file)
index 0000000..0217a6e
--- /dev/null
@@ -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 (file)
index 0000000..148a93b
--- /dev/null
@@ -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;
+}