[libcxx-commits] [libcxx] e5ec94a - [libc++] Implement P0919R3: heterogenous lookup for unordered containers

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Nov 11 14:45:07 PST 2020


Author: Ruslan Arutyunyan
Date: 2020-11-11T17:44:42-05:00
New Revision: e5ec94a1a083e055ac2686ecc72fb4868dd7ce85

URL: https://github.com/llvm/llvm-project/commit/e5ec94a1a083e055ac2686ecc72fb4868dd7ce85
DIFF: https://github.com/llvm/llvm-project/commit/e5ec94a1a083e055ac2686ecc72fb4868dd7ce85.diff

LOG: [libc++] Implement P0919R3: heterogenous lookup for unordered containers

Implement heterogenous lookup for unordered containers, including the
refinement from P1690R1.

Differential Revision: https://reviews.llvm.org/D87171

Added: 
    libcxx/test/std/containers/unord/unord.map/contains.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.map/count.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.map/equal_range_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.map/equal_range_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.map/find_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.map/find_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/contains.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/count.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/equal_range_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/equal_range_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/find_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/find_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/contains.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/count.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/equal_range_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/equal_range_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/find_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/find_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/contains.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/count.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/equal_range_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/equal_range_non_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/find_const.transparent.pass.cpp
    libcxx/test/std/containers/unord/unord.set/find_non_const.transparent.pass.cpp
    libcxx/test/support/test_transparent_unordered.h

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/include/unordered_map
    libcxx/include/unordered_set
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/test/support/is_transparent.h
    libcxx/utils/generate_feature_test_macro_components.py
    libcxx/www/cxx2a_status.html

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 0f17a3a1bd54..8d7bfd45fc56 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -206,7 +206,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_erase_if``                            ``202002L``
     ------------------------------------------------- -----------------
-    ``__cpp_lib_generic_unordered_lookup``            *unimplemented*
+    ``__cpp_lib_generic_unordered_lookup``            ``201811L``
     ------------------------------------------------- -----------------
     ``__cpp_lib_interpolate``                         ``201902L``
     ------------------------------------------------- -----------------

diff  --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index fcdb15b32b18..9a00fd76f28d 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -173,10 +173,22 @@ public:
 
     iterator       find(const key_type& k);
     const_iterator find(const key_type& k) const;
+    template<typename K>
+        iterator find(const K& x);              // C++20
+    template<typename K>
+        const_iterator find(const K& x) const;  // C++20
     size_type count(const key_type& k) const;
+    template<typename K>
+        size_type count(const K& k) const; // C++20
     bool contains(const key_type& k) const; // C++20
+    template<typename K>
+        bool contains(const K& k) const; // C++20
     pair<iterator, iterator>             equal_range(const key_type& k);
     pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
+    template<typename K>
+        pair<iterator, iterator>             equal_range(const K& k); // C++20
+    template<typename K>
+        pair<const_iterator, const_iterator> equal_range(const K& k) const; // C++20
 
     mapped_type& operator[](const key_type& k);
     mapped_type& operator[](key_type&& k);
@@ -355,10 +367,22 @@ public:
 
     iterator       find(const key_type& k);
     const_iterator find(const key_type& k) const;
+    template<typename K>
+        iterator find(const K& x);              // C++20
+    template<typename K>
+        const_iterator find(const K& x) const;  // C++20
     size_type count(const key_type& k) const;
+    template<typename K>
+        size_type count(const K& k) const; // C++20
     bool contains(const key_type& k) const; // C++20
+    template<typename K>
+        bool contains(const K& k) const; // C++20
     pair<iterator, iterator>             equal_range(const key_type& k);
     pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
+    template<typename K>
+        pair<iterator, iterator>             equal_range(const K& k); // C++20
+    template<typename K>
+        pair<const_iterator, const_iterator> equal_range(const K& k) const; // C++20
 
     size_type bucket_count() const noexcept;
     size_type max_bucket_count() const noexcept;
@@ -423,7 +447,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Key, class _Cp, class _Hash,
+template <class _Key, class _Cp, class _Hash, class _Pred,
           bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value>
 class __unordered_map_hasher
     : private _Hash
@@ -445,6 +469,12 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(const _Key& __x) const
         {return static_cast<const _Hash&>(*this)(__x);}
+#if _LIBCPP_STD_VER > 17
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(const _K2& __x) const
+        {return static_cast<const _Hash&>(*this)(__x);}
+#endif
     void swap(__unordered_map_hasher&__y)
         _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
     {
@@ -453,8 +483,8 @@ public:
     }
 };
 
-template <class _Key, class _Cp, class _Hash>
-class __unordered_map_hasher<_Key, _Cp, _Hash, false>
+template <class _Key, class _Cp, class _Hash, class _Pred>
+class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false>
 {
     _Hash __hash_;
 public:
@@ -474,6 +504,12 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(const _Key& __x) const
         {return __hash_(__x);}
+#if _LIBCPP_STD_VER > 17
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(const _K2& __x) const
+        {return __hash_(__x);}
+#endif
     void swap(__unordered_map_hasher&__y)
         _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
     {
@@ -482,17 +518,17 @@ public:
     }
 };
 
