[libcxx-commits] [libcxx] [libc++] Implement P2077R3 Heterogeneous erasure overloads for associative containers (PR #78277)

Mital Ashok via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 16 05:57:27 PST 2024


https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/78277

>From 51a7b54edf34154ddde1e77720467a8db84025db Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Tue, 16 Jan 2024 13:31:06 +0000
Subject: [PATCH] [libc++] Implement P2077R3 Heterogeneous erasure overloads
 for associative containers

---
 libcxx/docs/ReleaseNotes/18.rst               |  1 +
 libcxx/docs/Status/Cxx23Papers.csv            |  4 +-
 libcxx/include/__hash_table                   |  8 +--
 libcxx/include/__tree                         |  8 +--
 libcxx/include/map                            | 40 +++++++++++--
 libcxx/include/set                            | 36 ++++++++++-
 libcxx/include/unordered_map                  | 36 ++++++++++-
 libcxx/include/unordered_set                  | 42 +++++++++++--
 libcxx/include/version                        |  2 +-
 .../map/map.modifiers/erase_tran.pass.cpp     | 56 ++++++++++++++++++
 .../erase_tran1.compile.fail.cpp              | 38 ++++++++++++
 .../erase_tran2.compile.fail.cpp              | 38 ++++++++++++
 .../erase_tran3.compile.fail.cpp              | 38 ++++++++++++
 .../map/map.modifiers/erase_tran4.pass.cpp    | 45 ++++++++++++++
 .../map/map.modifiers/erase_tran5.pass.cpp    | 49 +++++++++++++++
 .../map/map.modifiers/extract_tran.pass.cpp   | 59 +++++++++++++++++++
 .../extract_tran1.compile.fail.cpp            | 38 ++++++++++++
 .../extract_tran2.compile.fail.cpp            | 38 ++++++++++++
 .../extract_tran3.compile.fail.cpp            | 38 ++++++++++++
 .../map/map.modifiers/extract_tran4.pass.cpp  | 45 ++++++++++++++
 .../map/map.modifiers/extract_tran5.pass.cpp  | 49 +++++++++++++++
 .../multimap.modifiers/erase_tran.pass.cpp    | 56 ++++++++++++++++++
 .../erase_tran1.compile.fail.cpp              | 38 ++++++++++++
 .../erase_tran2.compile.fail.cpp              | 38 ++++++++++++
 .../erase_tran3.compile.fail.cpp              | 38 ++++++++++++
 .../multimap.modifiers/erase_tran4.pass.cpp   | 45 ++++++++++++++
 .../multimap.modifiers/erase_tran5.pass.cpp   | 49 +++++++++++++++
 .../multimap.modifiers/extract_tran.pass.cpp  | 59 +++++++++++++++++++
 .../extract_tran1.compile.fail.cpp            | 38 ++++++++++++
 .../extract_tran2.compile.fail.cpp            | 38 ++++++++++++
 .../extract_tran3.compile.fail.cpp            | 38 ++++++++++++
 .../multimap.modifiers/extract_tran4.pass.cpp | 45 ++++++++++++++
 .../multimap.modifiers/extract_tran5.pass.cpp | 49 +++++++++++++++
 .../associative/multiset/erase_tran.pass.cpp  | 56 ++++++++++++++++++
 .../multiset/erase_tran1.compile.fail.cpp     | 38 ++++++++++++
 .../multiset/erase_tran2.compile.fail.cpp     | 38 ++++++++++++
 .../multiset/erase_tran3.compile.fail.cpp     | 38 ++++++++++++
 .../associative/multiset/erase_tran4.pass.cpp | 45 ++++++++++++++
 .../associative/multiset/erase_tran5.pass.cpp | 49 +++++++++++++++
 .../multiset/extract_tran.pass.cpp            | 59 +++++++++++++++++++
 .../multiset/extract_tran1.compile.fail.cpp   | 38 ++++++++++++
 .../multiset/extract_tran2.compile.fail.cpp   | 38 ++++++++++++
 .../multiset/extract_tran3.compile.fail.cpp   | 38 ++++++++++++
 .../multiset/extract_tran4.pass.cpp           | 45 ++++++++++++++
 .../multiset/extract_tran5.pass.cpp           | 49 +++++++++++++++
 .../associative/set/erase_tran.pass.cpp       | 56 ++++++++++++++++++
 .../set/erase_tran1.compile.fail.cpp          | 38 ++++++++++++
 .../set/erase_tran2.compile.fail.cpp          | 38 ++++++++++++
 .../set/erase_tran3.compile.fail.cpp          | 38 ++++++++++++
 .../associative/set/erase_tran4.pass.cpp      | 45 ++++++++++++++
 .../associative/set/erase_tran5.pass.cpp      | 49 +++++++++++++++
 .../associative/set/extract_tran.pass.cpp     | 59 +++++++++++++++++++
 .../set/extract_tran1.compile.fail.cpp        | 38 ++++++++++++
 .../set/extract_tran2.compile.fail.cpp        | 38 ++++++++++++
 .../set/extract_tran3.compile.fail.cpp        | 38 ++++++++++++
 .../associative/set/extract_tran4.pass.cpp    | 45 ++++++++++++++
 .../associative/set/extract_tran5.pass.cpp    | 49 +++++++++++++++
 57 files changed, 2277 insertions(+), 24 deletions(-)
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/erase_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/map/map.modifiers/extract_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/erase_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/extract_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/erase_tran5.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran1.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran2.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran3.compile.fail.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran4.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/extract_tran5.pass.cpp

diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 62a1fec627d0ca..8db818ef490203 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -60,6 +60,7 @@ Implemented Papers
 - P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``)
 - P1759R6 - Native handles and file streams
 - P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``
