On Tue, 8 Jul 2025 at 12:54, Paul Keir <paul.k...@uws.ac.uk> wrote:
>
> Let me know if this needs a refresh.

The patch fails to apply:

error: patch failed: libstdc++-v3/include/bits/shared_ptr_base.h:1715
error: libstdc++-v3/include/bits/shared_ptr_base.h: patch does not apply

but I think it's your mail client munging whitespace, not something
that can be fixed by rebasing on trunk.
I'll figure it out and apply it by hand.


>
> ________________________________________
> From: Paul Keir <paul.k...@uws.ac.uk>
> Sent: 06 June 2025 5:32 PM
> To: Jonathan Wakely
> 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
>
> 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