[libcxx-commits] [libcxx] 68072a7 - [libc++] P0433R2: test that deduction guides are properly SFINAEd away.

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 9 09:32:37 PST 2021


Author: Konstantin Varlamov
Date: 2021-11-09T09:32:24-08:00
New Revision: 68072a71662a7955b65a761b8e36a5ef6d38186a

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

LOG: [libc++] P0433R2: test that deduction guides are properly SFINAEd away.

Deduction guides for containers should not participate in overload
resolution when called with certain incorrect types (e.g. when called
with a template argument in place of an `InputIterator` that doesn't
qualify as an input iterator). Similarly, class template argument
deduction should not select `unique_ptr` constructors that take a
a pointer.

The tests try out every possible incorrect parameter (but never more
than one incorrect parameter in the same invocation).

Also add deduction guides to the synopsis for associative and unordered
containers (this was accidentally omitted from [D112510](https://reviews.llvm.org/D112510)).

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

Added: 
    libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp
    libcxx/test/support/deduction_guides_sfinae_checks.h

Modified: 
    libcxx/docs/Status/Cxx17.rst
    libcxx/docs/Status/Cxx17Papers.csv
    libcxx/include/__memory/allocator_traits.h
    libcxx/include/deque
    libcxx/include/forward_list
    libcxx/include/list
    libcxx/include/map
    libcxx/include/queue
    libcxx/include/set
    libcxx/include/unordered_map
    libcxx/include/unordered_set
    libcxx/include/vector
    libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
    libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
    libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp
    libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp
    libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
    libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
    libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
    libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
    libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
    libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp
    libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx17.rst b/libcxx/docs/Status/Cxx17.rst
index 1131950820f2a..7afeb1bf48d5c 100644
--- a/libcxx/docs/Status/Cxx17.rst
+++ b/libcxx/docs/Status/Cxx17.rst
@@ -40,7 +40,6 @@ Paper Status
 
 .. note::
 
-   .. [#note-P0433] P0433: The only part not fully implemented is the requirement that certain deduction guides should not participate in overload resolution when given incorrect template arguments.
    .. [#note-P0607] P0607: The parts of P0607 that are not done are the ``<regex>`` bits.
 
 

diff  --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv
index 642a374496da4..9bb16bcb5ede7 100644
--- a/libcxx/docs/Status/Cxx17Papers.csv
+++ b/libcxx/docs/Status/Cxx17Papers.csv
@@ -94,7 +94,7 @@
 "`P0298R3 <https://wg21.link/P0298R3>`__","CWG","A byte type definition","Kona","|Complete|","5.0"
 "`P0317R1 <https://wg21.link/P0317R1>`__","LWG","Directory Entry Caching for Filesystem","Kona","|Complete|","7.0"
 "`P0430R2 <https://wg21.link/P0430R2>`__","LWG","File system library on non-POSIX-like operating systems","Kona","|Complete|","7.0"
-"`P0433R2 <https://wg21.link/P0433R2>`__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|In Progress| [#note-P0433]_","7.0"
+"`P0433R2 <https://wg21.link/P0433R2>`__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|Complete|","14.0"
 "`P0452R1 <https://wg21.link/P0452R1>`__","LWG","Unifying <numeric> Parallel Algorithms","Kona","",""
 "`P0467R2 <https://wg21.link/P0467R2>`__","LWG","Iterator Concerns for Parallel Algorithms","Kona","",""
 "`P0492R2 <https://wg21.link/P0492R2>`__","LWG","Proposed Resolution of C++17 National Body Comments for Filesystems","Kona","|Complete|","7.0"

diff  --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h
index f4c8fa02d650c..cc32352ae11c6 100644
--- a/libcxx/include/__memory/allocator_traits.h
+++ b/libcxx/include/__memory/allocator_traits.h
@@ -349,6 +349,14 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
     }
 };
 
+// A version of `allocator_traits` for internal usage that SFINAEs away if the
+// given allocator doesn't have a nested `value_type`. This helps avoid hard
+// errors when forming implicit deduction guides for a container that has an
+// invalid Allocator type. See https://wg21.link/LWGXXXXX.
+// TODO(varconst): use the actual link once available.
+template <class _Alloc, class _ValueType = typename _Alloc::value_type>
+struct _LIBCPP_TEMPLATE_VIS __allocator_traits : allocator_traits<_Alloc> {};
+
 template <class _Traits, class _Tp>
 struct __rebind_alloc_helper {
 #ifndef _LIBCPP_CXX03_LANG

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index 12e0399eaa015..95ded311c5432 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -129,7 +129,7 @@ public:
 
 template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
    deque(InputIterator, InputIterator, Allocator = Allocator())
-   -> deque<typename iterator_traits<InputIterator>::value_type, Allocator>;
+   -> deque<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
 
 template <class T, class Allocator>
     bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
@@ -162,6 +162,7 @@ template <class T, class Allocator, class Predicate>
 
 #include <__config>
 #include <__debug>
+#include <__iterator/iterator_traits.h>
 #include <__split_buffer>
 #include <__utility/forward.h>
 #include <algorithm>
@@ -1258,20 +1259,20 @@ public:
     static_assert((is_same<typename allocator_type::value_type, value_type>::value),
                   "Allocator::value_type must be same type as value_type");
 
-    typedef __deque_base<value_type, allocator_type> __base;
+    typedef __deque_base<value_type, allocator_type>                 __base;
 
-    typedef typename __base::__alloc_traits        __alloc_traits;
-    typedef typename __base::reference             reference;
-    typedef typename __base::const_reference       const_reference;
-    typedef typename __base::iterator              iterator;
-    typedef typename __base::const_iterator        const_iterator;
-    typedef typename __base::size_type             size_type;
-    typedef typename __base::
diff erence_type       
diff erence_type;
+    typedef typename __base::__alloc_traits                          __alloc_traits;
+    typedef typename __base::reference                               reference;
+    typedef typename __base::const_reference                         const_reference;
+    typedef typename __base::iterator                                iterator;
+    typedef typename __base::const_iterator                          const_iterator;
+    typedef typename __allocator_traits<allocator_type>::size_type   size_type;
+    typedef typename __base::
diff erence_type                         
diff erence_type;
 
-    typedef typename __base::pointer               pointer;
-    typedef typename __base::const_pointer         const_pointer;
-    typedef _VSTD::reverse_iterator<iterator>       reverse_iterator;
-    typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename __base::pointer                                 pointer;
+    typedef typename __base::const_pointer                           const_pointer;
+    typedef _VSTD::reverse_iterator<iterator>                        reverse_iterator;
+    typedef _VSTD::reverse_iterator<const_iterator>                  const_reverse_iterator;
 
     using typename __base::__deque_range;
     using typename __base::__deque_block_range;
@@ -1568,6 +1569,7 @@ public:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator,
          class _Alloc = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 deque(_InputIterator, _InputIterator)
@@ -1575,13 +1577,13 @@ deque(_InputIterator, _InputIterator)
 
 template<class _InputIterator,
          class _Alloc,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 deque(_InputIterator, _InputIterator, _Alloc)
   -> deque<__iter_value_type<_InputIterator>, _Alloc>;
 #endif
 
-
 template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(size_type __n)
 {

diff  --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 3454a784a1ca7..717dc904e3028 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -647,7 +647,7 @@ public:
     typedef const value_type&                                          const_reference;
     typedef typename allocator_traits<allocator_type>::pointer         pointer;
     typedef typename allocator_traits<allocator_type>::const_pointer   const_pointer;
-    typedef typename allocator_traits<allocator_type>::size_type       size_type;
+    typedef typename __allocator_traits<allocator_type>::size_type     size_type;
     typedef typename allocator_traits<allocator_type>::
diff erence_type 
diff erence_type;
 
     typedef typename base::iterator       iterator;
@@ -873,6 +873,7 @@ private:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator,
          class _Alloc = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 forward_list(_InputIterator, _InputIterator)
@@ -880,6 +881,7 @@ forward_list(_InputIterator, _InputIterator)
 
 template<class _InputIterator,
          class _Alloc,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 forward_list(_InputIterator, _InputIterator, _Alloc)

diff  --git a/libcxx/include/list b/libcxx/include/list
index 80abe1c890aed..cd526f12e2ffc 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -845,24 +845,24 @@ class _LIBCPP_TEMPLATE_VIS list
     typedef typename base::__link_pointer __link_pointer;
 
 public:
-    typedef _Tp                                      value_type;
-    typedef _Alloc                                   allocator_type;
+    typedef _Tp                                                      value_type;
+    typedef _Alloc                                                   allocator_type;
     static_assert((is_same<value_type, typename allocator_type::value_type>::value),
                   "Invalid allocator::value_type");
-    typedef value_type&                              reference;
-    typedef const value_type&                        const_reference;
-    typedef typename base::pointer                   pointer;
-    typedef typename base::const_pointer             const_pointer;
-    typedef typename base::size_type                 size_type;
-    typedef typename base::
diff erence_type           
diff erence_type;
-    typedef typename base::iterator                  iterator;
-    typedef typename base::const_iterator            const_iterator;
-    typedef _VSTD::reverse_iterator<iterator>         reverse_iterator;
-    typedef _VSTD::reverse_iterator<const_iterator>   const_reverse_iterator;
+    typedef value_type&                                              reference;
+    typedef const value_type&                                        const_reference;
+    typedef typename base::pointer                                   pointer;
+    typedef typename base::const_pointer                             const_pointer;
+    typedef typename __allocator_traits<allocator_type>::size_type   size_type;
+    typedef typename base::
diff erence_type                           
diff erence_type;
+    typedef typename base::iterator                                  iterator;
+    typedef typename base::const_iterator                            const_iterator;
+    typedef _VSTD::reverse_iterator<iterator>                        reverse_iterator;
+    typedef _VSTD::reverse_iterator<const_iterator>                  const_reverse_iterator;
 #if _LIBCPP_STD_VER > 17
-    typedef size_type                                __remove_return_type;
+    typedef size_type                                                __remove_return_type;
 #else
-    typedef void                                     __remove_return_type;
+    typedef void                                                     __remove_return_type;
 #endif
 
     _LIBCPP_INLINE_VISIBILITY
@@ -1144,6 +1144,7 @@ private:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator,
          class _Alloc = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 list(_InputIterator, _InputIterator)
@@ -1151,6 +1152,7 @@ list(_InputIterator, _InputIterator)
 
 template<class _InputIterator,
          class _Alloc,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 list(_InputIterator, _InputIterator, _Alloc)

diff  --git a/libcxx/include/map b/libcxx/include/map
index 667dc0e3f883e..867004aec1053 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -223,6 +223,25 @@ public:
         pair<const_iterator,const_iterator> equal_range(const K& x) const;  // C++14
 };
 
+template <class InputIterator,
+      class Compare = less<iter_key_t<InputIterator>>,
+      class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
+map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
+  -> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17
+
+template<class Key, class T, class Compare = less<Key>,
+    class Allocator = allocator<pair<const Key, T>>>
+map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
+  -> map<Key, T, Compare, Allocator>; // C++17
+
+template <class InputIterator, class Allocator>
+map(InputIterator, InputIterator, Allocator)
+  -> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, less<iter_key_t<InputIterator>>,
+    Allocator>; // C++17
+
+template<class Key, class T, class Allocator>
+map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>; // C++17
+
 template <class Key, class T, class Compare, class Allocator>
 bool
 operator==(const map<Key, T, Compare, Allocator>& x,
@@ -444,6 +463,26 @@ public:
         pair<const_iterator,const_iterator> equal_range(const K& x) const;  // C++14
 };
 
+template <class InputIterator,
+      class Compare = less<iter_key_t<InputIterator>>,
+      class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
+multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
+  -> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17
+
+template<class Key, class T, class Compare = less<Key>,
+    class Allocator = allocator<pair<const Key, T>>>
+multimap(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
+  -> multimap<Key, T, Compare, Allocator>; // C++17
+
+template <class InputIterator, class Allocator>
+multimap(InputIterator, InputIterator, Allocator)
+  -> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
+    less<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class Key, class T, class Allocator>
+multimap(initializer_list<pair<const Key, T>>, Allocator)
+  -> multimap<Key, T, less<Key>, Allocator>; // C++17
+
 template <class Key, class T, class Compare, class Allocator>
 bool
 operator==(const multimap<Key, T, Compare, Allocator>& x,
@@ -492,6 +531,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
 #include <__config>
 #include <__debug>
 #include <__functional/is_transparent.h>
+#include <__iterator/iterator_traits.h>
 #include <__node_handle>
 #include <__tree>
 #include <__utility/forward.h>
@@ -1501,6 +1541,7 @@ private:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
          class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<!__is_allocator<_Compare>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -1514,6 +1555,7 @@ map(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allo
   -> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 map(_InputIterator, _InputIterator, _Allocator)
   -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
@@ -2174,6 +2216,7 @@ private:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
          class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<!__is_allocator<_Compare>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -2187,6 +2230,7 @@ multimap(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator =
   -> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 multimap(_InputIterator, _InputIterator, _Allocator)
   -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,

diff  --git a/libcxx/include/queue b/libcxx/include/queue
index cbd07140a7264..2c5fa3237f5d3 100644
--- a/libcxx/include/queue
+++ b/libcxx/include/queue
@@ -185,16 +185,16 @@ template<class InputIterator, class Allocator>
 priority_queue(InputIterator, InputIterator, Allocator)
     -> priority_queue<iter-value-type<InputIterator>,
                       vector<iter-value-type<InputIterator>, Allocator>,
-                      less<iter-value-type<InputIterator>>>;
+                      less<iter-value-type<InputIterator>>>; // C++17
 
 template<class InputIterator, class Compare, class Allocator>
 priority_queue(InputIterator, InputIterator, Compare, Allocator)
     -> priority_queue<iter-value-type<InputIterator>,
-                      vector<iter-value-type<InputIterator>, Allocator>, Compare>;
+                      vector<iter-value-type<InputIterator>, Allocator>, Compare>; // C++17
 
 template<class InputIterator, class Compare, class Container, class Allocator>
 priority_queue(InputIterator, InputIterator, Compare, Container, Allocator)
-    -> priority_queue<typename Container::value_type, Container, Compare>;
+    -> priority_queue<typename Container::value_type, Container, Compare>; // C++17
 
 template <class T, class Container, class Compare>
   void swap(priority_queue<T, Container, Compare>& x,

diff  --git a/libcxx/include/set b/libcxx/include/set
index a5e80206519b9..42ded23d70f62 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -183,6 +183,25 @@ public:
         pair<const_iterator,const_iterator> equal_range(const K& x) const;  // C++14
 };
 
+template <class InputIterator,
+      class Compare = less<typename iterator_traits<InputIterator>::value_type>,
+      class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
+set(InputIterator, InputIterator,
+    Compare = Compare(), Allocator = Allocator())
+  -> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>; // C++17
+
+template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+  -> set<Key, Compare, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+set(InputIterator, InputIterator, Allocator)
+  -> set<typename iterator_traits<InputIterator>::value_type,
+          less<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17
+
+template<class Key, class Allocator>
+set(initializer_list<Key>, Allocator) -> set<Key, less<Key>, Allocator>; // C++17
+
 template <class Key, class Compare, class Allocator>
 bool
 operator==(const set<Key, Compare, Allocator>& x,
@@ -389,6 +408,25 @@ public:
         pair<const_iterator,const_iterator> equal_range(const K& x) const;  // C++14
 };
 
+template <class InputIterator,
+      class Compare = less<typename iterator_traits<InputIterator>::value_type>,
+      class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
+multiset(InputIterator, InputIterator,
+    Compare = Compare(), Allocator = Allocator())
+  -> multiset<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>; // C++17
+
+template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+  -> multiset<Key, Compare, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+multiset(InputIterator, InputIterator, Allocator)
+  -> multiset<typename iterator_traits<InputIterator>::value_type,
+          less<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17
+
+template<class Key, class Allocator>
+multiset(initializer_list<Key>, Allocator) -> multiset<Key, less<Key>, Allocator>; // C++17
+
 template <class Key, class Compare, class Allocator>
 bool
 operator==(const multiset<Key, Compare, Allocator>& x,
@@ -436,6 +474,7 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred);  // C++20
 #include <__config>
 #include <__debug>
 #include <__functional/is_transparent.h>
+#include <__iterator/iterator_traits.h>
 #include <__node_handle>
 #include <__tree>
 #include <__utility/forward.h>
@@ -462,7 +501,7 @@ public:
     // types:
     typedef _Key                                     key_type;
     typedef key_type                                 value_type;
-    typedef _Compare                                 key_compare;
+    typedef __identity_t<_Compare>                   key_compare;
     typedef key_compare                              value_compare;
     typedef __identity_t<_Allocator>                 allocator_type;
     typedef value_type&                              reference;
@@ -474,7 +513,6 @@ public:
 private:
     typedef __tree<value_type, value_compare, allocator_type> __base;
     typedef allocator_traits<allocator_type>                  __alloc_traits;
-    typedef typename __base::__node_holder                    __node_holder;
 
     __base __tree_;
 
@@ -872,6 +910,7 @@ public:
 template<class _InputIterator,
          class _Compare = less<__iter_value_type<_InputIterator>>,
          class _Allocator = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>,
          class = enable_if_t<!__is_allocator<_Compare>::value, void>>
 set(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -879,12 +918,13 @@ set(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocat
 
 template<class _Key, class _Compare = less<_Key>,
          class _Allocator = allocator<_Key>,
-         class = enable_if_t<__is_allocator<_Allocator>::value, void>,
-         class = enable_if_t<!__is_allocator<_Compare>::value, void>>
+         class = enable_if_t<!__is_allocator<_Compare>::value, void>,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 set(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator())
   -> set<_Key, _Compare, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 set(_InputIterator, _InputIterator, _Allocator)
   -> set<__iter_value_type<_InputIterator>,
@@ -994,7 +1034,7 @@ public:
     // types:
     typedef _Key                                     key_type;
     typedef key_type                                 value_type;
-    typedef _Compare                                 key_compare;
+    typedef __identity_t<_Compare>                   key_compare;
     typedef key_compare                              value_compare;
     typedef __identity_t<_Allocator>                 allocator_type;
     typedef value_type&                              reference;
@@ -1006,7 +1046,6 @@ public:
 private:
     typedef __tree<value_type, value_compare, allocator_type> __base;
     typedef allocator_traits<allocator_type>                  __alloc_traits;
-    typedef typename __base::__node_holder                    __node_holder;
 
     __base __tree_;
 
@@ -1403,6 +1442,7 @@ public:
 template<class _InputIterator,
          class _Compare = less<__iter_value_type<_InputIterator>>,
          class _Allocator = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>,
          class = enable_if_t<!__is_allocator<_Compare>::value, void>>
 multiset(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -1416,6 +1456,7 @@ multiset(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator(
   -> multiset<_Key, _Compare, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
          class = enable_if_t<__is_allocator<_Allocator>::value, void>>
 multiset(_InputIterator, _InputIterator, _Allocator)
   -> multiset<__iter_value_type<_InputIterator>,

diff  --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 417180a530e7c..c6d4137b2103a 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -216,6 +216,47 @@ public:
     void reserve(size_type n);
 };
 
+template<class InputIterator,
+    class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>,
+    class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
+unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_map<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred,
+    Allocator>; // C++17
+
+template<class Key, class T, class Hash = hash<Key>,
+    class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
+unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_map<Key, T, Hash, Pred, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+unordered_map(InputIterator, InputIterator, typename see below::size_type, Allocator)
+  -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
+        hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+unordered_map(InputIterator, InputIterator, Allocator)
+  -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
+        hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class InputIterator, class Hash, class Allocator>
+unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+  -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash,
+          equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class Key, class T, typename Allocator>
+unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator)
+  -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17
+
+template<class Key, class T, typename Allocator>
+unordered_map(initializer_list<pair<const Key, T>>, Allocator)
+  -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17
+
+template<class Key, class T, class Hash, class Allocator>
+unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash, Allocator)
+  -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>; // C++17
+
 template <class Key, class T, class Hash, class Pred, class Alloc>
     void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x,
               unordered_map<Key, T, Hash, Pred, Alloc>& y)
@@ -404,6 +445,48 @@ public:
     void reserve(size_type n);
 };
 
+template<class InputIterator,
+    class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>,
+    class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
+unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_multimap<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred,
+    Allocator>; // C++17
+
+template<class Key, class T, class Hash = hash<Key>,
+    class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
+unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_multimap<Key, T, Hash, Pred, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Allocator)
+  -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
+        hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class InputIterator, class Allocator>
+unordered_multimap(InputIterator, InputIterator, Allocator)
+  -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
+        hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class InputIterator, class Hash, class Allocator>
+unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+  -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash,
+          equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17
+
+template<class Key, class T, typename Allocator>
+unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator)
+  -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17
+
+template<class Key, class T, typename Allocator>
+unordered_multimap(initializer_list<pair<const Key, T>>, Allocator)
+  -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17
+
+template<class Key, class T, class Hash, class Allocator>
+unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash,
+    Allocator)
+  -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>; // C++17
+
 template <class Key, class T, class Hash, class Pred, class Alloc>
     void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
               unordered_multimap<Key, T, Hash, Pred, Alloc>& y)
@@ -434,6 +517,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
 #include <__config>
 #include <__debug>
 #include <__functional/is_transparent.h>
+#include <__iterator/iterator_traits.h>
 #include <__hash_table>
 #include <__node_handle>
 #include <__utility/forward.h>
@@ -1470,6 +1554,7 @@ template<class _InputIterator,
          class _Hash = hash<__iter_key_type<_InputIterator>>,
          class _Pred = equal_to<__iter_key_type<_InputIterator>>,
          class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<!__is_allocator<_Pred>::value>,
@@ -1490,18 +1575,21 @@ unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allo
   -> unordered_map<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator)
   -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
                    hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_map(_InputIterator, _InputIterator, _Allocator)
   -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
                    hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
 
 template<class _InputIterator, class _Hash, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
@@ -2268,6 +2356,7 @@ template<class _InputIterator,
          class _Hash = hash<__iter_key_type<_InputIterator>>,
          class _Pred = equal_to<__iter_key_type<_InputIterator>>,
          class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<!__is_allocator<_Pred>::value>,
@@ -2288,18 +2377,21 @@ unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<
   -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator)
   -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
                         hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_multimap(_InputIterator, _InputIterator, _Allocator)
   -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
                         hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
 
 template<class _InputIterator, class _Hash, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>

diff  --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 5856e4bc40108..33b54d957ffa0 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -182,6 +182,43 @@ public:
     void reserve(size_type n);
 };
 
