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.