[libc++] P0433R2: test that deduction guides are properly SFINAEd away.
authorKonstantin Varlamov <varconst@apple.com>
Tue, 9 Nov 2021 17:21:02 +0000 (09:21 -0800)
committerKonstantin Varlamov <varconst@apple.com>
Tue, 9 Nov 2021 17:32:24 +0000 (09:32 -0800)
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

29 files changed:
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
libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp [new file with mode: 0644]
libcxx/test/support/deduction_guides_sfinae_checks.h [new file with mode: 0644]

index 1131950..7afeb1b 100644 (file)
@@ -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.
 
 
index 642a374..9bb16bc 100644 (file)
@@ -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"
index f4c8fa0..cc32352 100644 (file)
@@ -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
index 12e0399..95ded31 100644 (file)
@@ -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::difference_type       difference_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::difference_type                         difference_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)
 {
index 3454a78..717dc90 100644 (file)
@@ -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>::difference_type difference_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)
index 80abe1c..cd526f1 100644 (file)
@@ -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::difference_type           difference_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::difference_type                           difference_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)
index 667dc0e..867004a 100644 (file)
@@ -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>,
index cbd0714..2c5fa32 100644 (file)
@@ -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,
index a5e8020..42ded23 100644 (file)
@@ -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>,
index 417180a..c6d4137 100644 (file)
@@ -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>>
index 5856e4b..33b54d9 100644 (file)
@@ -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>>
index f19aaa1..cfd2fc4 100644 (file)
@@ -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::difference_type difference_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::difference_type                 difference_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)
index 4444782..f104397 100644 (file)
@@ -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;
 }
index b1faba6..c71a739 100644 (file)
@@ -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;
 }
index a24588f..233ddd2 100644 (file)
@@ -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;
 }
index 7234ee1..fdc7255 100644 (file)
@@ -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;
 }
index 6804c4d..7dbeeee 100644 (file)
@@ -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 different 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 difference_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;
 }
index b346edf..a30d11f 100644 (file)
@@ -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 different 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;
 }
index 14a847d..0e6bed7 100644 (file)
@@ -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 different 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;
 }
index fb5f69c..216dcac 100644 (file)
@@ -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;
 }
index 9af93f9..61f31af 100644 (file)
@@ -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;
 }
index afebdf8..a82dac7 100644 (file)
@@ -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;
 }
index 6cdc19a..c876662 100644 (file)
 //
 
 #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;
 }
index 791830b..d543e38 100644 (file)
@@ -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;
 }
index 8d23afa..527cc4c 100644 (file)
@@ -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;
 }
index d8da875..912a6d8 100644 (file)
@@ -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;
 }
index a252497..13c5416 100644 (file)
@@ -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 (file)
index 0000000..7243f58
--- /dev/null
@@ -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 (file)
index 0000000..f1f31c8
--- /dev/null
@@ -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