+template<class InputIterator,
+    class Hash = hash<typename iterator_traits<InputIterator>::value_type>,
+    class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>,
+    class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
+unordered_set(InputIterator, InputIterator, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_set<typename iterator_traits<InputIterator>::value_type,
+        Hash, Pred, Allocator>; // C++17
+
+template<class T, class Hash = hash<T>,
+          class Pred = equal_to<T>, class Allocator = allocator<T>>
+unordered_set(initializer_list<T>, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_set<T, Hash, Pred, Allocator>; // C++17
+
+template<class InputIterator,  class Allocator>
+unordered_set(InputIterator, InputIterator, typename see below::size_type, Allocator)
+  -> unordered_set<typename iterator_traits<InputIterator>::value_type,
+        hash<typename iterator_traits<InputIterator>::value_type>,
+        equal_to<typename iterator_traits<InputIterator>::value_type>,
+        Allocator>; // C++17
+
+template<class InputIterator, class Hash, class Allocator>
+unordered_set(InputIterator, InputIterator, typename see below::size_type,
+    Hash, Allocator)
+  -> unordered_set<typename iterator_traits<InputIterator>::value_type, Hash,
+        equal_to<typename iterator_traits<InputIterator>::value_type>,
+        Allocator>; // C++17
+
+template<class T, class Allocator>
+unordered_set(initializer_list<T>, typename see below::size_type, Allocator)
+  -> unordered_set<T, hash<T>, equal_to<T>, Allocator>; // C++17
+
+template<class T, class Hash, class Allocator>
+unordered_set(initializer_list<T>, typename see below::size_type, Hash, Allocator)
+  -> unordered_set<T, Hash, equal_to<T>, Allocator>; // C++17
+
 template <class Value, class Hash, class Pred, class Alloc>
     void swap(unordered_set<Value, Hash, Pred, Alloc>& x,
               unordered_set<Value, Hash, Pred, Alloc>& y)
@@ -359,6 +396,42 @@ public:
     void reserve(size_type n);
 };
 
+template<class InputIterator,
+    class Hash = hash<typename iterator_traits<InputIterator>::value_type>,
+    class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>,
+    class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
+unordered_multiset(InputIterator, InputIterator, see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_multiset<typename iterator_traits<InputIterator>::value_type,
+        Hash, Pred, Allocator>; // C++17
+
+template<class T, class Hash = hash<T>,
+          class Pred = equal_to<T>, class Allocator = allocator<T>>
+unordered_multiset(initializer_list<T>, typename see below::size_type = see below,
+    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+  -> unordered_multiset<T, Hash, Pred, Allocator>; // C++17
+
+template<class InputIterator,  class Allocator>
+unordered_multiset(InputIterator, InputIterator, typename see below::size_type, Allocator)
+  -> unordered_multiset<typename iterator_traits<InputIterator>::value_type,
+        hash<typename iterator_traits<InputIterator>::value_type>,
+        equal_to<typename iterator_traits<InputIterator>::value_type>,
+        Allocator>; // C++17
+
+template<class InputIterator,  class Hash, class Allocator>
+unordered_multiset(InputIterator, InputIterator, typename see below::size_type,
+    Hash, Allocator)
+  -> unordered_multiset<typename iterator_traits<InputIterator>::value_type, Hash,
+        equal_to<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17
+
+template<class T, class Allocator>
+unordered_multiset(initializer_list<T>, typename see below::size_type, Allocator)
+  -> unordered_multiset<T, hash<T>, equal_to<T>, Allocator>; // C++17
+
+template<class T, class Hash, class Allocator>
+unordered_multiset(initializer_list<T>, typename see below::size_type, Hash, Allocator)
+  -> unordered_multiset<T, Hash, equal_to<T>, Allocator>; // C++17
+
 template <class Value, class Hash, class Pred, class Alloc>
     void swap(unordered_multiset<Value, Hash, Pred, Alloc>& x,
               unordered_multiset<Value, Hash, Pred, Alloc>& y)
@@ -803,6 +876,7 @@ template<class _InputIterator,
          class _Hash = hash<__iter_value_type<_InputIterator>>,
          class _Pred = equal_to<__iter_value_type<_InputIterator>>,
          class _Allocator = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<!__is_allocator<_Pred>::value>,
@@ -823,6 +897,7 @@ unordered_set(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size
   -> unordered_set<_Tp, _Hash, _Pred, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_set(_InputIterator, _InputIterator,
               typename allocator_traits<_Allocator>::size_type, _Allocator)
@@ -832,6 +907,7 @@ unordered_set(_InputIterator, _InputIterator,
                    _Allocator>;
 
 template<class _InputIterator, class _Hash, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
@@ -1468,6 +1544,7 @@ template<class _InputIterator,
          class _Hash = hash<__iter_value_type<_InputIterator>>,
          class _Pred = equal_to<__iter_value_type<_InputIterator>>,
          class _Allocator = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<!__is_allocator<_Pred>::value>,
@@ -1487,6 +1564,7 @@ unordered_multiset(initializer_list<_Tp>, typename allocator_traits<_Allocator>:
   -> unordered_multiset<_Tp, _Hash, _Pred, _Allocator>;
 
 template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>
 unordered_multiset(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator)
   -> unordered_multiset<__iter_value_type<_InputIterator>,
@@ -1495,6 +1573,7 @@ unordered_multiset(_InputIterator, _InputIterator, typename allocator_traits<_Al
                    _Allocator>;
 
 template<class _InputIterator, class _Hash, class _Allocator,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<!__is_allocator<_Hash>::value>,
          class = enable_if_t<!is_integral<_Hash>::value>,
          class = enable_if_t<__is_allocator<_Allocator>::value>>

diff  --git a/libcxx/include/vector b/libcxx/include/vector
index f19aaa1cbd7b6..cfd2fc4aff2cf 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -245,7 +245,7 @@ public:
 
 template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
    vector(InputIterator, InputIterator, Allocator = Allocator())
-   -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>;
+   -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
 
 template <class Allocator> struct hash<std::vector<bool, Allocator>>;
 
@@ -275,6 +275,7 @@ erase_if(vector<T, Allocator>& c, Predicate pred);    // C++20
 #include <__bit_reference>
 #include <__debug>
 #include <__functional_base>
+#include <__iterator/iterator_traits.h>
 #include <__iterator/wrap_iter.h>
 #include <__split_buffer>
 #include <__utility/forward.h>
@@ -349,22 +350,22 @@ class _LIBCPP_TEMPLATE_VIS vector
     : private __vector_base<_Tp, _Allocator>
 {
 private:
-    typedef __vector_base<_Tp, _Allocator>           __base;
-    typedef allocator<_Tp>                           __default_allocator_type;
+    typedef __vector_base<_Tp, _Allocator>                           __base;
+    typedef allocator<_Tp>                                           __default_allocator_type;
 public:
-    typedef vector                                   __self;
-    typedef _Tp                                      value_type;
-    typedef _Allocator                               allocator_type;
-    typedef allocator_traits<allocator_type>         __alloc_traits;
-    typedef value_type&                              reference;
-    typedef const value_type&                        const_reference;
-    typedef typename __alloc_traits::size_type       size_type;
-    typedef typename __alloc_traits::
diff erence_type 
diff erence_type;
-    typedef typename __alloc_traits::pointer         pointer;
-    typedef typename __alloc_traits::const_pointer   const_pointer;
-    typedef __wrap_iter<pointer>                     iterator;
-    typedef __wrap_iter<const_pointer>               const_iterator;
-    typedef _VSTD::reverse_iterator<iterator>        reverse_iterator;
+    typedef vector                                                   __self;
+    typedef _Tp                                                      value_type;
+    typedef _Allocator                                               allocator_type;
+    typedef allocator_traits<allocator_type>                         __alloc_traits;
+    typedef value_type&                                              reference;
+    typedef const value_type&                                        const_reference;
+    typedef typename __allocator_traits<allocator_type>::size_type   size_type;
+    typedef typename __alloc_traits::
diff erence_type                 
diff erence_type;
+    typedef typename __alloc_traits::pointer                         pointer;
+    typedef typename __alloc_traits::const_pointer                   const_pointer;
+    typedef __wrap_iter<pointer>                                     iterator;
+    typedef __wrap_iter<const_pointer>                               const_iterator;
+    typedef _VSTD::reverse_iterator<iterator>                        reverse_iterator;
     typedef _VSTD::reverse_iterator<const_iterator>  const_reverse_iterator;
 
     static_assert((is_same<typename allocator_type::value_type, value_type>::value),
@@ -898,6 +899,7 @@ private:
 #if _LIBCPP_STD_VER >= 17
 template<class _InputIterator,
          class _Alloc = allocator<__iter_value_type<_InputIterator>>,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 vector(_InputIterator, _InputIterator)
@@ -905,6 +907,7 @@ vector(_InputIterator, _InputIterator)
 
 template<class _InputIterator,
          class _Alloc,
+         class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
          class = enable_if_t<__is_allocator<_Alloc>::value>
          >
 vector(_InputIterator, _InputIterator, _Alloc)

diff  --git a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
index 4444782291ecb..f104397955c09 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
@@ -32,6 +32,7 @@
 #include <map>
 #include <type_traits>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 using P = std::pair<int, long>;
@@ -151,5 +152,7 @@ int main(int, char**)
     ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>);
     }
 
+    AssociativeContainerDeductionGuidesSfinaeAway<std::map, std::map<int, long>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
index b1faba622346c..c71a739036fab 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
@@ -32,6 +32,7 @@
 #include <map>
 #include <type_traits>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 using P = std::pair<int, long>;
@@ -151,5 +152,7 @@ int main(int, char**)
     ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>);
     }
 
+    AssociativeContainerDeductionGuidesSfinaeAway<std::multimap, std::multimap<int, long>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp
index a24588f8fd951..233ddd2397921 100644
--- a/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp
@@ -35,6 +35,7 @@
 #include <set>
 #include <type_traits>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 struct NotAnAllocator {
@@ -186,5 +187,7 @@ int main(int, char **) {
     assert(s.size() == 2);
   }
 
+  AssociativeContainerDeductionGuidesSfinaeAway<std::multiset, std::multiset<int>>();
+
   return 0;
 }

diff  --git a/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp
index 7234ee1d913fa..fdc725504b065 100644
--- a/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp
@@ -35,6 +35,7 @@
 #include <set>
 #include <type_traits>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 struct NotAnAllocator {
@@ -184,5 +185,7 @@ int main(int, char **) {
     assert(s.size() == 2);
   }
 
+  AssociativeContainerDeductionGuidesSfinaeAway<std::set, std::set<int>>();
+
   return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
index 6804c4df667dd..7dbeeee735d1f 100644
--- a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
@@ -31,6 +31,7 @@
 #include <cstddef>
 #include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -239,5 +240,121 @@ int main(int, char**)
         }
     }
 
+    // Deduction guides should be SFINAE'd away when given:
+    // - "bad" input iterators (that is, a type not qualifying as an input
+    //   iterator);
+    // - a bad allocator;
+    // - an allocator instead of a comparator;
+    // - an allocator instead of a container;
+    // - an allocator and a container that uses a 
diff erent allocator.
+    {
+        using Comp = std::less<int>;
+        using Cont = std::vector<int>;
+        using Alloc = std::allocator<int>;
+        using Iter = int*;
+
+        // The only requirement in the Standard is that integral types cannot be
+        // considered input iterators, beyond that it is unspecified.
+        using BadIter = int;
+#ifdef _LIBCPP_VERSION
+        struct OutputIter {
+          using iterator_category = std::output_iterator_tag;
+          using value_type = void;
+          using 
diff erence_type = void;
+          using pointer = void;
+          using reference = void;
+
+          const OutputIter& operator*() const { return *this; }
+          const OutputIter& operator++() { return *this; }
+          OutputIter operator++(int) const { return *this; }
+        };
+#endif // _LIBCPP_VERSION
+
+        struct BadAlloc {};
+        using AllocAsComp = Alloc;
+        using AllocAsCont = Alloc;
+        using DiffAlloc = test_allocator<int>;
+
+        // (iter, iter)
+        //
+        // Cannot deduce from (BAD_iter, BAD_iter)
+        static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter>);
+        // Note: (OutputIter, OutputIter) is interpreted as (comp, cont) and fails on accessing
+        // non-existent typedefs in `OutputIter` (as if it were a container). There is no
+        // requirement to SFINAE away bad containers.
+
+        // (iter, iter, comp)
+        //
+        // Cannot deduce from (BAD_iter, BAD_iter, comp)
+        static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter, Comp>);
+        LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp>);
+        // Note: (iter, iter, ALLOC_as_comp) is allowed -- it just calls (iter, iter, alloc).
+
+        // (iter, iter, comp, cont)
+        //
+        // Cannot deduce from (BAD_iter, BAD_iter, comp, cont)
+        static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter, Comp, Cont>);
+        LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp, Cont>);
+        // Cannot deduce from (iter, iter, ALLOC_as_comp, cont)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, AllocAsComp, Cont>);
+        // Note: (iter, iter, comp, ALLOC_as_cont) is allowed -- it just calls (iter, iter, comp,
+        // alloc).
+
+        // (iter, iter, alloc)
+        //
+        // Cannot deduce from (BAD_iter, BAD_iter, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter, Alloc>);
+        LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Alloc>);
+        // Note: (iter, iter, BAD_alloc) is interpreted as (iter, iter, comp) instead and fails upon
+        // instantiation. There is no requirement to SFINAE away bad comparators.
+
+        // (iter, iter, comp, alloc)
+        //
+        // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, AllocAsComp, Alloc>);
+        // Note: (iter, iter, comp, BAD_alloc) is interpreted as (iter, iter, comp, cont) instead
+        // and fails upon instantiation. There is no requirement to SFINAE away bad containers.
+
+        // (iter, iter, comp, cont, alloc)
+        //
+        // Cannot deduce from (BAD_iter, BAD_iter, comp, cont, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter, Comp, Cont, Alloc>);
+        LIBCPP_STATIC_ASSERT(
+            SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp, Cont, Alloc>);
+        // Cannot deduce from (iter, iter, ALLOC_as_comp, cont, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, AllocAsComp, Cont, Alloc>);
+        // Cannot deduce from (iter, iter, comp, ALLOC_as_cont, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, AllocAsCont, Alloc>);
+        // Cannot deduce from (iter, iter, comp, cont, BAD_alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, Cont, BadAlloc>);
+        // Cannot deduce from (iter, iter, comp, cont, DIFFERENT_alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, Cont, DiffAlloc>);
+
+        // (comp, alloc)
+        //
+        // Cannot deduce from (ALLOC_as_comp, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Alloc>);
+        // Cannot deduce from (comp, BAD_alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Comp, BadAlloc>);
+
+        // (comp, cont, alloc)
+        //
+        // Cannot deduce from (ALLOC_as_comp, cont, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Cont, Alloc>);
+        // Cannot deduce from (comp, ALLOC_as_cont, alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Comp, AllocAsCont, Alloc>);
+        // Cannot deduce from (comp, cont, BAD_alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Comp, Cont, BadAlloc>);
+        // Cannot deduce from (comp, cont, DIFFERENT_alloc)
+        static_assert(SFINAEs_away<std::priority_queue, Comp, Cont, DiffAlloc>);
+
+        // (comp, cont)
+        //
+        // Cannot deduce from (ALLOC_as_comp, cont)
+        static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Cont>);
+        // Cannot deduce from (comp, ALLOC_as_cont)
+        static_assert(SFINAEs_away<std::priority_queue, Comp, AllocAsCont>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
index b346edfc8016f..a30d11fd493f1 100644
--- a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
@@ -21,8 +21,8 @@
 #include <iterator>
 #include <cassert>
 #include <cstddef>
-#include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -133,5 +133,27 @@ int main(int, char**)
         }
     }
 
