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