-template <class _Key, class _Cp, class _Hash, bool __b>
+template <class _Key, class _Cp, class _Hash, class _Pred, bool __b>
 inline _LIBCPP_INLINE_VISIBILITY
 void
-swap(__unordered_map_hasher<_Key, _Cp, _Hash, __b>& __x,
-     __unordered_map_hasher<_Key, _Cp, _Hash, __b>& __y)
+swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x,
+     __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y)
     _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
 {
     __x.swap(__y);
 }
 
-template <class _Key, class _Cp, class _Pred,
+template <class _Key, class _Cp, class _Pred, class _Hash,
           bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value>
 class __unordered_map_equal
     : private _Pred
@@ -517,6 +553,24 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _Cp& __y) const
         {return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);}
+#if _LIBCPP_STD_VER > 17
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _Cp& __x, const _K2& __y) const
+        {return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _K2& __x, const _Cp& __y) const
+        {return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _Key& __x, const _K2& __y) const
+        {return static_cast<const _Pred&>(*this)(__x, __y);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _K2& __x, const _Key& __y) const
+        {return static_cast<const _Pred&>(*this)(__x, __y);}
+#endif
     void swap(__unordered_map_equal&__y)
         _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
     {
@@ -525,8 +579,8 @@ public:
     }
 };
 
-template <class _Key, class _Cp, class _Pred>
-class __unordered_map_equal<_Key, _Cp, _Pred, false>
+template <class _Key, class _Cp, class _Pred, class _Hash>
+class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false>
 {
     _Pred __pred_;
 public:
@@ -549,6 +603,24 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _Cp& __y) const
         {return __pred_(__x, __y.__get_value().first);}
+#if _LIBCPP_STD_VER > 17
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _Cp& __x, const _K2& __y) const
+        {return __pred_(__x.__get_value().first, __y);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _K2& __x, const _Cp& __y) const
+        {return __pred_(__x, __y.__get_value().first);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _Key& __x, const _K2& __y) const
+        {return __pred_(__x, __y);}
+    template <typename _K2, typename = _EnableIf<__is_transparent<_Hash, _K2>::value && __is_transparent<_Pred, _K2>::value>>
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator()(const _K2& __x, const _Key& __y) const
+        {return __pred_(__x, __y);}
+#endif
     void swap(__unordered_map_equal&__y)
         _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
     {
@@ -557,11 +629,11 @@ public:
     }
 };
 
-template <class _Key, class _Cp, class _Pred, bool __b>
+template <class _Key, class _Cp, class _Pred, class _Hash, bool __b>
 inline _LIBCPP_INLINE_VISIBILITY
 void
-swap(__unordered_map_equal<_Key, _Cp, _Pred, __b>& __x,
-     __unordered_map_equal<_Key, _Cp, _Pred, __b>& __y)
+swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x,
+     __unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y)
     _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
 {
     __x.swap(__y);
@@ -858,11 +930,11 @@ public:
                   "Invalid allocator::value_type");
 
 private:
-    typedef __hash_value_type<key_type, mapped_type>                 __value_type;
-    typedef __unordered_map_hasher<key_type, __value_type, hasher>   __hasher;
-    typedef __unordered_map_equal<key_type, __value_type, key_equal> __key_equal;
+    typedef __hash_value_type<key_type, mapped_type>                          __value_type;
+    typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
+    typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher>  __key_equal;
     typedef typename __rebind_alloc_helper<allocator_traits<allocator_type>,
-                                                 __value_type>::type __allocator_type;
+                                                 __value_type>::type          __allocator_type;
 
     typedef __hash_table<__value_type, __hasher,
                          __key_equal,  __allocator_type>   __table;
@@ -1280,11 +1352,34 @@ public:
     iterator       find(const key_type& __k)       {return __table_.find(__k);}
     _LIBCPP_INLINE_VISIBILITY
     const_iterator find(const key_type& __k) const {return __table_.find(__k);}