+    // Deduction guides should be SFINAE'd away when given:
+    // - a "bad" allocator (that is, a type not qualifying as an allocator);
+    // - an allocator instead of a container;
+    // - an allocator and a container that uses a 
diff erent allocator.
+    {
+        using Cont = std::list<int>;
+        using Alloc = std::allocator<int>;
+        using DiffAlloc = test_allocator<int>;
+
+        struct BadAlloc {};
+        using AllocAsCont = Alloc;
+
+        // (cont, alloc)
+        //
+        // Cannot deduce from (ALLOC_as_cont, alloc)
+        static_assert(SFINAEs_away<std::queue, AllocAsCont, BadAlloc>);
+        // Cannot deduce from (cont, BAD_alloc)
+        static_assert(SFINAEs_away<std::queue, Cont, BadAlloc>);
+        // Cannot deduce from (cont, DIFFERENT_alloc)
+        static_assert(SFINAEs_away<std::queue, Cont, DiffAlloc>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
index 14a847d68818c..0e6bed76b520d 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
@@ -25,6 +25,7 @@
 #include <cstddef>
 #include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -136,5 +137,27 @@ int main(int, char**)
         }
     }
 
+    // Deduction guides should be SFINAE'd away when given:
+    // - a "bad" allocator (that is, a type not qualifying as an allocator);
+    // - an allocator instead of a container;
+    // - an allocator and a container that uses a 
diff erent allocator.
+    {
+        using Cont = std::list<int>;
+        using Alloc = std::allocator<int>;
+        using DiffAlloc = test_allocator<int>;
+
+        struct BadAlloc {};
+        using AllocAsCont = Alloc;
+
+        // (cont, alloc)
+        //
+        // Cannot deduce from (ALLOC_as_cont, alloc)
+        static_assert(SFINAEs_away<std::stack, AllocAsCont, Alloc>);
+        // Cannot deduce from (cont, BAD_alloc)
+        static_assert(SFINAEs_away<std::stack, Cont, BadAlloc>);
+        // Cannot deduce from (cont, DIFFERENT_alloc)
+        static_assert(SFINAEs_away<std::stack, Cont, DiffAlloc>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
index fb5f69cd042e2..216dcace16cb5 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -121,5 +122,7 @@ int main(int, char**)
         }
     }
 