+- P2077R3 - Heterogeneous erasure overloads for associative containers
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index ebab3ef735b617..5e091f6151399b 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -30,7 +30,7 @@
 "`P1147R1 <https://wg21.link/P1147R1>`__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0"
 "`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0"
 "`P1675R2 <https://wg21.link/P1675R2>`__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","",""
-"`P2077R3 <https://wg21.link/P2077R3>`__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","",""
+"`P2077R3 <https://wg21.link/P2077R3>`__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","|Complete|","18.0"
 "`P2251R1 <https://wg21.link/P2251R1>`__","LWG","Require ``span`` & ``basic_string_view`` to be Trivially Copyable","October 2021","|Complete|","14.0"
 "`P2301R1 <https://wg21.link/P2301R1>`__","LWG","Add a ``pmr`` alias for ``std::stacktrace``","October 2021","",""
 "`P2321R2 <https://wg21.link/P2321R2>`__","LWG","``zip``","October 2021","|In Progress|","","|ranges|"
@@ -59,7 +59,7 @@
 "`P1467R9 <https://wg21.link/P1467R9>`__","LWG","Extended ``floating-point`` types and standard names","July 2022","",""
 "`P1642R11 <https://wg21.link/P1642R11>`__","LWG","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","July 2022","",""
 "`P1899R3 <https://wg21.link/P1899R3>`__","LWG","``stride_view``","July 2022","","","|ranges|"
-"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","","|Complete|","18.0"
+"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","|Complete|","18.0",""
 "`P2165R4 <https://wg21.link/P2165R4>`__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","",""
 "`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|"
 "`P2286R8 <https://wg21.link/P2286R8>`__","LWG","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|"
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 4ca49fe42606c7..0d7c38f9d056f5 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -836,8 +836,8 @@ public:
   template <class _Table>
   _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Table& __source);
 
-  template <class _NodeHandle>
-  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const& __key);
+  template <class _NodeHandle, class _Key>
+  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_find_and_extract(const _Key& __key);
   template <class _NodeHandle>
   _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator __it);
 #endif
@@ -1579,9 +1579,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(const_iter
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _NodeHandle>
+template <class _NodeHandle, class _Key>
 _LIBCPP_HIDE_FROM_ABI _NodeHandle
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(key_type const& __key) {
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_find_and_extract(const _Key& __key) {
   iterator __i = find(__key);
   if (__i == end())
     return _NodeHandle();
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 2dcc3c614d3660..84cda01df51494 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1168,8 +1168,8 @@ public:
   template <class _Tree>
   _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Tree& __source);
 
-  template <class _NodeHandle>
-  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const&);
+  template <class _NodeHandle, class _Key>
+  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_find_and_extract(const _Key&);
   template <class _NodeHandle>
   _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator);
 #endif
@@ -1963,8 +1963,8 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __
 }
 
 template <class _Tp, class _Compare, class _Allocator>
