[libcxx-commits] [libcxx] 1b3d208 - [libc++] Implement P1901R2: owner_hash and owner_equal for shared_ptr/weak_ptr (#210551)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 27 03:00:50 PDT 2026
Author: Avi Patel
Date: 2026-07-27T18:00:45+08:00
New Revision: 1b3d208c77145b670207a646050bbe2cc8aea567
URL: https://github.com/llvm/llvm-project/commit/1b3d208c77145b670207a646050bbe2cc8aea567
DIFF: https://github.com/llvm/llvm-project/commit/1b3d208c77145b670207a646050bbe2cc8aea567.diff
LOG: [libc++] Implement P1901R2: owner_hash and owner_equal for shared_ptr/weak_ptr (#210551)
Fixes #105372.
## Acknowledgements
Claude assisted with test development.
Added:
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerhash/owner_hash.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_shared_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_weak_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_hash.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/ReleaseNotes/24.rst
libcxx/docs/Status/Cxx26Papers.csv
libcxx/include/__memory/shared_ptr.h
libcxx/include/memory
libcxx/include/version
libcxx/modules/std/memory.inc
libcxx/test/libcxx/utilities/smartptr/nodiscard.verify.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 108702e71dec7..60af581e122ec 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -526,7 +526,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_senders`` *unimplemented*
---------------------------------------------------------- -----------------
- ``__cpp_lib_smart_ptr_owner_equality`` *unimplemented*
+ ``__cpp_lib_smart_ptr_owner_equality`` ``202306L``
---------------------------------------------------------- -----------------
``__cpp_lib_span_at`` ``202311L``
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index e20fa560865ad..2cd6a4c756113 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -42,6 +42,7 @@ Implemented Papers
- P0792R14: ``function_ref`` : a type-erased callable reference (`Github <https://llvm.org/PR105376>`__)
- P3948R1: ``constant_wrapper`` is the only tool needed for passing constant expressions via function arguments (`Github <https://llvm.org/PR189604>`__)
- P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)
+- P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index 81b20f6088097..855ac2533a282 100644
--- a/libcxx/docs/Status/Cxx26Papers.csv
+++ b/libcxx/docs/Status/Cxx26Papers.csv
@@ -12,7 +12,7 @@
"`P2338R4 <https://wg21.link/P2338R4>`__","Freestanding Library: Character primitives and the C library","2023-06 (Varna)","","","`#105369 <https://github.com/llvm/llvm-project/issues/105369>`__",""
"`P2013R5 <https://wg21.link/P2013R5>`__","Freestanding Language: Optional ``::operator new``","2023-06 (Varna)","","","`#105370 <https://github.com/llvm/llvm-project/issues/105370>`__",""
"`P2363R5 <https://wg21.link/P2363R5>`__","Extending associative containers with the remaining heterogeneous overloads","2023-06 (Varna)","","","`#105371 <https://github.com/llvm/llvm-project/issues/105371>`__",""
-"`P1901R2 <https://wg21.link/P1901R2>`__","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","2023-06 (Varna)","","","`#105372 <https://github.com/llvm/llvm-project/issues/105372>`__",""
+"`P1901R2 <https://wg21.link/P1901R2>`__","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","2023-06 (Varna)","|Complete|","24","`#105372 <https://github.com/llvm/llvm-project/issues/105372>`__",""
"`P1885R12 <https://wg21.link/P1885R12>`__","Naming Text Encodings to Demystify Them","2023-06 (Varna)","|Complete|","23","`#105373 <https://github.com/llvm/llvm-project/issues/105373>`__",""
"`P0792R14 <https://wg21.link/P0792R14>`__","``function_ref``: a type-erased callable reference","2023-06 (Varna)","|Complete|","24","`#105376 <https://github.com/llvm/llvm-project/issues/105376>`__",""
"`P2874R2 <https://wg21.link/P2874R2>`__","P2874R2: Mandating Annex D Require No More","2023-06 (Varna)","|Complete|","12","`#105377 <https://github.com/llvm/llvm-project/issues/105377>`__",""
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 4112c1175b9e1..7d8a0d27739a0 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -18,6 +18,7 @@
#include <__cstddef/ptr
diff _t.h>
#include <__exception/exception.h>
#include <__functional/binary_function.h>
+#include <__functional/hash.h>
#include <__functional/operations.h>
#include <__functional/reference_wrapper.h>
#include <__fwd/ostream.h>
@@ -555,6 +556,22 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
_LIBCPP_HIDE_FROM_ABI bool __owner_equivalent(const shared_ptr& __p) const { return __cntrl_ == __p.__cntrl_; }
+#if _LIBCPP_STD_VER >= 26
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t owner_hash() const noexcept {
+ return std::hash<__shared_weak_count*>()(__cntrl_);
+ }
+
+ template <class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(shared_ptr<_Up> const& __p) const noexcept {
+ return __cntrl_ == __p.__cntrl_;
+ }
+
+ template <class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(weak_ptr<_Up> const& __p) const noexcept {
+ return __cntrl_ == __p.__cntrl_;
+ }
+#endif
+
#if _LIBCPP_STD_VER >= 17
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator[](ptr
diff _t __i) const {
static_assert(is_array<_Tp>::value, "std::shared_ptr<T>::operator[] is only valid when T is an array type.");
@@ -1245,6 +1262,22 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI weak_ptr {
return __cntrl_ < __r.__cntrl_;
}
+#if _LIBCPP_STD_VER >= 26
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t owner_hash() const noexcept {
+ return std::hash<__shared_weak_count*>()(__cntrl_);
+ }
+
+ template <class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(shared_ptr<_Up> const& __p) const noexcept {
+ return __cntrl_ == __p.__cntrl_;
+ }
+
+ template <class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(weak_ptr<_Up> const& __p) const noexcept {
+ return __cntrl_ == __p.__cntrl_;
+ }
+#endif
+
template <class _Up>
friend class weak_ptr;
template <class _Up>
@@ -1318,6 +1351,46 @@ struct owner_less<void> {
};
#endif
+#if _LIBCPP_STD_VER >= 26
+struct owner_hash {
+ template <class _Tp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(shared_ptr<_Tp> const& __p) const noexcept {
+ return __p.owner_hash();
+ }
+ template <class _Tp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(weak_ptr<_Tp> const& __p) const noexcept {
+ return __p.owner_hash();
+ }
+
+ using is_transparent = void;
+};
+
+struct owner_equal {
+ template <class _Tp, class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const noexcept {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(shared_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const noexcept {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(weak_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const noexcept {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(weak_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const noexcept {
+ return __x.owner_equal(__y);
+ }
+
+ using is_transparent = void;
+};
+#endif
+
template <class _Tp>
class enable_shared_from_this {
mutable weak_ptr<_Tp> __weak_this_;
diff --git a/libcxx/include/memory b/libcxx/include/memory
index d5d48ed9a9e6d..6a16358324f10 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -633,6 +633,9 @@ public:
explicit operator bool() const noexcept;
template<class U> bool owner_before(shared_ptr<U> const& b) const noexcept;
template<class U> bool owner_before(weak_ptr<U> const& b) const noexcept;
+ size_t owner_hash() const noexcept; // C++26
+ template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26
+ template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26
};
template<class T>
@@ -771,6 +774,9 @@ public:
shared_ptr<T> lock() const noexcept;
template<class U> bool owner_before(shared_ptr<U> const& b) const noexcept;
template<class U> bool owner_before(weak_ptr<U> const& b) const noexcept;
+ size_t owner_hash() const noexcept; // C++26
+ template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26
+ template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26
};
template<class T>
@@ -817,6 +823,31 @@ struct owner_less<void>
typedef void is_transparent;
};
+// struct owner_hash
+struct owner_hash { // C++26
+ template<class T>
+ size_t operator()(const shared_ptr<T>&) const noexcept;
+
+ template<class T>
+ size_t operator()(const weak_ptr<T>&) const noexcept;
+
+ using is_transparent = unspecified;
+};
+
+// struct owner_equal
+struct owner_equal { // C++26
+ template<class T, class U>
+ bool operator()(const shared_ptr<T>&, const shared_ptr<U>&) const noexcept;
+ template<class T, class U>
+ bool operator()(const shared_ptr<T>&, const weak_ptr<U>&) const noexcept;
+ template<class T, class U>
+ bool operator()(const weak_ptr<T>&, const shared_ptr<U>&) const noexcept;
+ template<class T, class U>
+ bool operator()(const weak_ptr<T>&, const weak_ptr<U>&) const noexcept;
+
+ using is_transparent = unspecified;
+};
+
template<class T>
class enable_shared_from_this
{
diff --git a/libcxx/include/version b/libcxx/include/version
index 9160c51835d6f..5d0b96a1fe230 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -628,7 +628,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202603L
// # define __cpp_lib_senders 202406L
-// # define __cpp_lib_smart_ptr_owner_equality 202306L
+# define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
# define __cpp_lib_sstream_from_string_view 202306L
# define __cpp_lib_string_subview 202506L
diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc
index c25e9e3443e9c..0338ec0db325e 100644
--- a/libcxx/modules/std/memory.inc
+++ b/libcxx/modules/std/memory.inc
@@ -171,6 +171,14 @@ export namespace std {
// [util.smartptr.ownerless], class template owner_less
using std::owner_less;
+#if _LIBCPP_STD_VER >= 26
+ // [util.smartptr.owner.hash], class owner_hash
+ using std::owner_hash;
+
+ // [util.smartptr.owner.equal], class owner_equal
+ using std::owner_equal;
+#endif
+
// [util.smartptr.enab], class template enable_shared_from_this
using std::enable_shared_from_this;
diff --git a/libcxx/test/libcxx/utilities/smartptr/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/smartptr/nodiscard.verify.cpp
index 6943a4002c245..84020942f0a74 100644
--- a/libcxx/test/libcxx/utilities/smartptr/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/smartptr/nodiscard.verify.cpp
@@ -59,6 +59,14 @@ void test() {
sPtr.owner_before(std::shared_ptr<int>());
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
sPtr.owner_before(std::weak_ptr<int>());
+#if TEST_STD_VER >= 26
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sPtr.owner_hash();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sPtr.owner_equal(std::shared_ptr<int>());
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sPtr.owner_equal(std::weak_ptr<int>());
+#endif
#if TEST_STD_VER >= 17
sPtr[0]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
#endif
@@ -138,7 +146,31 @@ void test() {
wPtr.owner_before(std::weak_ptr<int>());
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
wPtr.owner_before(std::shared_ptr<int>());
+#if TEST_STD_VER >= 26
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ wPtr.owner_hash();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ wPtr.owner_equal(std::weak_ptr<int>());
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ wPtr.owner_equal(std::shared_ptr<int>());
+#endif
+ }
+#if TEST_STD_VER >= 26
+ { // [util.smartptr.owner.hash], [util.smartptr.owner.equal]
+ std::shared_ptr<int> sPtr;
+ std::weak_ptr<int> wPtr;
+
+ std::owner_hash oh;
+ oh(sPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ oh(wPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ std::owner_equal oe;
+ oe(sPtr, sPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ oe(sPtr, wPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ oe(wPtr, sPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ oe(wPtr, wPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
+#endif
{ // [util.smartptr.enab]
class EnableShared : public std::enable_shared_from_this<EnableShared> {};
EnableShared es;
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index c58357a463ffd..dc14ff766ac5c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -648,17 +648,11 @@
# error "__cpp_lib_smart_ptr_for_overwrite should have the value 202002L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
-# endif
-# if __cpp_lib_smart_ptr_owner_equality != 202306L
-# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_smart_ptr_owner_equality
+# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
+# endif
+# if __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
# endif
# ifndef __cpp_lib_to_address
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 3af3d6694c6bf..9143d715ff7d7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -8012,17 +8012,11 @@
# error "__cpp_lib_smart_ptr_for_overwrite should have the value 202002L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
-# endif
-# if __cpp_lib_smart_ptr_owner_equality != 202306L
-# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_smart_ptr_owner_equality
+# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
+# endif
+# if __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
# endif
# ifndef __cpp_lib_source_location
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp
new file mode 100644
index 0000000000000..356ad0ab48275
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// shared_ptr
+
+// template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::shared_ptr<void> empty1;
+ const std::shared_ptr<long> empty2;
+
+ std::same_as<bool> decltype(auto) result = p1.owner_equal(p2);
+ assert(result);
+ static_assert(noexcept(p1.owner_equal(p2)));
+
+ assert(p2.owner_equal(p1));
+ assert(!p1.owner_equal(p3));
+ assert(!p3.owner_equal(p1));
+
+ assert(empty1.owner_equal(empty2));
+ assert(!p1.owner_equal(empty1));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp
new file mode 100644
index 0000000000000..11166b2bec49d
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// shared_ptr
+
+// template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w3(p3);
+ const std::shared_ptr<void> empty_sp;
+ const std::weak_ptr<long> empty_wp;
+
+ std::same_as<bool> decltype(auto) result = p1.owner_equal(w1);
+ assert(result);
+ static_assert(noexcept(p1.owner_equal(w1)));
+
+ assert(p2.owner_equal(w1));
+ assert(!p1.owner_equal(w3));
+ assert(!p3.owner_equal(w1));
+
+ assert(empty_sp.owner_equal(empty_wp));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp
new file mode 100644
index 0000000000000..79ebea344ba74
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// shared_ptr
+
+// size_t owner_hash() const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <memory>
+
+#include "test_macros.h"
+
+struct Pair {
+ int a;
+ int b;
+};
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::weak_ptr<int> w1(p1);
+
+ std::same_as<std::size_t> decltype(auto) hash1 = p1.owner_hash();
+ static_assert(noexcept(p1.owner_hash()));
+
+ assert(hash1 == p2.owner_hash());
+ assert(hash1 == w1.owner_hash());
+
+ const std::shared_ptr<Pair> sp(new Pair{1, 2});
+ const std::shared_ptr<int> alias(sp, &sp->b);
+ assert(static_cast<void*>(sp.get()) != static_cast<void*>(alias.get()));
+ assert(sp.owner_hash() == alias.owner_hash());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp
new file mode 100644
index 0000000000000..ce8580c7547b2
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// struct owner_equal
+// {
+// template<class T, class U>
+// bool operator()(shared_ptr<T> const&, shared_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(shared_ptr<T> const&, weak_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(weak_ptr<T> const&, shared_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(weak_ptr<T> const&, weak_ptr<U> const&) const noexcept;
+//
+// using is_transparent = unspecified;
+// };
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+#include <unordered_set>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w3(p3);
+
+ std::owner_equal oe;
+
+ std::same_as<bool> decltype(auto) result = oe(p1, p2);
+ assert(result);
+ static_assert(noexcept(oe(p1, p2)));
+ static_assert(noexcept(oe(p1, w1)));
+ static_assert(noexcept(oe(w1, p1)));
+ static_assert(noexcept(oe(w1, w1)));
+
+ assert(oe(p1, w1));
+ assert(oe(w1, p1));
+ assert(oe(w1, w1));
+
+ assert(!oe(p1, p3));
+ assert(!oe(p1, w3));
+ assert(!oe(w1, p3));
+ assert(!oe(w1, w3));
+
+ using member_is_transparent [[maybe_unused]] = std::owner_equal::is_transparent;
+ LIBCPP_STATIC_ASSERT(std::same_as<member_is_transparent, void>);
+
+ {
+ std::unordered_set<std::weak_ptr<int>, std::owner_hash, std::owner_equal> s;
+ s.insert(w1);
+ assert(s.count(w1) == 1);
+ assert(s.count(std::weak_ptr<int>(p2)) == 1);
+ assert(s.count(w3) == 0);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerhash/owner_hash.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerhash/owner_hash.pass.cpp
new file mode 100644
index 0000000000000..fa0931abe3a3e
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerhash/owner_hash.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// struct owner_hash
+// {
+// template<class T>
+// size_t operator()(shared_ptr<T> const&) const noexcept;
+// template<class T>
+// size_t operator()(weak_ptr<T> const&) const noexcept;
+//
+// using is_transparent = unspecified;
+// };
+
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::weak_ptr<int> w1(p1);
+
+ std::owner_hash oh;
+
+ std::same_as<std::size_t> decltype(auto) hash_p1 = oh(p1);
+ std::same_as<std::size_t> decltype(auto) hash_w1 = oh(w1);
+ static_assert(noexcept(oh(p1)));
+ static_assert(noexcept(oh(w1)));
+
+ assert(hash_p1 == p1.owner_hash());
+ assert(hash_w1 == w1.owner_hash());
+ assert(hash_p1 == oh(p2));
+ assert(hash_p1 == hash_w1);
+
+ using member_is_transparent [[maybe_unused]] = std::owner_hash::is_transparent;
+ LIBCPP_STATIC_ASSERT(std::same_as<member_is_transparent, void>);
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_shared_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_shared_ptr.pass.cpp
new file mode 100644
index 0000000000000..f71131f7369e3
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_shared_ptr.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// weak_ptr
+
+// template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<void> empty;
+
+ std::same_as<bool> decltype(auto) result = w1.owner_equal(p1);
+ assert(result);
+ static_assert(noexcept(w1.owner_equal(p1)));
+
+ assert(!w1.owner_equal(p3));
+
+ const std::shared_ptr<long> empty_sp;
+ assert(empty.owner_equal(empty_sp));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_weak_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_weak_ptr.pass.cpp
new file mode 100644
index 0000000000000..d0e8b6e657673
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_equal_weak_ptr.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// weak_ptr
+
+// template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w2(p1);
+ const std::weak_ptr<int> w3(p3);
+ const std::weak_ptr<void> empty1;
+ const std::weak_ptr<long> empty2;
+
+ std::same_as<bool> decltype(auto) result = w1.owner_equal(w2);
+ assert(result);
+ static_assert(noexcept(w1.owner_equal(w2)));
+
+ assert(w2.owner_equal(w1));
+ assert(!w1.owner_equal(w3));
+ assert(!w3.owner_equal(w1));
+
+ assert(empty1.owner_equal(empty2));
+ assert(!w1.owner_equal(empty1));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_hash.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_hash.pass.cpp
new file mode 100644
index 0000000000000..aac6fec718d5d
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.obs/owner_hash.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <memory>
+
+// weak_ptr
+
+// size_t owner_hash() const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <memory>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w2(p1);
+
+ std::same_as<std::size_t> decltype(auto) hash1 = w1.owner_hash();
+ static_assert(noexcept(w1.owner_hash()));
+
+ assert(hash1 == w2.owner_hash());
+ assert(hash1 == p1.owner_hash());
+
+ return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 145be8c4f33cd..09126c14478bc 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1314,7 +1314,6 @@ def add_version_header(tc):
"c++26": 202306 # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
},
"headers": ["memory"],
- "unimplemented": True,
},
{
"name": "__cpp_lib_source_location",
More information about the libcxx-commits
mailing list