+    SequenceContainerDeductionGuidesSfinaeAway<std::deque, std::deque<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
index 9af93f9a316a4..61f31af9b6ab6 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -126,5 +127,7 @@ int main(int, char**)
         }
     }
 
+    SequenceContainerDeductionGuidesSfinaeAway<std::forward_list, std::forward_list<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
index afebdf8d817da..a82dac71f1bae 100644
--- a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <climits> // INT_MAX
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -126,5 +127,7 @@ int main(int, char**)
         }
     }
 
+    SequenceContainerDeductionGuidesSfinaeAway<std::list, std::list<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
index 6cdc19a2c89d3..c876662bbbb2b 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
@@ -15,11 +15,13 @@
 //
 
 #include <vector>
-#include <iterator>
 #include <cassert>
 #include <cstddef>
 #include <climits> // INT_MAX
+#include <iterator>
+#include <type_traits>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "test_allocator.h"
@@ -139,5 +141,7 @@ int main(int, char**)
         }
     }
 
+    SequenceContainerDeductionGuidesSfinaeAway<std::vector, std::vector<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
index 791830b2af1f2..d543e38c2ec90 100644
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
@@ -61,6 +61,7 @@
 #include <type_traits>
 #include <unordered_map>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 using P = std::pair<int, long>;
