[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