xref: /llvm-project/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp (revision 8426b51e0e942b27af8a50b9cee53c1b68d139c2)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03
10 
11 // <utility>
12 
13 // template <class T1, class T2> struct pair
14 
15 // template <class U, class V>
16 //   constexpr explicit(see below) pair(pair<U, V>&& p);
17 
18 #include <utility>
19 #include <memory>
20 #include <cassert>
21 
22 #include "archetypes.h"
23 #include "test_convertible.h"
24 
25 #include "test_macros.h"
26 using namespace ImplicitTypes; // Get implicitly archetypes
27 
28 template <class T1, class U1,
29           bool CanCopy = true, bool CanConvert = CanCopy>
test_pair_rv()30 void test_pair_rv()
31 {
32     using P1 = std::pair<T1, int>;
33     using P2 = std::pair<int, T1>;
34     using UP1 = std::pair<U1, int>&&;
35     using UP2 = std::pair<int, U1>&&;
36     static_assert(std::is_constructible<P1, UP1>::value == CanCopy, "");
37     static_assert(test_convertible<P1, UP1>() == CanConvert, "");
38     static_assert(std::is_constructible<P2, UP2>::value == CanCopy, "");
39     static_assert(test_convertible<P2,  UP2>() == CanConvert, "");
40 }
41 
42 struct Base
43 {
~BaseBase44     virtual ~Base() {}
45 };
46 
47 struct Derived
48     : public Base
49 {
50 };
51 
52 
53 template <class T, class U>
54 struct DPair : public std::pair<T, U> {
55   using Base = std::pair<T, U>;
56   using Base::Base;
57 };
58 
59 struct ExplicitT {
ExplicitTExplicitT60   constexpr explicit ExplicitT(int x) : value(x) {}
61   int value;
62 };
63 
64 struct ImplicitT {
ImplicitTImplicitT65   constexpr ImplicitT(int x) : value(x) {}
66   int value;
67 };
68 
69 struct NotCopyOrMoveConstructible {
70   NotCopyOrMoveConstructible() = default;
71   NotCopyOrMoveConstructible(NotCopyOrMoveConstructible const&) = delete;
72   NotCopyOrMoveConstructible(NotCopyOrMoveConstructible&&) = delete;
73 };
74 
75 struct NonCopyConstructible {
76     NonCopyConstructible(NonCopyConstructible const&) = delete;
77     NonCopyConstructible(NonCopyConstructible&&) = default;
78 };
79 
main(int,char **)80 int main(int, char**)
81 {
82     {
83         typedef std::pair<std::unique_ptr<Derived>, int> P1;
84         typedef std::pair<std::unique_ptr<Base>, long> P2;
85         P1 p1(std::unique_ptr<Derived>(), 4);
86         P2 p2 = std::move(p1);
87         assert(p2.first == nullptr);
88         assert(p2.second == 4);
89     }
90     {
91         // We allow derived types to use this constructor
92         using P1 = DPair<long, long>;
93         using P2 = std::pair<int, int>;
94         P1 p1(42, 101);
95         P2 p2(std::move(p1));
96         assert(p2.first == 42);
97         assert(p2.second == 101);
98     }
99     {
100         test_pair_rv<AllCtors, AllCtors>();
101         test_pair_rv<AllCtors, AllCtors&>();
102         test_pair_rv<AllCtors, AllCtors&&>();
103         test_pair_rv<AllCtors, const AllCtors&>();
104         test_pair_rv<AllCtors, const AllCtors&&>();
105 
106         test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors>();
107         test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors&, true, false>();
108         test_pair_rv<ExplicitTypes::AllCtors, ExplicitTypes::AllCtors&&, true, false>();
109         test_pair_rv<ExplicitTypes::AllCtors, const ExplicitTypes::AllCtors&, true, false>();
110         test_pair_rv<ExplicitTypes::AllCtors, const ExplicitTypes::AllCtors&&, true, false>();
111 
112         test_pair_rv<MoveOnly, MoveOnly>();
113         test_pair_rv<MoveOnly, MoveOnly&, false>();
114         test_pair_rv<MoveOnly, MoveOnly&&>();
115 
116         test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly>(); // copy construction
117         test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly&, false>();
118         test_pair_rv<ExplicitTypes::MoveOnly, ExplicitTypes::MoveOnly&&, true, false>();
119 
120         test_pair_rv<CopyOnly, CopyOnly>();
121         test_pair_rv<CopyOnly, CopyOnly&>();
122         test_pair_rv<CopyOnly, CopyOnly&&>();
123 
124         /* For ExplicitTypes::CopyOnly, two of the viable candidates for initializing from a non-const xvalue are:
125          *   pair(const pair&);  // (defaulted copy constructor)
126          *   template<class U1, class U2> explicit pair(const pair<U1, U2>&&); [U1 = ExplicitTypes::CopyOnly, U2 = int]
127          *
128          * This results in diverging behavior for test_convertible which uses copy-list-initialization.
129          * Prior to CWG2137, this would have selected the first (non-explicit) ctor as explicit ctors
130          * would not be considered. Afterwards, it should select the second since it is a better match,
131          * and then failed because it is explicit.
132          *
133          * This may change with future defect reports, and some compilers only have partial support
134          * for CWG2137, so use std::is_convertible directly to avoid a copy-list-initialization
135          */
136         {
137           using P1  = std::pair<ExplicitTypes::CopyOnly, int>;
138           using P2  = std::pair<int, ExplicitTypes::CopyOnly>;
139           using UP1 = std::pair<ExplicitTypes::CopyOnly, int>&&;
140           using UP2 = std::pair<int, ExplicitTypes::CopyOnly>&&;
141           static_assert(std::is_constructible<P1, UP1>::value, "");
142           static_assert(std::is_convertible<P1, UP1>::value, "");
143           static_assert(std::is_constructible<P2, UP2>::value, "");
144           static_assert(std::is_convertible<P2, UP2>::value, "");
145         }
146         test_pair_rv<ExplicitTypes::CopyOnly, ExplicitTypes::CopyOnly&, true, false>();
147         test_pair_rv<ExplicitTypes::CopyOnly, ExplicitTypes::CopyOnly&&, true, false>();
148 
149         test_pair_rv<NonCopyable, NonCopyable, false>();
150         test_pair_rv<NonCopyable, NonCopyable&, false>();
151         test_pair_rv<NonCopyable, NonCopyable&&, false>();
152         test_pair_rv<NonCopyable, const NonCopyable&, false>();
153         test_pair_rv<NonCopyable, const NonCopyable&&, false>();
154     }
155     { // Test construction of references
156         test_pair_rv<NonCopyable&, NonCopyable&>();
157         test_pair_rv<NonCopyable&, NonCopyable&&>();
158         test_pair_rv<NonCopyable&, NonCopyable const&, false>();
159         test_pair_rv<NonCopyable const&, NonCopyable&&>();
160         test_pair_rv<NonCopyable&&, NonCopyable&&>();
161 
162         test_pair_rv<ConvertingType&, int, false>();
163         test_pair_rv<ExplicitTypes::ConvertingType&, int, false>();
164         // Unfortunately the below conversions are allowed and create dangling
165         // references.
166         //test_pair_rv<ConvertingType&&, int>();
167         //test_pair_rv<ConvertingType const&, int>();
168         //test_pair_rv<ConvertingType const&&, int>();
169         // But these are not because the converting constructor is explicit.
170         test_pair_rv<ExplicitTypes::ConvertingType&&, int, false>();
171         test_pair_rv<ExplicitTypes::ConvertingType const&, int, false>();
172         test_pair_rv<ExplicitTypes::ConvertingType const&&, int, false>();
173     }
174     {
175         test_pair_rv<AllCtors, int, false>();
176         test_pair_rv<ExplicitTypes::AllCtors, int, false>();
177         test_pair_rv<ConvertingType, int>();
178         test_pair_rv<ExplicitTypes::ConvertingType, int, true, false>();
179 
180         test_pair_rv<ConvertingType, int>();
181         test_pair_rv<ConvertingType, ConvertingType>();
182         test_pair_rv<ConvertingType, ConvertingType const&>();
183         test_pair_rv<ConvertingType, ConvertingType&>();
184         test_pair_rv<ConvertingType, ConvertingType&&>();
185 
186         test_pair_rv<ExplicitTypes::ConvertingType, int, true, false>();
187         test_pair_rv<ExplicitTypes::ConvertingType, int&, true, false>();
188         test_pair_rv<ExplicitTypes::ConvertingType, const int&, true, false>();
189         test_pair_rv<ExplicitTypes::ConvertingType, int&&, true, false>();
190         test_pair_rv<ExplicitTypes::ConvertingType, const int&&, true, false>();
191 
192         test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType>();
193         test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType const&, true, false>();
194         test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType&, true, false>();
195         test_pair_rv<ExplicitTypes::ConvertingType, ExplicitTypes::ConvertingType&&, true, false>();
196     }
197     {
198         // When constructing a pair containing a reference, we only bind the
199         // reference, so it doesn't matter whether the type is or isn't
200         // copy/move constructible.
201         {
202             using P1 = std::pair<NotCopyOrMoveConstructible&, long>;
203             using P2 = std::pair<NotCopyOrMoveConstructible&, int>;
204             static_assert(std::is_constructible<P1, P2&&>::value, "");
205 
206             NotCopyOrMoveConstructible obj;
207             P2 p2{obj, 3};
208             P1 p1(std::move(p2));
209             assert(&p1.first == &obj);
210             assert(&p2.first == &obj);
211         }
212         {
213             using P1 = std::pair<NotCopyOrMoveConstructible&&, long>;
214             using P2 = std::pair<NotCopyOrMoveConstructible&&, int>;
215             static_assert(std::is_constructible<P1, P2&&>::value, "");
216 
217             NotCopyOrMoveConstructible obj;
218             P2 p2{std::move(obj), 3};
219             P1 p1(std::move(p2));
220             assert(&p1.first == &obj);
221             assert(&p2.first == &obj);
222         }
223     }
224     {
225         // Make sure we can't move-construct from a pair containing a reference
226         // if that type isn't copy-constructible (since otherwise we'd be stealing
227         // the object through the reference).
228         using P1 = std::pair<NonCopyConstructible, long>;
229         using P2 = std::pair<NonCopyConstructible&, int>;
230         static_assert(!std::is_constructible<P1, P2&&>::value, "");
231     }
232 #if TEST_STD_VER > 11
233     { // explicit constexpr test
234         constexpr std::pair<int, int> p1(42, 43);
235         constexpr std::pair<ExplicitT, ExplicitT> p2(std::move(p1));
236         static_assert(p2.first.value == 42, "");
237         static_assert(p2.second.value == 43, "");
238     }
239     { // implicit constexpr test
240         constexpr std::pair<int, int> p1(42, 43);
241         constexpr std::pair<ImplicitT, ImplicitT> p2 = std::move(p1);
242         static_assert(p2.first.value == 42, "");
243         static_assert(p2.second.value == 43, "");
244     }
245 #endif
246 
247   return 0;
248 }
249