@@ -218,5 +219,7 @@ int main(int, char**)
     ASSERT_SAME_TYPE(decltype(m2), std::unordered_map<int, int>);
     }
 
+    UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_map, std::unordered_map<int, long>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
index 8d23afaeb0c3b..527cc4c247e8f 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
@@ -61,6 +61,7 @@
 #include <type_traits>
 #include <unordered_map>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 using P = std::pair<int, long>;
@@ -218,5 +219,7 @@ int main(int, char**)
     ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap<int, int>);
     }
 
+    UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_multimap, std::unordered_multimap<int, long>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp
index d8da875030dd2..912a6d8653259 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp
@@ -53,6 +53,7 @@
 #include <type_traits>
 #include <unordered_set>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 int main(int, char**)
@@ -192,5 +193,7 @@ int main(int, char**)
     assert(s.get_allocator().get_id() == 42);
     }
 
+    UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_multiset, std::unordered_multiset<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp
index a252497a3cdd7..13c541692d1ba 100644
--- a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp
@@ -53,6 +53,7 @@
 #include <type_traits>
 #include <unordered_set>
 
+#include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
 
 int main(int, char**)
@@ -192,5 +193,7 @@ int main(int, char**)
     assert(s.get_allocator().get_id() == 42);
     }
 
+    UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_set, std::unordered_set<int>>();
+
     return 0;
 }

