[libcxx-commits] [libcxx] dd15c27 - [libc++] [P1518R2] Better CTAD behavior for containers with allocators.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 18 12:55:41 PDT 2021


Author: Arthur O'Dwyer
Date: 2021-06-18T15:54:46-04:00
New Revision: dd15c2723cd29574c341ec189409a6c83fbefb04

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

LOG: [libc++] [P1518R2] Better CTAD behavior for containers with allocators.

P1518 does the following in C++23 but we'll just do it in C++17 as well:
- Stop requiring `Alloc` to be an allocator on some container-adaptor deduction guides
- Stop deducing from `Allocator` on some sequence container constructors
- Stop deducing from `Allocator` on some other container constructors (libc++ already did this)

The affected constructors are the "allocator-extended" versions of
constructors where the non-allocator arguments are already sufficient
to deduce the allocator type. For example,

    std::pmr::vector<int> v1;
    std::vector v2(v1, std::pmr::new_delete_resource());
    std::stack s2(v1, std::pmr::new_delete_resource());

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

Added: 
    

Modified: 
    libcxx/docs/Cxx2bStatusPaperStatus.csv
    libcxx/include/deque
    libcxx/include/forward_list
    libcxx/include/list
    libcxx/include/queue
    libcxx/include/stack
    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/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

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Cxx2bStatusPaperStatus.csv b/libcxx/docs/Cxx2bStatusPaperStatus.csv
index 9cbd990b0bb94..8905486bb257f 100644
--- a/libcxx/docs/Cxx2bStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2bStatusPaperStatus.csv
@@ -11,3 +11,5 @@
 "`P2212R2 <https://wg21.link/P2212R2>`__","LWG","Relax Requirements for time_point::clock","February 2021","",""
 "`P2259R1 <https://wg21.link/P2259R1>`__","LWG","Repairing input range adaptors and counted_iterator","February 2021","",""
 "","","","","",""
+"`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
+"","","","","",""

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index 4780a24d3837a..526a1c83c6d00 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -1317,7 +1317,7 @@ public:
         deque(_InputIter __f, _InputIter __l, const allocator_type& __a,
               typename enable_if<__is_cpp17_input_iterator<_InputIter>::value>::type* = 0);
     deque(const deque& __c);
-    deque(const deque& __c, const allocator_type& __a);
+    deque(const deque& __c, const __identity_t<allocator_type>& __a);
 
     deque& operator=(const deque& __c);
 
@@ -1331,7 +1331,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__base>::value);
     _LIBCPP_INLINE_VISIBILITY
-    deque(deque&& __c, const allocator_type& __a);
+    deque(deque&& __c, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     deque& operator=(deque&& __c)
         _NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
@@ -1660,7 +1660,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c)
 }
 
 template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(const deque& __c, const allocator_type& __a)
