Pushed to trunk now - thanks for contributing this!
On Tue, 8 Jul 2025 at 18:32, Paul Keir <paul.k...@uws.ac.uk> wrote:
>
> Thanks Jonathan.
>
>
> ________________________________________
> From: Jonathan Wakely <jwak...@redhat.com>
> Sent: 08 July 2025 1:37 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 Tue, 8 Jul 2025 at 13:24, Jonathan Wakely <jwak...@redhat.com> wrote:
> >
> > 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.
>
> OK, I added your github fork and did a merge --squash from there
>
>
> >
> >
> > >
> > > ________________________________________
> > > 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.
> > >
>
>
>
> 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.
>