diff  --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp
new file mode 100644
index 0000000000000..7243f5857fcd1
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <memory>
+
+// unique_ptr
+
+// The following constructors should not be selected by class template argument
+// deduction:
+//
+// explicit unique_ptr(pointer p)
+// unique_ptr(pointer p, const D& d) noexcept
+// unique_ptr(pointer p, remove_reference_t<D>&& d) noexcept
+
+#include <memory>
+
+#include "deduction_guides_sfinae_checks.h"
+
+struct Deleter {
+  void operator()(int* p) const { delete p; }
+};
+
+int main(int, char**) {
+  // Cannot deduce from (ptr).
+  static_assert(SFINAEs_away<std::unique_ptr, int*>);
+  // Cannot deduce from (array).
+  static_assert(SFINAEs_away<std::unique_ptr, int[]>);
+  // Cannot deduce from (ptr, Deleter&&).
+  static_assert(SFINAEs_away<std::unique_ptr, int*, Deleter&&>);
+  // Cannot deduce from (array, Deleter&&).
+  static_assert(SFINAEs_away<std::unique_ptr, int[], Deleter&&>);
+  // Cannot deduce from (ptr, const Deleter&).
+  static_assert(SFINAEs_away<std::unique_ptr, int*, const Deleter&>);
+  // Cannot deduce from (array, const Deleter&).
+  static_assert(SFINAEs_away<std::unique_ptr, int[], const Deleter&>);
+
+  return 0;
+}