+deque<_Tp, _Allocator>::deque(const deque& __c, const __identity_t<allocator_type>& __a)
     : __base(__a)
 {
     __append(__c.begin(), __c.end());
@@ -1703,7 +1703,7 @@ deque<_Tp, _Allocator>::deque(deque&& __c)
 
 template <class _Tp, class _Allocator>
 inline
-deque<_Tp, _Allocator>::deque(deque&& __c, const allocator_type& __a)
+deque<_Tp, _Allocator>::deque(deque&& __c, const __identity_t<allocator_type>& __a)
     : __base(_VSTD::move(__c), __a)
 {
     if (__a != __c.__alloc())

diff  --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 66bb449d9f759..086e8ef4ca6ae 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -681,7 +681,7 @@ public:
                        __is_cpp17_input_iterator<_InputIterator>::value
                      >::type* = nullptr);
     forward_list(const forward_list& __x);
-    forward_list(const forward_list& __x, const allocator_type& __a);
+    forward_list(const forward_list& __x, const __identity_t<allocator_type>& __a);
 
     forward_list& operator=(const forward_list& __x);
 
@@ -690,7 +690,7 @@ public:
     forward_list(forward_list&& __x)
         _NOEXCEPT_(is_nothrow_move_constructible<base>::value)
         : base(_VSTD::move(__x)) {}
-    forward_list(forward_list&& __x, const allocator_type& __a);
+    forward_list(forward_list&& __x, const __identity_t<allocator_type>& __a);
 
     forward_list(initializer_list<value_type> __il);
     forward_list(initializer_list<value_type> __il, const allocator_type& __a);
@@ -979,7 +979,7 @@ forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x)
 
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x,
-                                        const allocator_type& __a)
+                                        const __identity_t<allocator_type>& __a)
     : base(__a)
 {
     insert_after(cbefore_begin(), __x.begin(), __x.end());
@@ -1000,7 +1000,7 @@ forward_list<_Tp, _Alloc>::operator=(const forward_list& __x)
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x,
-                                        const allocator_type& __a)
+                                        const __identity_t<allocator_type>& __a)
     : base(_VSTD::move(__x), __a)
 {
     if (base::__alloc() != __x.__alloc())

diff  --git a/libcxx/include/list b/libcxx/include/list
index 439b53398b8f6..f5980570901ad 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -893,7 +893,7 @@ public:
              typename enable_if<__is_cpp17_input_iterator<_InpIter>::value>::type* = 0);
 
     list(const list& __c);
-    list(const list& __c, const allocator_type& __a);
+    list(const list& __c, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     list& operator=(const list& __c);
 #ifndef _LIBCPP_CXX03_LANG
@@ -904,7 +904,7 @@ public:
     list(list&& __c)
         _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value);
     _LIBCPP_INLINE_VISIBILITY