+
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, iterator>
+        find(const _K2& __k)       {return __table_.find(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, const_iterator>
+        find(const _K2& __k) const {return __table_.find(__k);}
+    #endif // _LIBCPP_STD_VER > 17
+
     _LIBCPP_INLINE_VISIBILITY
     size_type count(const key_type& __k) const {return __table_.__count_unique(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, size_type>
+        count(const _K2& __k) const {return __table_.__count_unique(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     #if _LIBCPP_STD_VER > 17
         _LIBCPP_INLINE_VISIBILITY
         bool contains(const key_type& __k) const {return find(__k) != end();}
+
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, bool>
+        contains(const _K2& __k) const {return find(__k) != end();}
     #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     pair<iterator, iterator>             equal_range(const key_type& __k)
@@ -1292,6 +1387,16 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     pair<const_iterator, const_iterator> equal_range(const key_type& __k) const
         {return __table_.__equal_range_unique(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<iterator, iterator>>
+        equal_range(const _K2& __k)       {return __table_.__equal_range_unique(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<const_iterator, const_iterator>>
+        equal_range(const _K2& __k) const {return __table_.__equal_range_unique(__k);}
+    #endif // _LIBCPP_STD_VER > 17
 
     mapped_type& operator[](const key_type& __k);
 #ifndef _LIBCPP_CXX03_LANG
@@ -1762,11 +1867,11 @@ public:
                   "Invalid allocator::value_type");
 
 private:
-    typedef __hash_value_type<key_type, mapped_type>                 __value_type;
-    typedef __unordered_map_hasher<key_type, __value_type, hasher>   __hasher;
-    typedef __unordered_map_equal<key_type, __value_type, key_equal> __key_equal;
+    typedef __hash_value_type<key_type, mapped_type>                          __value_type;
+    typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
+    typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher>  __key_equal;
     typedef typename __rebind_alloc_helper<allocator_traits<allocator_type>,
-                                                 __value_type>::type __allocator_type;
+                                                 __value_type>::type          __allocator_type;
 
     typedef __hash_table<__value_type, __hasher,
                          __key_equal,  __allocator_type>   __table;
@@ -2059,11 +2164,32 @@ public:
     iterator       find(const key_type& __k)       {return __table_.find(__k);}
     _LIBCPP_INLINE_VISIBILITY
     const_iterator find(const key_type& __k) const {return __table_.find(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, iterator>
+        find(const _K2& __k)       {return __table_.find(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, const_iterator>
+        find(const _K2& __k) const {return __table_.find(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     size_type count(const key_type& __k) const {return __table_.__count_multi(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, size_type>
+        count(const _K2& __k) const {return __table_.__count_multi(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     #if _LIBCPP_STD_VER > 17
         _LIBCPP_INLINE_VISIBILITY
         bool contains(const key_type& __k) const {return find(__k) != end();}
+
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, bool>
+        contains(const _K2& __k) const {return find(__k) != end();}
     #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     pair<iterator, iterator>             equal_range(const key_type& __k)
@@ -2071,6 +2197,16 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     pair<const_iterator, const_iterator> equal_range(const key_type& __k) const
         {return __table_.__equal_range_multi(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<iterator, iterator>>
+        equal_range(const _K2& __k)       {return __table_.__equal_range_multi(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<const_iterator, const_iterator>>
+        equal_range(const _K2& __k) const {return __table_.__equal_range_multi(__k);}
+    #endif // _LIBCPP_STD_VER > 17
 
     _LIBCPP_INLINE_VISIBILITY
     size_type bucket_count() const _NOEXCEPT {return __table_.bucket_count();}

diff  --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index da4beb176d2a..80f460d7edaa 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -145,10 +145,22 @@ public:
 
     iterator       find(const key_type& k);
     const_iterator find(const key_type& k) const;
+    template<typename K>
+        iterator find(const K& x);              // C++20
+    template<typename K>
+        const_iterator find(const K& x) const;  // C++20
     size_type count(const key_type& k) const;
+    template<typename K>
+        size_type count(const K& k) const; // C++20
     bool contains(const key_type& k) const; // C++20
+    template<typename K>
+        bool contains(const K& k) const; // C++20
     pair<iterator, iterator>             equal_range(const key_type& k);
     pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
+    template<typename K>
+        pair<iterator, iterator>             equal_range(const K& k); // C++20
+    template<typename K>
+        pair<const_iterator, const_iterator> equal_range(const K& k) const; // C++20
 
     size_type bucket_count() const noexcept;
     size_type max_bucket_count() const noexcept;
@@ -310,10 +322,22 @@ public:
 
     iterator       find(const key_type& k);
     const_iterator find(const key_type& k) const;
+    template<typename K>
+        iterator find(const K& x);              // C++20
+    template<typename K>
+        const_iterator find(const K& x) const;  // C++20
     size_type count(const key_type& k) const;
+    template<typename K>
+        size_type count(const K& k) const; // C++20
     bool contains(const key_type& k) const; // C++20
+    template<typename K>
+        bool contains(const K& k) const; // C++20
     pair<iterator, iterator>             equal_range(const key_type& k);
     pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
+    template<typename K>
+        pair<iterator, iterator>             equal_range(const K& k); // C++20
+    template<typename K>
+        pair<const_iterator, const_iterator> equal_range(const K& k) const; // C++20
 
     size_type bucket_count() const noexcept;
     size_type max_bucket_count() const noexcept;
@@ -679,11 +703,32 @@ public:
     iterator       find(const key_type& __k)       {return __table_.find(__k);}
     _LIBCPP_INLINE_VISIBILITY
     const_iterator find(const key_type& __k) const {return __table_.find(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, iterator>
+        find(const _K2& __k)       {return __table_.find(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, const_iterator>
+        find(const _K2& __k) const {return __table_.find(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     size_type count(const key_type& __k) const {return __table_.__count_unique(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, size_type>
+        count(const _K2& __k) const {return __table_.__count_unique(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     #if _LIBCPP_STD_VER > 17
         _LIBCPP_INLINE_VISIBILITY
         bool contains(const key_type& __k) const {return find(__k) != end();}
+
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, bool>
+        contains(const _K2& __k) const {return find(__k) != end();}
     #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     pair<iterator, iterator>             equal_range(const key_type& __k)
@@ -691,6 +736,16 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     pair<const_iterator, const_iterator> equal_range(const key_type& __k) const
         {return __table_.__equal_range_unique(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<iterator, iterator>>
+        equal_range(const _K2& __k)       {return __table_.__equal_range_unique(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<const_iterator, const_iterator>>
+        equal_range(const _K2& __k) const {return __table_.__equal_range_unique(__k);}
+    #endif // _LIBCPP_STD_VER > 17
 
     _LIBCPP_INLINE_VISIBILITY
     size_type bucket_count() const _NOEXCEPT {return __table_.bucket_count();}
@@ -1314,11 +1369,32 @@ public:
     iterator       find(const key_type& __k)       {return __table_.find(__k);}
     _LIBCPP_INLINE_VISIBILITY
     const_iterator find(const key_type& __k) const {return __table_.find(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, iterator>
+        find(const _K2& __k)       {return __table_.find(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, const_iterator>
+        find(const _K2& __k) const {return __table_.find(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     size_type count(const key_type& __k) const {return __table_.__count_multi(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, size_type>
+        count(const _K2& __k) const {return __table_.__count_multi(__k);}
+    #endif // _LIBCPP_STD_VER > 17
     #if _LIBCPP_STD_VER > 17
         _LIBCPP_INLINE_VISIBILITY
         bool contains(const key_type& __k) const {return find(__k) != end();}
+
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, bool>
+        contains(const _K2& __k) const {return find(__k) != end();}
     #endif // _LIBCPP_STD_VER > 17
     _LIBCPP_INLINE_VISIBILITY
     pair<iterator, iterator>             equal_range(const key_type& __k)
@@ -1326,6 +1402,16 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     pair<const_iterator, const_iterator> equal_range(const key_type& __k) const
         {return __table_.__equal_range_multi(__k);}
+    #if _LIBCPP_STD_VER > 17
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<iterator, iterator>>
+        equal_range(const _K2& __k)       {return __table_.__equal_range_multi(__k);}
+        template <typename _K2>
+        _LIBCPP_INLINE_VISIBILITY
+        _EnableIf<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value, pair<const_iterator, const_iterator>>
+        equal_range(const _K2& __k) const {return __table_.__equal_range_multi(__k);}
+    #endif // _LIBCPP_STD_VER > 17
 
     _LIBCPP_INLINE_VISIBILITY
     size_type bucket_count() const _NOEXCEPT {return __table_.bucket_count();}

diff  --git a/libcxx/include/version b/libcxx/include/version
index 3355e2d18c56..1f05f3a851cc 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -260,7 +260,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # endif
 # define __cpp_lib_endian                               201907L
 # define __cpp_lib_erase_if                             202002L
-// # define __cpp_lib_generic_unordered_lookup             201811L
+# define __cpp_lib_generic_unordered_lookup             201811L
 # define __cpp_lib_interpolate                          201902L
 # if !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)
 #   define __cpp_lib_is_constant_evaluated              201811L

diff  --git a/libcxx/test/std/containers/unord/unord.map/contains.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/contains.transparent.pass.cpp
new file mode 100644
index 000000000000..5d3b5cecfbdf
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/contains.transparent.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// bool contains(const K& x) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash, std::equal_to<> >;
+      test_transparent_contains<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash_final, transparent_equal_final>;
+      test_transparent_contains<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_contains<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_contains<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_contains<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.map/count.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/count.transparent.pass.cpp
new file mode 100644
index 000000000000..07276c25fe7c
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/count.transparent.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// size_type count(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash, std::equal_to<> >;
+      test_transparent_count<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type =
+          const unord_map_type<std::unordered_map, transparent_hash_final, transparent_equal_final>;
+      test_transparent_count<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash, std::equal_to<> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type =
+          const unord_map_type<std::unordered_map, transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type =
+          const unord_map_type<std::unordered_map, non_transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.map/equal_range_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/equal_range_const.transparent.pass.cpp
new file mode 100644
index 000000000000..9e76f72081ed
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/equal_range_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// pair<const_iterator, const_iterator> equal_range(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.map/equal_range_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/equal_range_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..97db1dcecc1e
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/equal_range_non_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// pair<iterator, iterator> equal_range(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = unord_map_type<std::unordered_map, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.map/find_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/find_const.transparent.pass.cpp
new file mode 100644
index 000000000000..cc9324f28190
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/find_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// const_iterator find(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = const unord_map_type<std::unordered_map, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_map, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.map/find_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.map/find_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..b4233a8333d1
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/find_non_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_map
+
+// template <typename K>
+// iterator find(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = unord_map_type<std::unordered_map, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = unord_map_type<std::unordered_map, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = unord_map_type<std::unordered_map, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/contains.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/contains.transparent.pass.cpp
new file mode 100644
index 000000000000..2f07bcd37fa0
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/contains.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// bool contains(const K& x) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                            std::equal_to<> >;
+      test_transparent_contains<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash_final, transparent_equal_final>;
+      test_transparent_contains<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                            std::equal_to<> >;
+      test_non_transparent_contains<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                            std::equal_to<key_type> >;
+      test_non_transparent_contains<map_type>(
+          ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                            std::equal_to<key_type> >;
+      test_non_transparent_contains<map_type>(
+          ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/count.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/count.transparent.pass.cpp
new file mode 100644
index 000000000000..7abf662982f6
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/count.transparent.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// size_type count(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash, std::equal_to<> >;
+      test_transparent_count<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type =
+          const unord_map_type<std::unordered_multimap, transparent_hash_final, transparent_equal_final>;
+      test_transparent_count<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_multimap, non_transparent_hash, std::equal_to<> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type =
+          const unord_map_type<std::unordered_multimap, transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type =
+          const unord_map_type<std::unordered_multimap, non_transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/equal_range_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/equal_range_const.transparent.pass.cpp
new file mode 100644
index 000000000000..2444e9ca9dc4
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/equal_range_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// pair<const_iterator, const_iterator> equal_range(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/equal_range_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/equal_range_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..a4c7730fd85f
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/equal_range_non_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// pair<iterator, iterator> equal_range(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/find_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/find_const.transparent.pass.cpp
new file mode 100644
index 000000000000..3737866cf4e0
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/find_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// const_iterator find(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = const unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = const unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/find_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/find_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..676c82a3bab1
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/find_non_const.transparent.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multimap
+
+// template <typename K>
+// iterator find(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_map>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+    using ilist_type = std::initializer_list<std::pair<const key_type, int> >;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using map_type = unord_map_type<std::unordered_multimap, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using map_type = unord_map_type<std::unordered_multimap, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<map_type>(ilist_type{{1, 2}, {1, 3}, {2, 3}});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/contains.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/contains.transparent.pass.cpp
new file mode 100644
index 000000000000..0256d71c4690
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/contains.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Value, class Hash = hash<Value>, class Pred = equal_to<Value>,
+//           class Alloc = allocator<Value>>
+// class unordered_multiset
+
+// template <typename K>
+// bool contains(const K& x) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                            std::equal_to<> >;
+      test_transparent_contains<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash_final, transparent_equal_final>;
+      test_transparent_contains<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                            std::equal_to<> >;
+      test_non_transparent_contains<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                            std::equal_to<key_type> >;
+      test_non_transparent_contains<set_type>(
+          key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                            std::equal_to<key_type> >;
+      test_non_transparent_contains<set_type>(
+          key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/count.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/count.transparent.pass.cpp
new file mode 100644
index 000000000000..a56a12a902c1
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/count.transparent.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multiset
+
+// template <typename K>
+// size_type count(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash, std::equal_to<> >;
+      test_transparent_count<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type =
+          const unord_set_type<std::unordered_multiset, transparent_hash_final, transparent_equal_final>;
+      test_transparent_count<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_multiset, non_transparent_hash, std::equal_to<> >;
+      test_non_transparent_count<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type =
+          const unord_set_type<std::unordered_multiset, transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type =
+          const unord_set_type<std::unordered_multiset, non_transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/equal_range_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/equal_range_const.transparent.pass.cpp
new file mode 100644
index 000000000000..991ffcd30dee
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/equal_range_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multiset
+
+// template <typename K>
+// pair<const_iterator, const_iterator> equal_range(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/equal_range_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/equal_range_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..dc84dc6a50c8
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/equal_range_non_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multiset
+
+// template <typename K>
+// pair<iterator, iterator> equal_range(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/find_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/find_const.transparent.pass.cpp
new file mode 100644
index 000000000000..c3a765462514
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/find_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multiset
+
+// template <typename K>
+// const_iterator find(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/find_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/find_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..3255c8c6ab4f
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/find_non_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_multiset
+
+// template <typename K>
+// iterator find(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = unord_set_type<std::unordered_multiset, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = unord_set_type<std::unordered_multiset, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/contains.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/contains.transparent.pass.cpp
new file mode 100644
index 000000000000..6adf6ab4313e
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/contains.transparent.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Value, class Hash = hash<Value>, class Pred = equal_to<Value>,
+//           class Alloc = allocator<Value>>
+// class unordered_multiset
+
+// template <typename K>
+// bool contains(const K& x) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash, std::equal_to<> >;
+      test_transparent_contains<set_type>(key_type(1), key_type(2));
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash_final, transparent_equal_final>;
+      test_transparent_contains<set_type>(key_type(1), key_type(2));
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_contains<set_type>(key_type(1), key_type(2));
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_contains<set_type>(key_type(1), key_type(2));
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_contains<set_type>(key_type(1), key_type(2));
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/count.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/count.transparent.pass.cpp
new file mode 100644
index 000000000000..277308ea5323
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/count.transparent.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_set
+
+// template <typename K>
+// size_type count(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash, std::equal_to<> >;
+      test_transparent_count<set_type>(key_type{1},  key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type =
+          const unord_set_type<std::unordered_set, transparent_hash_final, transparent_equal_final>;
+      test_transparent_count<set_type>(key_type{1},  key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash, std::equal_to<> >;
+      test_non_transparent_count<set_type>(key_type{1},  key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type =
+          const unord_set_type<std::unordered_set, transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<set_type>(key_type{1},  key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type =
+          const unord_set_type<std::unordered_set, non_transparent_hash, std::equal_to<key_type> >;
+      test_non_transparent_count<set_type>(key_type{1},  key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/equal_range_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/equal_range_const.transparent.pass.cpp
new file mode 100644
index 000000000000..0c3f18bb4382
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/equal_range_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_set
+
+// template <typename K>
+// pair<const_iterator, const_iterator> equal_range(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/equal_range_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/equal_range_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..452d15d7b0c9
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/equal_range_non_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_set
+
+// template <typename K>
+// pair<iterator, iterator> equal_range(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = unord_set_type<std::unordered_set, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_equal_range<set_type>(key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/find_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/find_const.transparent.pass.cpp
new file mode 100644
index 000000000000..6256ef35f5a8
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/find_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_set
+
+// template <typename K>
+// const_iterator find(const K& k) const;
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash,
+                                       std::equal_to<> >;
+      test_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash_final,
+                                       transparent_equal_final>;
+      test_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = const unord_set_type<std::unordered_set, transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = const unord_set_type<std::unordered_set, non_transparent_hash,
+                                       std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/containers/unord/unord.set/find_non_const.transparent.pass.cpp b/libcxx/test/std/containers/unord/unord.set/find_non_const.transparent.pass.cpp
new file mode 100644
index 000000000000..7fa3508ae09e
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/find_non_const.transparent.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
+//           class Alloc = allocator<pair<const Key, T>>>
+// class unordered_set
+
+// template <typename K>
+// iterator find(const K& k);
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <unordered_set>
+
+#include "test_transparent_unordered.h"
+
+int main(int, char**)
+{
+    using key_type = StoredType<int>;
+
+    {
+      // Make sure conversions don't happen for transparent non-final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash,
+                                 std::equal_to<> >;
+      test_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions don't happen for transparent final hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash_final,
+                                 transparent_equal_final>;
+      test_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent hasher
+      using set_type = unord_set_type<std::unordered_set, non_transparent_hash,
+                                 std::equal_to<> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for non-transparent key_equal
+      using set_type = unord_set_type<std::unordered_set, transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    {
+      // Make sure conversions do happen for both non-transparent hasher and key_equal
+      using set_type = unord_set_type<std::unordered_set, non_transparent_hash,
+                                 std::equal_to<key_type> >;
+      test_non_transparent_find<set_type>(key_type{1}, key_type{2});
+    }
+
+    return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
index 62c974add1ba..a3365f40b9bb 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
@@ -131,17 +131,11 @@
 #   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
-#   endif
-#   if __cpp_lib_generic_unordered_lookup != 201811L
-#     error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_generic_unordered_lookup
+#   error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
+# endif
+# if __cpp_lib_generic_unordered_lookup != 201811L
+#   error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
 # endif
 
 # ifndef __cpp_lib_node_extract

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
index 6fe59790857b..1cd59235ab82 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
@@ -115,17 +115,11 @@
 #   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
-#   endif
-#   if __cpp_lib_generic_unordered_lookup != 201811L
-#     error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_generic_unordered_lookup
+#   error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
+# endif
+# if __cpp_lib_generic_unordered_lookup != 201811L
+#   error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
 # endif
 
 # ifndef __cpp_lib_node_extract

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index 86579298afdb..c625753ca2bd 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -1992,17 +1992,11 @@
 #   error "__cpp_lib_generic_associative_lookup should have the value 201304L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
-#   endif
-#   if __cpp_lib_generic_unordered_lookup != 201811L
-#     error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_generic_unordered_lookup
-#     error "__cpp_lib_generic_unordered_lookup should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_generic_unordered_lookup
+#   error "__cpp_lib_generic_unordered_lookup should be defined in c++2a"
+# endif
+# if __cpp_lib_generic_unordered_lookup != 201811L
+#   error "__cpp_lib_generic_unordered_lookup should have the value 201811L in c++2a"
 # endif
 
 # if !defined(_LIBCPP_VERSION)

diff  --git a/libcxx/test/support/is_transparent.h b/libcxx/test/support/is_transparent.h
index 667877526efe..9088ab67d31b 100644
--- a/libcxx/test/support/is_transparent.h
+++ b/libcxx/test/support/is_transparent.h
@@ -11,6 +11,8 @@
 
 #include "test_macros.h"
 
+#include <functional> // for std::equal_to
+
 // testing transparent
 #if TEST_STD_VER > 11
 
@@ -79,6 +81,87 @@ bool operator <(int          rhs,   const C2Int& lhs) { return rhs       < lhs.g
 bool operator <(const C2Int& rhs,   const C2Int& lhs) { return rhs.get() < lhs.get(); }
 bool operator <(const C2Int& rhs,            int lhs) { return rhs.get() < lhs; }
 
-#endif
+#endif // TEST_STD_VER > 11
+
+#if TEST_STD_VER > 17
+
+template <typename T>
+struct StoredType;
+
+template <typename T>
+struct SearchedType;
+
+struct hash_impl {
+  template <typename T>
+  constexpr std::size_t operator()(SearchedType<T> const& t) const {
+    return static_cast<std::size_t>(t.get_value());
+  }
+
+  template <typename T>
+  constexpr std::size_t operator()(StoredType<T> const& t) const {
+    return static_cast<std::size_t>(t.get_value());
+  }
+};
+
+struct non_transparent_hash : hash_impl {};
+
+struct transparent_hash : hash_impl {
+  using is_transparent = void;
+};
+
+struct transparent_hash_final final : transparent_hash {};
+
+struct transparent_equal_final final : std::equal_to<> {};
+
+template <typename T>
+struct SearchedType {
+  SearchedType(T value, int* counter) : value_(value), conversions_(counter) { }
+
+  // Whenever a conversion is performed, increment the counter to keep track
+  // of conversions.
+  operator StoredType<T>() const {
+    ++*conversions_;
+    return StoredType<T>{value_};
+  }
+
+  int get_value() const {
+    return value_;
+  }
+
+private:
+  T value_;
+  int* conversions_;
+};
+
+template <typename T>
+struct StoredType {
+  StoredType() = default;
+  StoredType(T value) : value_(value) { }
+
+  friend bool operator==(StoredType const& lhs, StoredType const& rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+
+  // If we're being passed a SearchedType<T> object, avoid the conversion
+  // to T. This allows testing that the transparent operations are correctly
+  // forwarding the SearchedType all the way to this comparison by checking
+  // that we didn't have a conversion when we search for a SearchedType<T>
+  // in a container full of StoredType<T>.
+  friend bool operator==(StoredType const& lhs, SearchedType<T> const& rhs) {
+    return lhs.value_ == rhs.get_value();
+  }
+  friend bool operator==(SearchedType<T> const& lhs, StoredType<T> const& rhs) {
+    return lhs.get_value() == rhs.value_;
+  }
+
+  int get_value() const {
+    return value_;
+  }
+
+private:
+  T value_;
+};
+
+#endif // TEST_STD_VER > 17
 
 #endif  // TRANSPARENT_H

diff  --git a/libcxx/test/support/test_transparent_unordered.h b/libcxx/test/support/test_transparent_unordered.h
new file mode 100644
index 000000000000..7bcbc19c05a8
--- /dev/null
+++ b/libcxx/test/support/test_transparent_unordered.h
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_TRANSPARENT_UNORDERED_H
+#define TEST_TRANSPARENT_UNORDERED_H
+
+#include "test_macros.h"
+#include "is_transparent.h"
+
+#include <cassert>
+
+// testing transparent unordered containers
+#if TEST_STD_VER > 17
+
+template <template <typename...> class UnorderedSet, typename Hash,
+          typename Equal>
+using unord_set_type = UnorderedSet<StoredType<int>, Hash, Equal>;
+
+template <template <typename...> class UnorderedMap, typename Hash,
+          typename Equal>
+using unord_map_type = UnorderedMap<StoredType<int>, int, Hash, Equal>;
+
+template <typename Container, typename... Args>
+void test_transparent_find(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.find(SearchedType<int>(1, &conversions)) != c.end());
+  assert(c.find(SearchedType<int>(2, &conversions)) != c.end());
+  assert(conversions == 0);
+  assert(c.find(SearchedType<int>(3, &conversions)) == c.end());
+  assert(conversions == 0);
+}
+
+template <typename Container, typename... Args>
+void test_non_transparent_find(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.find(SearchedType<int>(1, &conversions)) != c.end());
+  assert(conversions > 0);
+  conversions = 0;
+  assert(c.find(SearchedType<int>(2, &conversions)) != c.end());
+  assert(conversions > 0);
+  conversions = 0;
+  assert(c.find(SearchedType<int>(3, &conversions)) == c.end());
+  assert(conversions > 0);
+}
+
+template <typename Container, typename... Args>
+void test_transparent_count(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.count(SearchedType<int>(1, &conversions)) > 0);
+  assert(c.count(SearchedType<int>(2, &conversions)) > 0);
+  assert(conversions == 0);
+  assert(c.count(SearchedType<int>(3, &conversions)) == 0);
+  assert(conversions == 0);
+}
+
+template <typename Container, typename... Args>
+void test_non_transparent_count(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.count(SearchedType<int>(1, &conversions)) > 0);
+  assert(conversions > 0);
+  conversions = 0;
+  assert(c.count(SearchedType<int>(2, &conversions)) > 0);
+  assert(conversions > 0);
+  conversions = 0;
+  assert(c.count(SearchedType<int>(3, &conversions)) == 0);
+  assert(conversions > 0);
+}
+
+template <typename Container, typename... Args>
+void test_transparent_contains(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.contains(SearchedType<int>(1, &conversions)));
+  assert(c.contains(SearchedType<int>(2, &conversions)));
+  assert(conversions == 0);
+  assert(!c.contains(SearchedType<int>(3, &conversions)));
+  assert(conversions == 0);
+}
+
+template <typename Container, typename... Args>
+void test_non_transparent_contains(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  assert(c.contains(SearchedType<int>(1, &conversions)));
+  assert(conversions > 0);
+  conversions = 0;
+  assert(c.contains(SearchedType<int>(2, &conversions)));
+  assert(conversions > 0);
+  conversions = 0;
+  assert(!c.contains(SearchedType<int>(3, &conversions)));
+  assert(conversions > 0);
+}
+
+template <typename Container, typename... Args>
+void test_transparent_equal_range(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  auto iters = c.equal_range(SearchedType<int>(1, &conversions));
+  assert(std::distance(iters.first, iters.second) > 0);
+  iters = c.equal_range(SearchedType<int>(2, &conversions));
+  assert(std::distance(iters.first, iters.second) > 0);
+  assert(conversions == 0);
+  iters = c.equal_range(SearchedType<int>(3, &conversions));
+  assert(std::distance(iters.first, iters.second) == 0);
+  assert(conversions == 0);
+}
+
+template <typename Container, typename... Args>
+void test_non_transparent_equal_range(Args&&... args) {
+  Container c{std::forward<Args>(args)...};
+  int conversions = 0;
+  auto iters = c.equal_range(SearchedType<int>(1, &conversions));
+  assert(std::distance(iters.first, iters.second) > 0);
+  assert(conversions > 0);
+  conversions = 0;
+  iters = c.equal_range(SearchedType<int>(2, &conversions));
+  assert(std::distance(iters.first, iters.second) > 0);
+  assert(conversions > 0);
+  conversions = 0;
+  iters = c.equal_range(SearchedType<int>(3, &conversions));
+  assert(std::distance(iters.first, iters.second) == 0);
+  assert(conversions > 0);
+}
+
+#endif // TEST_STD_VER > 17
+
+#endif // TEST_TRANSPARENT_UNORDERED_H

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 6fef8ea85606..06eb57d8b3fc 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -393,7 +393,6 @@ def add_version_header(tc):
     "name": "__cpp_lib_generic_unordered_lookup",
     "values": { "c++2a": int(201811) },
     "headers": ["unordered_map", "unordered_set"],
-    "unimplemented": True,
    }, {
     "name": "__cpp_lib_ranges",
     "values": { "c++2a": int(201811) },

diff  --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html
index a038ef4c1f0a..254eb9a05d38 100644
--- a/libcxx/www/cxx2a_status.html
+++ b/libcxx/www/cxx2a_status.html
@@ -120,7 +120,7 @@ <h3>Paper Status</h3>
 	<tr><td><a href="https://wg21.link/P0771R1">P0771R1</a></td><td>LWG</td><td>std::function move constructor should be noexcept</td><td>San Diego</td><td>Complete</td><td>6.0</td></tr>
 	<tr><td><a href="https://wg21.link/P0896R4">P0896R4</a></td><td>LWG</td><td>The One Ranges Proposal</td><td>San Diego</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0899R1">P0899R1</a></td><td>LWG</td><td>P0899R1 - LWG 3016 is not a defect</td><td>San Diego</td><td><i>Nothing to do</i></td><td></td></tr>
-	<tr><td><a href="https://wg21.link/P0919R3">P0919R3</a></td><td>LWG</td><td>Heterogeneous lookup for unordered containers</td><td>San Diego</td><td><i> </i></td><td></td></tr>
+	<tr><td><a href="https://wg21.link/P0919R3">P0919R3</a></td><td>LWG</td><td>Heterogeneous lookup for unordered containers</td><td>San Diego</td><td>Complete</td><td>12.0</td></tr>
 	<tr><td><a href="https://wg21.link/P0972R0">P0972R0</a></td><td>LWG</td><td><chrono> <tt>zero()</tt>, <tt>min()</tt>, and <tt>max()</tt> should be noexcept</td><td>San Diego</td><td>Complete</td><td>8.0</td></tr>
 	<tr><td><a href="https://wg21.link/P1006R1">P1006R1</a></td><td>LWG</td><td>Constexpr in std::pointer_traits</td><td>San Diego</td><td>Complete</td><td>8.0</td></tr>
 	<tr><td><a href="https://wg21.link/P1007R3">P1007R3</a></td><td>LWG</td><td><tt>std::assume_aligned</tt></td><td>San Diego</td><td><i> </i></td><td></td></tr>
@@ -201,7 +201,7 @@ <h3>Paper Status</h3>
 	<tr><td><a href="https://wg21.link/P1645">P1645</a></td><td>LWG</td><td>constexpr for numeric algorithms </td><td>Belfast</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1664">P1664</a></td><td>LWG</td><td>reconstructible_range - a concept for putting ranges back together </td><td>Belfast</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1686">P1686</a></td><td>LWG</td><td>Mandating the Standard Library: Clause 27 - Time library </td><td>Belfast</td><td><i> </i></td><td></td></tr>
-	<tr><td><a href="https://wg21.link/P1690">P1690</a></td><td>LWG</td><td>Refinement Proposal for P0919 Heterogeneous lookup for unordered containers </td><td>Belfast</td><td><i> </i></td><td></td></tr>
+	<tr><td><a href="https://wg21.link/P1690">P1690</a></td><td>LWG</td><td>Refinement Proposal for P0919 Heterogeneous lookup for unordered containers </td><td>Belfast</td><td>Complete</td><td>12.0</td></tr>
 	<tr><td><a href="https://wg21.link/P1716">P1716</a></td><td>LWG</td><td>ranges compare algorithm are over-constrained </td><td>Belfast</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1718">P1718</a></td><td>LWG</td><td>Mandating the Standard Library: Clause 25 - Algorithms library </td><td>Belfast</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1719">P1719</a></td><td>LWG</td><td>Mandating the Standard Library: Clause 26 - Numerics library </td><td>Belfast</td><td><i> </i></td><td></td></tr>


        


More information about the libcxx-commits mailing list