diff  --git a/libcxx/test/support/deduction_guides_sfinae_checks.h b/libcxx/test/support/deduction_guides_sfinae_checks.h
new file mode 100644
index 0000000000000..f1f31c8e8c384
--- /dev/null
+++ b/libcxx/test/support/deduction_guides_sfinae_checks.h
@@ -0,0 +1,309 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H
+#define TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H
+
+#include <initializer_list>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+// `SFINAEs_away` template variable checks whether the template arguments for
+// a given template class `Instantiated` can be deduced from the given
+// constructor parameter types `CtrArgs` using CTAD.
+
+template<template<typename ...> class Instantiated, class ...CtrArgs,
+    class = decltype(Instantiated(std::declval<CtrArgs>()...))>
+std::false_type SFINAEs_away_impl(int);
+
+template<template<typename ...> class Instantiated, class ...CtrArgs>
+std::true_type SFINAEs_away_impl(...);
+
+template<template<typename ...> class Instantiated, class ...CtrArgs>
+constexpr bool SFINAEs_away =
+    decltype(SFINAEs_away_impl<Instantiated, CtrArgs...>(0))::value;
+
+// For sequence containers the deduction guides should be SFINAE'd away when
+// given:
+// - "bad" input iterators (that is, a type not qualifying as an input
+//   iterator);
+// - a bad allocator.
+template<template<typename ...> class Container, typename InstantiatedContainer>
+constexpr void SequenceContainerDeductionGuidesSfinaeAway() {
+  using Alloc = std::allocator<int>;
+  using Iter = int*;
+
+  struct BadAlloc {};
+  // Note: the only requirement in the Standard is that integral types cannot be
+  // considered input iterators; however, this doesn't work for sequence
+  // containers because they have constructors of the form `(size_type count,
+  // const value_type& value)`. These constructors would be used when passing
+  // two integral types and would deduce `value_type` to be an integral type.
+#ifdef _LIBCPP_VERSION
+  using OutputIter = std::insert_iterator<InstantiatedContainer>;
+#endif // _LIBCPP_VERSION
+
+  // (iter, iter)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter)
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>);
+
+  // (iter, iter, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, alloc)
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>);
+  // Cannot deduce from (iter, iter, BAD_alloc)
+  static_assert(SFINAEs_away<Container, Iter, Iter, BadAlloc>);
+
+  // (alloc)
+  //
+  // Cannot deduce from (alloc)
+  static_assert(SFINAEs_away<Container, Alloc>);
+}
+
+// For associative containers the deduction guides should be SFINAE'd away when
+// given:
+// - "bad" input iterators (that is, a type not qualifying as an input
+//   iterator);
+// - a bad allocator;
+// - an allocator in place of a comparator.
+
+template<template<typename ...> class Container, typename InstantiatedContainer>
+constexpr void AssociativeContainerDeductionGuidesSfinaeAway() {
+  using ValueType = typename InstantiatedContainer::value_type;
+  using Comp = std::less<int>;
+  using Alloc = std::allocator<ValueType>;
+  using Iter = ValueType*;
+  using InitList = std::initializer_list<ValueType>;
+
+  struct BadAlloc {};
+  // The only requirement in the Standard is that integral types cannot be
+  // considered input iterators, beyond that it is unspecified.
+  using BadIter = int;
+#ifdef _LIBCPP_VERSION
+  using OutputIter = std::insert_iterator<InstantiatedContainer>;
+#endif // _LIBCPP_VERSION
+  using AllocAsComp = Alloc;
+
+  // (iter, iter)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>);
+
+  // (iter, iter, comp)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, comp)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, Comp>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Comp>);
+
+  // (iter, iter, comp, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, comp, alloc)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, Comp, Alloc>);
+  LIBCPP_STATIC_ASSERT(
+      SFINAEs_away<Container, OutputIter, OutputIter, Comp, Alloc>);
+  // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc)
+  static_assert(SFINAEs_away<Container, Iter, Iter, AllocAsComp, Alloc>);
+  // Cannot deduce from (iter, iter, comp, BAD_alloc)
+  static_assert(SFINAEs_away<Container, Iter, Iter, Comp, BadAlloc>);
+
+  // (iter, iter, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, alloc)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, Alloc>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>);
+  // Note: (iter, iter, BAD_alloc) is interpreted as (iter, iter, comp)
+  // instead and fails upon instantiation. There is no requirement to SFINAE
+  // away bad comparators.
+
+  // (init_list, comp, alloc)
+  //
+  // Cannot deduce from (init_list, ALLOC_as_comp, alloc)
+  static_assert(SFINAEs_away<Container, InitList, AllocAsComp, Alloc>);
+  // Cannot deduce from (init_list, comp, BAD_alloc)
+  static_assert(SFINAEs_away<Container, InitList, Comp, BadAlloc>);
+
+  // (init_list, alloc)
+  //
+  // Note: (init_list, BAD_alloc) is interpreted as (init_list, comp) instead
+  // and fails upon instantiation. There is no requirement to SFINAE away bad
+  // comparators.
+}
+
+// For unordered containers the deduction guides should be SFINAE'd away when
+// given:
+// - "bad" input iterators (that is, a type not qualifying as an input
+//   iterator);
+// - a bad allocator;
+// - a bad hash functor (an integral type in place of a hash);
+// - an allocator in place of a hash functor;
+// - an allocator in place of a predicate.
+template<template<typename ...> class Container, typename InstantiatedContainer>
+constexpr void UnorderedContainerDeductionGuidesSfinaeAway() {
+  using ValueType = typename InstantiatedContainer::value_type;
+  using Pred = std::equal_to<int>;
+  using Hash = std::hash<int>;
+  using Alloc = std::allocator<ValueType>;
+  using Iter = ValueType*;
+  using InitList = std::initializer_list<ValueType>;
+
+  using BadHash = int;
+  struct BadAlloc {};
+  // The only requirement in the Standard is that integral types cannot be
+  // considered input iterators, beyond that it is unspecified.
+  using BadIter = int;
+#ifdef _LIBCPP_VERSION
+  using OutputIter = std::insert_iterator<InstantiatedContainer>;
+#endif // _LIBCPP_VERSION
+  using AllocAsHash = Alloc;
+  using AllocAsPred = Alloc;
+
+  // (iter, iter)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>);
+
+  // (iter, iter, buckets)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, size_t>);
+
+  // (iter, iter, buckets, hash)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Hash>);
+  LIBCPP_STATIC_ASSERT(
+      SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash>);
+  // Cannot deduce from (iter, iter, buckets, BAD_hash)
+  static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash>);
+  // Note: (iter, iter, buckets, ALLOC_as_hash) is allowed -- it just calls
+  // (iter, iter, buckets, alloc)
+
+  // (iter, iter, buckets, hash, pred)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Hash, Pred>);
+  LIBCPP_STATIC_ASSERT(
+      SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash, Pred>);
+  // Cannot deduce from (iter, iter, buckets, BAD_hash, pred)
+  static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Pred>);
+  // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred)
+  static_assert(SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Pred>);
+  // Note: (iter, iter, buckets, hash, ALLOC_as_pred) is allowed -- it just
+  // calls (iter, iter, buckets, hash, alloc)
+
+  // (iter, iter, buckets, hash, pred, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, BadIter, BadIter, size_t, Hash, Pred, Alloc>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter,
+      size_t, Hash, Pred, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, BAD_hash, pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Pred, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Pred, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, hash, ALLOC_as_pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, Iter, Iter, size_t, Hash, AllocAsPred, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, hash, pred, BAD_alloc)
+  static_assert(
+      SFINAEs_away<Container, Iter, Iter, size_t, Hash, Pred, BadAlloc>);
+
+  // (iter, iter, buckets, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets, alloc)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Alloc>);
+  LIBCPP_STATIC_ASSERT(
+      SFINAEs_away<Container, OutputIter, OutputIter, size_t, Alloc>);
+  // Note: (iter, iter, buckets, BAD_alloc) is interpreted as (iter, iter,
+  // buckets, hash), which is valid because the only requirement for the hash
+  // parameter is that it's not integral.
+
+  // (iter, iter, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, alloc)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, Alloc>);
+  LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>);
+  // Cannot deduce from (iter, iter, BAD_alloc)
+  static_assert(SFINAEs_away<Container, Iter, Iter, BadAlloc>);
+
+  // (iter, iter, buckets, hash, alloc)
+  //
+  // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, alloc)
+  static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Hash, Alloc>);
+  LIBCPP_STATIC_ASSERT(
+      SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, BAD_hash, alloc)
+  static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Alloc>);
+  // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, alloc)
+  static_assert(
+      SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Alloc>);
+  // Note: (iter, iter, buckets, hash, BAD_alloc) is interpreted as (iter, iter,
+  // buckets, hash, pred), which is valid because there are no requirements for
+  // the predicate.
+
+  // (init_list, buckets, hash)
+  //
+  // Cannot deduce from (init_list, buckets, BAD_hash)
+  static_assert(SFINAEs_away<Container, InitList, size_t, BadHash>);
+  // Note: (init_list, buckets, ALLOC_as_hash) is interpreted as (init_list,
+  // buckets, alloc), which is valid.
+
+  // (init_list, buckets, hash, pred)
+  //
+  // Cannot deduce from (init_list, buckets, BAD_hash, pred)
+  static_assert(SFINAEs_away<Container, InitList, size_t, BadHash, Pred>);
+  // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred)
+  static_assert(SFINAEs_away<Container, InitList, size_t, AllocAsHash, Pred>);
+  // Note: (init_list, buckets, hash, ALLOC_as_pred) is interpreted as
+  // (init_list, buckets, hash, alloc), which is valid.
+
+  // (init_list, buckets, hash, pred, alloc)
+  //
+  // Cannot deduce from (init_list, buckets, BAD_hash, pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, InitList, size_t, BadHash, Pred, Alloc>);
+  // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, InitList, size_t, AllocAsHash, Pred, Alloc>);
+  // Cannot deduce from (init_list, buckets, hash, ALLOC_as_pred, alloc)
+  static_assert(
+      SFINAEs_away<Container, InitList, size_t, Hash, AllocAsPred, Alloc>);
+  // Cannot deduce from (init_list, buckets, hash, pred, BAD_alloc)
+  static_assert(
+      SFINAEs_away<Container, InitList, size_t, Hash, Pred, BadAlloc>);
+
+  // (init_list, buckets, alloc)
+  //
+  // Note: (init_list, buckets, BAD_alloc) is interpreted as (init_list,
+  // buckets, hash), which is valid because the only requirement for the hash
+  // parameter is that it's not integral.
+
+  // (init_list, buckets, hash, alloc)
+  //
+  // Cannot deduce from (init_list, buckets, BAD_hash, alloc)
+  static_assert(SFINAEs_away<Container, InitList, size_t, BadHash, Alloc>);
+  // Cannot deduce from (init_list, buckets, ALLOC_as_hash, alloc)
+  static_assert(SFINAEs_away<Container, InitList, size_t, AllocAsHash, Alloc>);
+
+  // (init_list, alloc)
+  //
+  // Cannot deduce from (init_list, BAD_alloc)
+  static_assert(SFINAEs_away<Container, InitList, BadAlloc>);
+}
+
+#endif // TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H


        


More information about the libcxx-commits mailing list