-    list(list&& __c, const allocator_type& __a);
+    list(list&& __c, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     list& operator=(list&& __c)
         _NOEXCEPT_(
@@ -1286,7 +1286,7 @@ list<_Tp, _Alloc>::list(const list& __c)
 }
 
 template <class _Tp, class _Alloc>
-list<_Tp, _Alloc>::list(const list& __c, const allocator_type& __a)
+list<_Tp, _Alloc>::list(const list& __c, const __identity_t<allocator_type>& __a)
     : base(__a)
 {
 #if _LIBCPP_DEBUG_LEVEL == 2
@@ -1333,7 +1333,7 @@ inline list<_Tp, _Alloc>::list(list&& __c)
 
 template <class _Tp, class _Alloc>
 inline
-list<_Tp, _Alloc>::list(list&& __c, const allocator_type& __a)
+list<_Tp, _Alloc>::list(list&& __c, const __identity_t<allocator_type>& __a)
     : base(__a)
 {
 #if _LIBCPP_DEBUG_LEVEL == 2

diff  --git a/libcxx/include/queue b/libcxx/include/queue
index cc9aa874efe0a..9470a75102a67 100644
--- a/libcxx/include/queue
+++ b/libcxx/include/queue
@@ -339,7 +339,7 @@ queue(_Container)
 template<class _Container,
          class _Alloc,
          class = _EnableIf<!__is_allocator<_Container>::value>,
-         class = _EnableIf<__is_allocator<_Alloc>::value>
+         class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
 >
 queue(_Container, _Alloc)
     -> queue<typename _Container::value_type, _Container>;
@@ -554,7 +554,7 @@ template<class _Compare,
          class _Alloc,
          class = _EnableIf<!__is_allocator<_Compare>::value>,
          class = _EnableIf<!__is_allocator<_Container>::value>,
-         class = _EnableIf<__is_allocator<_Alloc>::value>
+         class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
 >
 priority_queue(_Compare, _Container, _Alloc)
     -> priority_queue<typename _Container::value_type, _Container, _Compare>;

diff  --git a/libcxx/include/stack b/libcxx/include/stack
index a45b979dea9c5..c1b2cbeafa07d 100644
--- a/libcxx/include/stack
+++ b/libcxx/include/stack
@@ -239,7 +239,7 @@ stack(_Container)
 template<class _Container,
          class _Alloc,
          class = _EnableIf<!__is_allocator<_Container>::value>,
-         class = _EnableIf<__is_allocator<_Alloc>::value>
+         class = _EnableIf<uses_allocator<_Container, _Alloc>::value>
          >
 stack(_Container, _Alloc)
     -> stack<typename _Container::value_type, _Container>;

diff  --git a/libcxx/include/vector b/libcxx/include/vector
index f75a1694910fe..95ef4391806af 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -557,7 +557,7 @@ public:
     }
 
     vector(const vector& __x);
-    vector(const vector& __x, const allocator_type& __a);
+    vector(const vector& __x, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     vector& operator=(const vector& __x);
 
@@ -577,7 +577,7 @@ public:
 #endif
 
     _LIBCPP_INLINE_VISIBILITY
-    vector(vector&& __x, const allocator_type& __a);
+    vector(vector&& __x, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     vector& operator=(vector&& __x)
         _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
@@ -1261,7 +1261,7 @@ vector<_Tp, _Allocator>::vector(const vector& __x)
 }
 
 template <class _Tp, class _Allocator>
-vector<_Tp, _Allocator>::vector(const vector& __x, const allocator_type& __a)
+vector<_Tp, _Allocator>::vector(const vector& __x, const __identity_t<allocator_type>& __a)
     : __base(__a)
 {
 #if _LIBCPP_DEBUG_LEVEL == 2
@@ -1299,7 +1299,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x)
 
 template <class _Tp, class _Allocator>
 inline _LIBCPP_INLINE_VISIBILITY
-vector<_Tp, _Allocator>::vector(vector&& __x, const allocator_type& __a)
+vector<_Tp, _Allocator>::vector(vector&& __x, const __identity_t<allocator_type>& __a)
     : __base(__a)
 {
 #if _LIBCPP_DEBUG_LEVEL == 2
@@ -2261,7 +2261,7 @@ public:
 #else
         _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
 #endif
-    vector(vector&& __v, const allocator_type& __a);
+    vector(vector&& __v, const __identity_t<allocator_type>& __a);
     _LIBCPP_INLINE_VISIBILITY
     vector& operator=(vector&& __v)
         _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
@@ -2887,7 +2887,7 @@ inline _LIBCPP_INLINE_VISIBILITY vector<bool, _Allocator>::vector(vector&& __v)
 }
 
 template <class _Allocator>
-vector<bool, _Allocator>::vector(vector&& __v, const allocator_type& __a)
+vector<bool, _Allocator>::vector(vector&& __v, const __identity_t<allocator_type>& __a)
     : __begin_(nullptr),
       __size_(0),
       __cap_alloc_(0, __a)

diff  --git a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
index 3023a0bf401e6..139714bc47c33 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
@@ -133,5 +133,24 @@ int main(int, char**)
     assert(m.get_allocator().get_id() == 45);
     }
 
+    {
+    // Examples from LWG3025
+    std::map m{std::pair{1, 1}, {2, 2}, {3, 3}};
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, int>);
+
+    std::map m2{m.begin(), m.end()};
+    ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>);
+    }
+
+    {
+    // Examples from LWG3531
+    std::map m1{{std::pair{1, 2}, {3, 4}}, std::less<int>()};
+    ASSERT_SAME_TYPE(decltype(m1), std::map<int, int>);
+
+    using value_type = std::pair<const int, int>;
+    std::map m2{{value_type{1, 2}, {3, 4}}, std::less<int>()};
+    ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
index 35be4b4cd2b88..e5b42ebb19cce 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
@@ -133,5 +133,24 @@ int main(int, char**)
     assert(m.get_allocator().get_id() == 45);
     }
 