-template <class _NodeHandle>
-_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(key_type const& __key) {
+template <class _NodeHandle, class _Key>
+_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_find_and_extract(const _Key& __key) {
   iterator __it = find(__key);
   if (__it == end())
     return _NodeHandle();
diff --git a/libcxx/include/map b/libcxx/include/map
index f122f2ebb15b52..5b3515c228e0b5 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -149,6 +149,8 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
@@ -170,8 +172,10 @@ public:
         iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);        // C++17
 
     iterator  erase(const_iterator position);
-    iterator  erase(iterator position); // C++14
+    iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -428,12 +432,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     iterator insert(node_type&& nh);                                                  // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
-    iterator  erase(iterator position); // C++14
+    iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -1309,6 +1317,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) {
     return __tree_.erase(__f.__i_, __l.__i_);
   }
@@ -1326,11 +1340,17 @@ public:
     return __tree_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(map<key_type, mapped_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -1900,6 +1920,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) {
     return __tree_.erase(__f.__i_, __l.__i_);
   }
@@ -1916,11 +1942,17 @@ public:
     return __tree_.template __node_handle_insert_multi<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
diff --git a/libcxx/include/set b/libcxx/include/set
index 55ba8f8208be1b..832ed876253c86 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -125,12 +125,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
     iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -370,12 +374,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     iterator insert(node_type&& nh);                                                  // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
     iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -764,6 +772,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
   _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
 
@@ -779,11 +793,17 @@ public:
     return __tree_.template __node_handle_insert_unique<node_type>(__hint, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -1222,6 +1242,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
   _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
 
@@ -1237,11 +1263,17 @@ public:
     return __tree_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 4be25fc1cdd8fe..42889a06ed019a 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -139,6 +139,8 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator           insert(const_iterator hint, node_type&& nh);                   // C++17
 
@@ -162,6 +164,8 @@ public:
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -425,12 +429,16 @@ public:
 
     node_type extract(const_iterator position);                // C++17
     node_type extract(const key_type& x);                      // C++17
+    template <class K>
+        node_type extract(K&& x);                              // C++23
     iterator insert(node_type&& nh);                           // C++17
     iterator insert(const_iterator hint, node_type&& nh);      // C++17
 
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -1322,6 +1330,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
     return __table_.erase(__first.__i_, __last.__i_);
   }
@@ -1339,11 +1353,17 @@ public:
     return __table_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __table_.template __node_handle_extract<node_type>(__key);
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __table_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
 
   template <class _H2, class _P2>
   _LIBCPP_HIDE_FROM_ABI void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>& __source) {
@@ -2073,6 +2093,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
     return __table_.erase(__first.__i_, __last.__i_);
   }
@@ -2090,11 +2116,17 @@ public:
     return __table_.template __node_handle_insert_multi<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __table_.template __node_handle_extract<node_type>(__key);
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __table_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
 
   template <class _H2, class _P2>
   _LIBCPP_HIDE_FROM_ABI void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>& __source) {
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 6414885f4c514a..009ef835a0d523 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -131,12 +131,16 @@ public:
 
     node_type extract(const_iterator position);                       // C++17
     node_type extract(const key_type& x);                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                     // C++23
     insert_return_type insert(node_type&& nh);                        // C++17
     iterator           insert(const_iterator hint, node_type&& nh);   // C++17
 
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -379,12 +383,16 @@ public:
 
     node_type extract(const_iterator position);             // C++17
     node_type extract(const key_type& x);                   // C++17
+    template <class K>
+        node_type extract(K&& x);                           // C++23
     iterator insert(node_type&& nh);                        // C++17
     iterator insert(const_iterator hint, node_type&& nh);   // C++17
 
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -777,6 +785,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
     return __table_.erase(__first, __last);
   }
@@ -794,11 +808,17 @@ public:
     return __table_.template __node_handle_insert_unique<node_type>(__h, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __table_.template __node_handle_extract<node_type>(__key);
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __table_.template __node_handle_extract<node_type>(__it);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
 
   template <class _H2, class _P2>
   _LIBCPP_HIDE_FROM_ABI void merge(unordered_set<key_type, _H2, _P2, allocator_type>& __source) {
@@ -1389,12 +1409,18 @@ public:
                                         "node_type with incompatible allocator passed to unordered_multiset::insert()");
     return __table_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh));
   }
