[libc++] Implement P0433: deduction guides for <unordered_map>

Thanks to Arthur O'Dwyer for the patch.

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@366124 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/unordered_map b/include/unordered_map
index 4dfe698..63aecc8 100644
--- a/include/unordered_map
+++ b/include/unordered_map
@@ -844,9 +844,9 @@
     // types
     typedef _Key                                           key_type;
     typedef _Tp                                            mapped_type;
-    typedef _Hash                                          hasher;
-    typedef _Pred                                          key_equal;
-    typedef _Alloc                                         allocator_type;
+    typedef typename __identity<_Hash>::type               hasher;
+    typedef typename __identity<_Pred>::type               key_equal;
+    typedef typename __identity<_Alloc>::type              allocator_type;
     typedef pair<const key_type, mapped_type>              value_type;
     typedef value_type&                                    reference;
     typedef const value_type&                              const_reference;
@@ -1348,6 +1348,73 @@
 #endif
 };
 
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+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 = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<!__is_allocator<_Pred>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0,
+              _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
+  -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Hash, _Pred, _Allocator>;
+
+template<class _Key, class _Tp, class _Hash = hash<remove_const_t<_Key>>,
+         class _Pred = equal_to<remove_const_t<_Key>>,
+         class _Allocator = allocator<pair<const _Key, _Tp>>,
+         class = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<!__is_allocator<_Pred>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type = 0,
+              _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
+  -> unordered_map<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>;
+
+template<class _InputIterator, class _Allocator,
+         class = _EnableIf<__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 = _EnableIf<__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 = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
+  -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
+                   _Hash, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Allocator)
+  -> unordered_map<remove_const_t<_Key>, _Tp,
+                   hash<remove_const_t<_Key>>,
+                   equal_to<remove_const_t<_Key>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(initializer_list<pair<_Key, _Tp>>, _Allocator)
+  -> unordered_map<remove_const_t<_Key>, _Tp,
+                   hash<remove_const_t<_Key>>,
+                   equal_to<remove_const_t<_Key>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Hash, class _Allocator,
+         class = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
+  -> unordered_map<remove_const_t<_Key>, _Tp, _Hash,
+                   equal_to<remove_const_t<_Key>>, _Allocator>;
+#endif
+
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
 unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
         size_type __n, const hasher& __hf, const key_equal& __eql)
@@ -1673,9 +1740,9 @@
     // types
     typedef _Key                                           key_type;
     typedef _Tp                                            mapped_type;
-    typedef _Hash                                          hasher;
-    typedef _Pred                                          key_equal;
-    typedef _Alloc                                         allocator_type;
+    typedef typename __identity<_Hash>::type               hasher;
+    typedef typename __identity<_Pred>::type               key_equal;
+    typedef typename __identity<_Alloc>::type              allocator_type;
     typedef pair<const key_type, mapped_type>              value_type;
     typedef value_type&                                    reference;
     typedef const value_type&                              const_reference;
@@ -2041,6 +2108,73 @@
 
 };
 
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+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 = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<!__is_allocator<_Pred>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0,
+                   _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
+  -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Hash, _Pred, _Allocator>;
+
+template<class _Key, class _Tp, class _Hash = hash<remove_const_t<_Key>>,
+         class _Pred = equal_to<remove_const_t<_Key>>,
+         class _Allocator = allocator<pair<const _Key, _Tp>>,
+         class = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<!__is_allocator<_Pred>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type = 0,
+                   _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
+  -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>;
+
+template<class _InputIterator, class _Allocator,
+         class = _EnableIf<__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 = _EnableIf<__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 = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
+  -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
+                        _Hash, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Allocator)
+  -> unordered_multimap<remove_const_t<_Key>, _Tp,
+                        hash<remove_const_t<_Key>>,
+                        equal_to<remove_const_t<_Key>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(initializer_list<pair<_Key, _Tp>>, _Allocator)
+  -> unordered_multimap<remove_const_t<_Key>, _Tp,
+                        hash<remove_const_t<_Key>>,
+                        equal_to<remove_const_t<_Key>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Hash, class _Allocator,
+         class = _EnableIf<!__is_allocator<_Hash>::value>,
+         class = _EnableIf<!is_integral<_Hash>::value>,
+         class = _EnableIf<__is_allocator<_Allocator>::value>>
+unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
+  -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash,
+                        equal_to<remove_const_t<_Key>>, _Allocator>;
+#endif
+
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
 unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
         size_type __n, const hasher& __hf, const key_equal& __eql)