+    {
+    // Examples from LWG3025
+    std::multimap m{std::pair{1, 1}, {2, 2}, {3, 3}};
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, int>);
+
+    std::multimap m2{m.begin(), m.end()};
+    ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>);
+    }
+
+    {
+    // Examples from LWG3531
+    std::multimap m1{{std::pair{1, 2}, {3, 4}}, std::less<int>()};
+    ASSERT_SAME_TYPE(decltype(m1), std::multimap<int, int>);
+
+    using value_type = std::pair<const int, int>;
+    std::multimap m2{{value_type{1, 2}, {3, 4}}, std::less<int>()};
+    ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
index c4f5375bad45a..af155f5f9cbda 100644
--- a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp
@@ -104,21 +104,76 @@ int main(int, char**)
     }
 
     {
-//  This one is odd - you can pass an allocator in to use, but the allocator
-//  has to match the type of the one used by the underlying container
-    typedef long double T;
-    typedef std::greater<T> Comp;
-    typedef test_allocator<T> Alloc;
-    typedef std::deque<T, Alloc> Cont;
-
-    Cont c{2,3,0,1};
-    std::priority_queue<T, Cont, Comp> source(Comp(), c);
-    std::priority_queue pri(source, Alloc(2)); // queue(queue &, allocator)
-    static_assert(std::is_same_v<decltype(pri)::value_type, T>, "");
-    static_assert(std::is_same_v<decltype(pri)::container_type, Cont>, "");
-    assert(pri.size() == 4);
-    assert(pri.top() == 0);
+        typedef short T;
+        typedef std::greater<T> Comp;
+        typedef test_allocator<T> Alloc;
+        typedef std::deque<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        Comp comp;
+        Cont cont;
+        std::priority_queue pri(comp, cont, Alloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        Comp comp;
+        Cont cont;
+        std::priority_queue pri(comp, cont, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        Comp comp;
+        Cont cont;
+        std::priority_queue pri(comp, std::move(cont), Alloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        Comp comp;
+        Cont cont;
+        std::priority_queue pri(comp, std::move(cont), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+    }
+
+    {
+        typedef short T;
+        typedef std::greater<T> Comp;
+        typedef test_allocator<T> Alloc;
+        typedef std::deque<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        std::priority_queue<T, Cont, Comp> source;
+        std::priority_queue pri(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        std::priority_queue<T, Cont, Comp> source;
+        std::priority_queue pri(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        std::priority_queue<T, Cont, Comp> source;
+        std::priority_queue pri(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
+
+        {
+        std::priority_queue<T, Cont, Comp> source;
+        std::priority_queue pri(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
+        }
     }
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
index 738a3a1701638..4404cc19ba02d 100644
--- a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp
@@ -72,21 +72,70 @@ int main(int, char**)
     }
 
     {
-//  This one is odd - you can pass an allocator in to use, but the allocator
-//  has to match the type of the one used by the underlying container
-    typedef short T;
-    typedef test_allocator<T> Alloc;
-    typedef std::deque<T, Alloc> Container;
-
-    Container c{0,1,2,3};
-    std::queue<T, Container> source(c);
-    std::queue que(source, Alloc(2)); // queue(queue &, allocator)
-    static_assert(std::is_same_v<decltype(que)::value_type, T>, "");
-    static_assert(std::is_same_v<decltype(que)::container_type, Container>, "");
-    assert(que.size() == 4);
-    assert(que.back() == 3);
+        typedef short T;
+        typedef test_allocator<T> Alloc;
+        typedef std::list<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        Cont cont;
+        std::queue que(cont, Alloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::queue que(cont, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::queue que(std::move(cont), Alloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::queue que(std::move(cont), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
     }
 
+    {
+        typedef short T;
+        typedef test_allocator<T> Alloc;
+        typedef std::list<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        std::queue<T, Cont> source;
+        std::queue que(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        std::queue<T, Cont> source;
+        std::queue que(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        std::queue<T, Cont> source;
+        std::queue que(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+
+        {
+        std::queue<T, Cont> source;
+        std::queue que(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(que), std::queue<T, Cont>>);
+        }
+    }
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
index fb211f6570d77..5e279fcedbdd6 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp
@@ -22,6 +22,7 @@
 
 
 #include <stack>
+#include <deque>
 #include <vector>
 #include <list>
 #include <iterator>
@@ -75,21 +76,70 @@ int main(int, char**)
     }
 
     {
-//  This one is odd - you can pass an allocator in to use, but the allocator
-//  has to match the type of the one used by the underlying container
-    typedef short T;
-    typedef test_allocator<T> Alloc;
-    typedef std::deque<T, Alloc> Container;
-
-    Container c{0,1,2,3};
-    std::stack<T, Container> source(c);
-    std::stack stk(source, Alloc(2)); // stack(stack &, allocator)
-    static_assert(std::is_same_v<decltype(stk)::value_type, T>, "");
-    static_assert(std::is_same_v<decltype(stk)::container_type, Container>, "");
-    assert(stk.size() == 4);
-    assert(stk.top() == 3);
+        typedef short T;
+        typedef test_allocator<T> Alloc;
+        typedef std::list<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        Cont cont;
+        std::stack stk(cont, Alloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::stack stk(cont, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::stack stk(std::move(cont), Alloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        Cont cont;
+        std::stack stk(std::move(cont), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
     }
 
+    {
+        typedef short T;
+        typedef test_allocator<T> Alloc;
+        typedef std::list<T, Alloc> Cont;
+        typedef test_allocator<int> ConvertibleToAlloc;
+        static_assert(std::uses_allocator_v<Cont, ConvertibleToAlloc> &&
+                      !std::is_same_v<typename Cont::allocator_type, ConvertibleToAlloc>);
+
+        {
+        std::stack<T, Cont> source;
+        std::stack stk(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        std::stack<T, Cont> source;
+        std::stack stk(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        std::stack<T, Cont> source;
+        std::stack stk(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+
+        {
+        std::stack<T, Cont> source;
+        std::stack stk(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(stk), std::stack<T, Cont>>);
+        }
+    }
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
index 1a143819106e7..3f0e16f4d1674 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// <array>
+// <deque>
 // UNSUPPORTED: c++03, c++11, c++14
 // UNSUPPORTED: libcpp-no-deduction-guides
 
@@ -95,5 +95,34 @@ int main(int, char**)
     assert(deq.size() == 0);
     }
 
-  return 0;
+    {
+        typedef test_allocator<short> Alloc;
+        typedef test_allocator<int> ConvertibleToAlloc;
+
+        {
+        std::deque<short, Alloc> source;
+        std::deque deq(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        }
+
+        {
+        std::deque<short, Alloc> source;
+        std::deque deq(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        }
+
+        {
+        std::deque<short, Alloc> source;
+        std::deque deq(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        }
+
+        {
+        std::deque<short, Alloc> source;
+        std::deque deq(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        }
+    }
+
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
index 49b1663da6ed4..6c134d840a238 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp
@@ -12,8 +12,8 @@
 
 
 // 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>;
+//    forward_list(InputIterator, InputIterator, Allocator = Allocator())
+//    -> forward_list<typename iterator_traits<InputIterator>::value_type, Allocator>;
 //
 
 
@@ -100,5 +100,34 @@ int main(int, char**)
     assert(std::distance(fwl.begin(), fwl.end()) == 0); // no size for forward_list
     }
 
-  return 0;
+    {
+        typedef test_allocator<short> Alloc;
+        typedef test_allocator<int> ConvertibleToAlloc;
+
+        {
+        std::forward_list<short, Alloc> source;
+        std::forward_list fwl(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(fwl), decltype(source)>);
+        }
+
+        {
+        std::forward_list<short, Alloc> source;
+        std::forward_list fwl(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(fwl), decltype(source)>);
+        }
+
+        {
+        std::forward_list<short, Alloc> source;
+        std::forward_list fwl(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(fwl), decltype(source)>);
+        }
+
+        {
+        std::forward_list<short, Alloc> source;
+        std::forward_list fwl(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(fwl), decltype(source)>);
+        }
+    }
+
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
index 766288940b911..9196317e81053 100644
--- a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp
@@ -100,5 +100,34 @@ int main(int, char**)
     assert(lst.size() == 0);
     }
 
-  return 0;
+    {
+        typedef test_allocator<short> Alloc;
+        typedef test_allocator<int> ConvertibleToAlloc;
+
+        {
+        std::list<short, Alloc> source;
+        std::list lst(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(lst), decltype(source)>);
+        }
+
+        {
+        std::list<short, Alloc> source;
+        std::list lst(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(lst), decltype(source)>);
+        }
+
+        {
+        std::list<short, Alloc> source;
+        std::list lst(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(lst), decltype(source)>);
+        }
+
+        {
+        std::list<short, Alloc> source;
+        std::list lst(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(lst), decltype(source)>);
+        }
+    }
+
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
index 4921ecda046b0..f343ba84fcaf4 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp
@@ -12,8 +12,8 @@
 
 
 // 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>;
+//    vector(InputIterator, InputIterator, Allocator = Allocator())
+//    -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>;
 //
 
 
@@ -113,5 +113,34 @@ int main(int, char**)
     assert(vec.size() == 0);
     }
 
-  return 0;
+    {
+        typedef test_allocator<short> Alloc;
+        typedef test_allocator<int> ConvertibleToAlloc;
+
+        {
+        std::vector<short, Alloc> source;
+        std::vector vec(source, Alloc(2));
+        static_assert(std::is_same_v<decltype(vec), decltype(source)>);
+        }
+
+        {
+        std::vector<short, Alloc> source;
+        std::vector vec(source, ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(vec), decltype(source)>);
+        }
+
+        {
+        std::vector<short, Alloc> source;
+        std::vector vec(std::move(source), Alloc(2));
+        static_assert(std::is_same_v<decltype(vec), decltype(source)>);
+        }
+
+        {
+        std::vector<short, Alloc> source;
+        std::vector vec(std::move(source), ConvertibleToAlloc(2));
+        static_assert(std::is_same_v<decltype(vec), decltype(source)>);
+        }
+    }
+
+    return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
index 40d0df0630622..195495b5e06b4 100644
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
@@ -200,5 +200,24 @@ int main(int, char**)
     assert(m.get_allocator().get_id() == 48);
     }
 
+    {
+    // Examples from LWG3025
+    std::unordered_map m{std::pair{1, 1}, {2, 2}, {3, 3}};
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_map<int, int>);
+
+    std::unordered_map m2{m.begin(), m.end()};
+    ASSERT_SAME_TYPE(decltype(m2), std::unordered_map<int, int>);
+    }
+
+    {
+    // Examples from LWG3531
+    std::unordered_map m1{{std::pair{1, 2}, {3, 4}}, 0};
+    ASSERT_SAME_TYPE(decltype(m1), std::unordered_map<int, int>);
+
+    using value_type = std::pair<const int, int>;
+    std::unordered_map m2{{value_type{1, 2}, {3, 4}}, 0};
+    ASSERT_SAME_TYPE(decltype(m2), std::unordered_map<int, int>);
+    }
+
     return 0;
 }

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
index 995920e904572..a7639ff5b7048 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
@@ -200,5 +200,24 @@ int main(int, char**)
     assert(m.get_allocator().get_id() == 48);
     }
 
+    {
+    // Examples from LWG3025
+    std::unordered_multimap m{std::pair{1, 1}, {2, 2}, {3, 3}};
+    ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap<int, int>);
+
+    std::unordered_multimap m2{m.begin(), m.end()};
+    ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap<int, int>);
+    }
+
+    {
+    // Examples from LWG3531
+    std::unordered_multimap m1{{std::pair{1, 2}, {3, 4}}, 0};
+    ASSERT_SAME_TYPE(decltype(m1), std::unordered_multimap<int, int>);
+
+    using value_type = std::pair<const int, int>;
+    std::unordered_multimap m2{{value_type{1, 2}, {3, 4}}, 0};
+    ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap<int, int>);
+    }
+
     return 0;
 }


        


More information about the libcxx-commits mailing list