-  _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __position) {
-    return __table_.template __node_handle_extract<node_type>(__position);
-  }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __table_.template __node_handle_extract<node_type>(__key);
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+  _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
+    return __table_.template __node_handle_extract<node_type>(__it);
+  }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
   }
+#endif
 
   template <class _H2, class _P2>
   _LIBCPP_HIDE_FROM_ABI void merge(unordered_multiset<key_type, _H2, _P2, allocator_type>& __source) {
@@ -1424,6 +1450,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
     return __table_.erase(__first, __last);
   }
diff --git a/libcxx/include/version b/libcxx/include/version
index c96647894dce63..d514f3e5003507 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -434,7 +434,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 #if _LIBCPP_STD_VER >= 23
 # define __cpp_lib_adaptor_iterator_pair_constructor    202106L
 # define __cpp_lib_allocate_at_least                    202106L
-// # define __cpp_lib_associative_heterogeneous_erasure    202110L
+# define __cpp_lib_associative_heterogeneous_erasure    202110L
 // # define __cpp_lib_bind_back                            202202L
 # define __cpp_lib_byteswap                             202110L
 # define __cpp_lib_constexpr_bitset                     202207L
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran.pass.cpp
new file mode 100644
index 00000000000000..b9072ec5bd5f52
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::map<int, double, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::map<int, double, transparent_less> M;
+    M example;
+    example.insert({5, 1.});
+    example.insert({6, 2.});
+    example.insert({4, 0.});
+    assert(example.size() == 3);
+    M::size_type erased = example.erase(C2Int{5});
+    assert(erased == 1);
+    assert(example.size() == 2);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..1202b3b95c73d6
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..5b49a587b5a495
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..db642780b9b2e2
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran4.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran4.pass.cpp
new file mode 100644
index 00000000000000..0d8330c674020c
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::map<int, double, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert({2, 3.});
+    M::iterator erased = example.erase(Convertible());
+    assert(example.empty() && erased == example.end());
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran5.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran5.pass.cpp
new file mode 100644
index 00000000000000..84a8a94c3ba678
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/erase_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::map<int, double, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert({0, 1.});
+    M::size_type erased = example.erase(c);
+    assert(erased == 1);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran.pass.cpp
new file mode 100644
index 00000000000000..00767524e77648
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::map<int, double, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::map<int, double, transparent_less> M;
+    M example;
+    example.insert({5, 1.});
+    example.insert({6, 2.});
+    example.insert({4, 0.});
+    assert(example.size() == 3);
+    M::node_type nh = example.extract(C2Int{5});
+    assert(nh && nh.key() == 5 && nh.mapped() == 1.);
+    assert(example.size() == 2);
+    example.insert(std::move(nh));
+    assert(example.size() == 3);
+    assert(example.find(5)->second == 1.);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..f819541a53c5de
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..2eb03312986bb1
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..e01eef5c5a438c
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::map<int, double, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran4.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran4.pass.cpp
new file mode 100644
index 00000000000000..4d469fad49272e
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::map<int, double, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert({2, 3.});
+    M::node_type nh = example.extract(Convertible());
+    assert(nh && nh.key() == 2 && nh.mapped() == 3.);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran5.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran5.pass.cpp
new file mode 100644
index 00000000000000..1adc76488f5264
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/extract_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class map
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::map<int, double, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert({0, 1.});
+    M::node_type nh = example.extract(c);
+    assert(nh && nh.key() == 0 && nh.mapped() == 1.);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran.pass.cpp
new file mode 100644
index 00000000000000..525518e9115f28
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::multimap<int, double, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::multimap<int, double, transparent_less> M;
+    M example;
+    example.insert({5, 1.});
+    example.insert({6, 2.});
+    example.insert({4, 0.});
+    assert(example.size() == 3);
+    M::size_type erased = example.erase(C2Int{5});
+    assert(erased == 1);
+    assert(example.size() == 2);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..59c7010b7dca58
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..773a9c74d7d2f0
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..f5d43e4ab528e4
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran4.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran4.pass.cpp
new file mode 100644
index 00000000000000..843dc49cd288c6
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multimap<int, double, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert({2, 3.});
+    M::iterator erased = example.erase(Convertible());
+    assert(example.empty() && erased == example.end());
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran5.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran5.pass.cpp
new file mode 100644
index 00000000000000..748d6d9d6da541
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multimap<int, double, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert({0, 1.});
+    M::size_type erased = example.erase(c);
+    assert(erased == 1);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran.pass.cpp
new file mode 100644
index 00000000000000..5e0748870ef328
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::multimap<int, double, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::multimap<int, double, transparent_less> M;
+    M example;
+    example.insert({5, 1.});
+    example.insert({6, 2.});
+    example.insert({4, 0.});
+    assert(example.size() == 3);
+    M::node_type nh = example.extract(C2Int{5});
+    assert(nh && nh.key() == 5 && nh.mapped() == 1.);
+    assert(example.size() == 2);
+    example.insert(std::move(nh));
+    assert(example.size() == 3);
+    assert(example.find(5)->second == 1.);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..1c987a690c9564
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..c31f29bd2e148a
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..6af18080257fe6
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multimap<int, double, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran4.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran4.pass.cpp
new file mode 100644
index 00000000000000..6ae8b1b6681acd
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multimap<int, double, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert({2, 3.});
+    M::node_type nh = example.extract(Convertible());
+    assert(nh && nh.key() == 2 && nh.mapped() == 3.);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran5.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran5.pass.cpp
new file mode 100644
index 00000000000000..5b74e667eeffcd
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <map>
+
+// class multimap
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <map>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multimap<int, double, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert({0, 1.});
+    M::node_type nh = example.extract(c);
+    assert(nh && nh.key() == 0 && nh.mapped() == 1.);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran.pass.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran.pass.cpp
new file mode 100644
index 00000000000000..bc74b05dd7635e
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::multiset<int, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::multiset<int, transparent_less> M;
+    M example;
+    example.insert(5);
+    example.insert(6);
+    example.insert(4);
+    assert(example.size() == 3);
+    M::size_type erased = example.erase(C2Int{5});
+    assert(erased == 1);
+    assert(example.size() == 2);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..6cdd9965c3fcac
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..d02d7f7e0bf689
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..5a88dac5ca0ab5
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran4.pass.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran4.pass.cpp
new file mode 100644
index 00000000000000..a96f9184ec88d6
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multiset<int, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert(2);
+    M::iterator erased = example.erase(Convertible());
+    assert(example.empty() && erased == example.end());
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/erase_tran5.pass.cpp b/libcxx/test/std/containers/associative/multiset/erase_tran5.pass.cpp
new file mode 100644
index 00000000000000..4809b8680f82dd
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/erase_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multiset<int, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert(0);
+    M::size_type erased = example.erase(c);
+    assert(erased == 1);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran.pass.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran.pass.cpp
new file mode 100644
index 00000000000000..84931ed27633f3
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::multiset<int, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::multiset<int, transparent_less> M;
+    M example;
+    example.insert(5);
+    example.insert(6);
+    example.insert(4);
+    assert(example.size() == 3);
+    M::node_type nh = example.extract(C2Int{5});
+    assert(nh && nh.value() == 5);
+    assert(example.size() == 2);
+    example.insert(std::move(nh));
+    assert(example.size() == 3);
+    assert(*example.find(5) == 5);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..9d355e5f9d26e0
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..b7b907261a9eb3
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..18654721a4fb0b
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::multiset<int, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran4.pass.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran4.pass.cpp
new file mode 100644
index 00000000000000..b5528aef8a8c3f
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multiset<int, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert(2);
+    M::node_type nh = example.extract(Convertible());
+    assert(nh && nh.value() == 2);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/multiset/extract_tran5.pass.cpp b/libcxx/test/std/containers/associative/multiset/extract_tran5.pass.cpp
new file mode 100644
index 00000000000000..fa474b9b96521f
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class multiset
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::multiset<int, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert(0);
+    M::node_type nh = example.extract(c);
+    assert(nh && nh.value() == 0);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran.pass.cpp b/libcxx/test/std/containers/associative/set/erase_tran.pass.cpp
new file mode 100644
index 00000000000000..c6e61f65b1fa9f
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::set<int, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.erase(C2Int{5}) == 0);
+  }
+  {
+    typedef std::set<int, transparent_less> M;
+    M example;
+    example.insert(5);
+    example.insert(6);
+    example.insert(4);
+    assert(example.size() == 3);
+    M::size_type erased = example.erase(C2Int{5});
+    assert(erased == 1);
+    assert(example.size() == 2);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/set/erase_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..94d091bc3b4cc7
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/set/erase_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..01367b0254f096
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/set/erase_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..4d0a10acfc9121
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().erase(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran4.pass.cpp b/libcxx/test/std/containers/associative/set/erase_tran4.pass.cpp
new file mode 100644
index 00000000000000..d6e0323fc78e4c
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::set<int, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert(2);
+    M::iterator erased = example.erase(Convertible());
+    assert(example.empty() && erased == example.end());
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/erase_tran5.pass.cpp b/libcxx/test/std/containers/associative/set/erase_tran5.pass.cpp
new file mode 100644
index 00000000000000..ae00dc51d26d70
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     size_type erase(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::set<int, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert(0);
+    M::size_type erased = example.erase(c);
+    assert(erased == 1);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran.pass.cpp b/libcxx/test/std/containers/associative/set/extract_tran.pass.cpp
new file mode 100644
index 00000000000000..15167bba5ed010
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::set<int, transparent_less_not_referenceable> M;
+    M example;
+    assert(example.extract(C2Int{5}).empty());
+  }
+  {
+    typedef std::set<int, transparent_less> M;
+    M example;
+    example.insert(5);
+    example.insert(6);
+    example.insert(4);
+    assert(example.size() == 3);
+    M::node_type nh = example.extract(C2Int{5});
+    assert(nh && nh.value() == 5);
+    assert(example.size() == 2);
+    example.insert(std::move(nh));
+    assert(example.size() == 3);
+    assert(*example.find(5) == 5);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran1.compile.fail.cpp b/libcxx/test/std/containers/associative/set/extract_tran1.compile.fail.cpp
new file mode 100644
index 00000000000000..e3599fff323dba
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran1.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_no_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran2.compile.fail.cpp b/libcxx/test/std/containers/associative/set/extract_tran2.compile.fail.cpp
new file mode 100644
index 00000000000000..e2249d702c2fdb
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran2.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_private> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran3.compile.fail.cpp b/libcxx/test/std/containers/associative/set/extract_tran3.compile.fail.cpp
new file mode 100644
index 00000000000000..a29bb01673ae2d
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran3.compile.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+int main(int, char**) {
+  {
+    typedef std::set<int, transparent_less_not_a_type> M;
+
+    TEST_IGNORE_NODISCARD M().extract(C2Int{5});
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran4.pass.cpp b/libcxx/test/std/containers/associative/set/extract_tran4.pass.cpp
new file mode 100644
index 00000000000000..192ab633511904
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran4.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::set<int, transparent_less> M;
+M example;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() { return example.begin(); }
+};
+
+int main(int, char**) {
+  {
+    example.insert(2);
+    M::node_type nh = example.extract(Convertible());
+    assert(nh && nh.value() == 2);
+  }
+}
diff --git a/libcxx/test/std/containers/associative/set/extract_tran5.pass.cpp b/libcxx/test/std/containers/associative/set/extract_tran5.pass.cpp
new file mode 100644
index 00000000000000..21247a00f8243f
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract_tran5.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: c++03, c++11, c++14, c++17, c++20
+
+// <set>
+
+// class set
+
+// template<class K>
+//     node_type extract(K&& x);
+//
+//   The member function templates find, count, lower_bound, upper_bound,
+// equal_range, erase, and extract shall not participate in overload resolution
+// unless the qualified-id Compare::is_transparent is valid and denotes a type.
+// Additionally, the member function templates erase and extract shall not
+// participate in overload resolution if is_convertible_v<K&&, iterator> ||
+// is_convertible_v<K&&, const_iterator> is true, where K is the type
+// substituted as the first template argument
+
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+typedef std::set<int, transparent_less> M;
+
+struct Convertible : C2Int {
+  operator M::const_iterator() const { assert(false); }
+
+private:
+  operator M::const_iterator();
+};
+
+int main(int, char**) {
+  {
+    Convertible c;
+    M example;
+    example.insert(0);
+    M::node_type nh = example.extract(c);
+    assert(nh && nh.value() == 0);
+  }
+}



More information about the libcxx-commits mailing list