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. >