diff --git a/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.fail.cpp b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.fail.cpp
new file mode 100644
index 0000000..642abce
--- /dev/null
+++ b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.fail.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+// XFAIL: clang-6, apple-clang-9.0, apple-clang-9.1, apple-clang-10.0
+
+// 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>>>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
+//               Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                    Allocator>;
+//
+// 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<Key, T>>,
+//               typename see below::size_type = see below, Hash = Hash(),
+//               Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_map(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                    equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//               Allocator)
+//   -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <functional>
+#include <unordered_map>
+
+int main(int, char**)
+{
+    using P = std::pair<const int, int>;
+    {
+        // cannot deduce Key from nothing
+        std::unordered_map m; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size)
+        std::unordered_map m(42); // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash)
+        std::unordered_map m(42, std::hash<int>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Pred)
+        std::unordered_map m(42, std::hash<int>(), std::equal_to<int>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Pred, Allocator)
+        std::unordered_map m(42, std::hash<int>(), std::equal_to<int>(), std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Allocator)
+        std::unordered_map m(std::allocator<P>{});
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Allocator)
+        std::unordered_map m(42, std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Allocator)
+        std::unordered_map m(42, std::hash<int>(), std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_map'}}
+    }
+
+  return 0;
+}
diff --git a/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
new file mode 100644
index 0000000..0923597
--- /dev/null
+++ b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
@@ -0,0 +1,204 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// 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>>>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
+//               Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                    Allocator>;
+//
+// 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<Key, T>>,
+//               typename see below::size_type = see below, Hash = Hash(),
+//               Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_map(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                    equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//               Allocator)
+//   -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <algorithm> // is_permutation
+#include <cassert>
+#include <climits> // INT_MAX
+#include <type_traits>
+#include <unordered_map>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    const PC expected_m[] = { {1,1}, {2,2}, {3,1}, {INT_MAX,1} };
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 41));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 41);
+    }
+
+    {
+    std::unordered_map<int, long> source;
+    std::unordered_map m(source);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_map<int, long> source;
+    std::unordered_map m{source};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>> source;
+    test_allocator<PC> a(0, 42);
+    std::unordered_map m(source, a);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.get_allocator().get_id() == 42);
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>> source;
+    test_allocator<PC> a(0, 43);
+    std::unordered_map m{source, a};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.get_allocator().get_id() == 43);
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_map m { P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} };
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 44));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, test_allocator<PC>(0, 45));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), test_allocator<PC>(0, 46));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 46);
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, test_allocator<PC>(0, 47));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 47);
+    }
+
+    {
+    std::unordered_map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), test_allocator<PC>(0, 48));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 48);
+    }
+
+    return 0;
+}
diff --git a/test/std/containers/unord/unord.map/unord.map.cnstr/deduct_const.pass.cpp b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct_const.pass.cpp
new file mode 100644
index 0000000..1fb4d67
--- /dev/null
+++ b/test/std/containers/unord/unord.map/unord.map.cnstr/deduct_const.pass.cpp
@@ -0,0 +1,172 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// 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>>>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
+//               Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                    Allocator>;
+//
+// 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<Key, T>>,
+//               typename see below::size_type = see below, Hash = Hash(),
+//               Pred = Pred(), Allocator = Allocator())
+//   -> unordered_map<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_map(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                    equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//               Allocator)
+//   -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <algorithm> // std::is_permutation
+#include <cassert>
+#include <climits> // INT_MAX
+#include <type_traits>
+#include <unordered_map>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    const PC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+
+    {
+    const PC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::unordered_map m(std::begin(arr), std::end(arr));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 41));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 41);
+    }
+
+    {
+    std::unordered_map m { PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} };
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 44));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, test_allocator<PC>(0, 45));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_map m(std::begin(arr), std::end(arr), 42, std::hash<short>(), test_allocator<PC>(0, 46));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 46);
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, test_allocator<PC>(0, 47));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 47);
+    }
+
+    {
+    std::unordered_map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), test_allocator<PC>(0, 48));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 48);
+    }
+
+    return 0;
+}
diff --git a/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.fail.cpp b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.fail.cpp
new file mode 100644
index 0000000..7f17047
--- /dev/null
+++ b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.fail.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+// XFAIL: clang-6, apple-clang-9.0, apple-clang-9.1, apple-clang-10.0
+
+// 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>>>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below,
+//               Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                    Allocator>;
+//
+// 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<Key, T>>,
+//               typename see below::size_type = see below, Hash = Hash(),
+//               Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_multimap(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                    equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//               Allocator)
+//   -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <functional>
+#include <unordered_map>
+
+int main(int, char**)
+{
+    using P = std::pair<const int, int>;
+    {
+        // cannot deduce Key from nothing
+        std::unordered_multimap m; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size)
+        std::unordered_multimap m(42); // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash)
+        std::unordered_multimap m(42, std::hash<int>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Pred)
+        std::unordered_multimap m(42, std::hash<int>(), std::equal_to<int>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Pred, Allocator)
+        std::unordered_multimap m(42, std::hash<int>(), std::equal_to<int>(), std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Allocator)
+        std::unordered_multimap m(std::allocator<P>{});
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Allocator)
+        std::unordered_multimap m(42, std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+    {
+        // cannot deduce Key from just (Size, Hash, Allocator)
+        std::unordered_multimap m(42, std::hash<int>(), std::allocator<P>());
+            // expected-error@-1{{no viable constructor or deduction guide for deduction of template arguments of 'unordered_multimap'}}
+    }
+
+  return 0;
+}
diff --git a/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
new file mode 100644
index 0000000..f620f1e
--- /dev/null
+++ b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
@@ -0,0 +1,204 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// 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>>>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below,
+//                    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                         Allocator>;
+//
+// 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<Key, T>>,
+//                    typename see below::size_type = see below, Hash = Hash(),
+//                    Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_multimap(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                         equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//                    Allocator)
+//   -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <algorithm> // is_permutation
+#include <cassert>
+#include <climits> // INT_MAX
+#include <type_traits>
+#include <unordered_map>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    const PC expected_m[] = { {1,1}, {1,1}, {2,2}, {3,1}, {INT_MAX,1} };
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 41));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 41);
+    }
+
+    {
+    std::unordered_multimap<int, long> source;
+    std::unordered_multimap m(source);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_multimap<int, long> source;
+    std::unordered_multimap m{source};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>> source;
+    test_allocator<PC> a(0, 42);
+    std::unordered_multimap m(source, a);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.get_allocator().get_id() == 42);
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>> source;
+    test_allocator<PC> a(0, 43);
+    std::unordered_multimap m{source, a};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.get_allocator().get_id() == 43);
+    assert(m.size() == 0);
+    }
+
+    {
+    std::unordered_multimap m { P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} };
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 44));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, test_allocator<PC>(0, 45));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    {
+    const P arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), test_allocator<PC>(0, 46));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 46);
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, test_allocator<PC>(0, 47));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 47);
+    }
+
+    {
+    std::unordered_multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, 42, std::hash<short>(), test_allocator<PC>(0, 48));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 48);
+    }
+
+    return 0;
+}
diff --git a/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct_const.pass.cpp b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct_const.pass.cpp
new file mode 100644
index 0000000..8a4a383
--- /dev/null
+++ b/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct_const.pass.cpp
@@ -0,0 +1,173 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// 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>>>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below,
+//                    Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
+//                         Allocator>;
+//
+// 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<Key, T>>,
+//                    typename see below::size_type = see below, Hash = Hash(),
+//                    Pred = Pred(), Allocator = Allocator())
+//   -> unordered_multimap<Key, T, Hash, Pred, Allocator>;
+//
+// template<class InputIterator, class Allocator>
+// unordered_multimap(InputIterator, InputIterator, typename see below::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>
+// 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>
+// unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
+//   -> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
+//                         equal_to<iter-key-type<InputIterator>>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
+//   -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+//
+// template<class Key, class T, class Hash, class Allocator>
+// unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
+//                    Allocator)
+//   -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
+
+#include <algorithm> // is_permutation
+#include <cassert>
+#include <climits> // INT_MAX
+#include <functional>
+#include <type_traits>
+#include <unordered_map>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    const PC expected_m[] = { {1,1}, {1,1}, {2,2}, {3,1}, {INT_MAX,1} };
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 41));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 41);
+    }
+
+    {
+    std::unordered_multimap m { PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} };
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42);
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), std::equal_to<>());
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), std::equal_to<>(), test_allocator<PC>(0, 44));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, test_allocator<PC>(0, 45));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    {
+    const PC arr[] = { {1,1}, {2,2}, {1,1}, {INT_MAX,1}, {3,1} };
+    std::unordered_multimap m(std::begin(arr), std::end(arr), 42, std::hash<short>(), test_allocator<PC>(0, 46));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 46);
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, test_allocator<PC>(0, 47));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<int>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 47);
+    }
+
+    {
+    std::unordered_multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, 42, std::hash<short>(), test_allocator<PC>(0, 48));
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, long, std::hash<short>, std::equal_to<int>, test_allocator<PC>>);
+    assert(std::is_permutation(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 48);
+    }
+
+    return 0;
+}
diff --git a/www/cxx2a_status.html b/www/cxx2a_status.html
index b800ef0..2b19eb8 100644
--- a/www/cxx2a_status.html
+++ b/www/cxx2a_status.html
@@ -283,7 +283,7 @@
 	<tr><td><a href="https://wg21.link/LWG2996">2996</a></td><td>Missing rvalue overloads for <tt>shared_ptr</tt> operations</td><td>San Diego</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3008">3008</a></td><td><tt>make_shared</tt> (sub)object destruction semantics are not specified</td><td>San Diego</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3022">3022</a></td><td><tt>is_convertible&lt;derived*, base*&gt;</tt> may lead to ODR</td><td>San Diego</td><td>Resolved by 1285R0</td></tr>
-	<tr><td><a href="https://wg21.link/LWG3025">3025</a></td><td>Map-like container deduction guides should use <tt>pair&lt;Key, T&gt;</tt>, not <tt>pair&lt;const Key, T&gt;</tt></td><td>San Diego</td><td></td></tr>
+	<tr><td><a href="https://wg21.link/LWG3025">3025</a></td><td>Map-like container deduction guides should use <tt>pair&lt;Key, T&gt;</tt>, not <tt>pair&lt;const Key, T&gt;</tt></td><td>San Diego</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG3031">3031</a></td><td>Algorithms and predicates with non-const reference arguments</td><td>San Diego</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3037">3037</a></td><td><tt>polymorphic_allocator</tt> and incomplete types</td><td>San Diego</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3038">3038</a></td><td><tt>polymorphic_allocator::allocate</tt> should not allow integer overflow to create vulnerabilities</td><td>San Diego</td><td></td></tr>