1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
12 
13 // XFAIL: availability=macosx10.13
14 // XFAIL: availability=macosx10.12
15 // XFAIL: availability=macosx10.11
16 // XFAIL: availability=macosx10.10
17 // XFAIL: availability=macosx10.9
18 // XFAIL: availability=macosx10.8
19 // XFAIL: availability=macosx10.7
20 
21 // <variant>
22 
23 // template <class ...Types> class variant;
24 
25 // variant(variant&&) noexcept(see below);
26 
27 #include <cassert>
28 #include <string>
29 #include <type_traits>
30 #include <variant>
31 
32 #include "test_macros.h"
33 #include "test_workarounds.h"
34 
35 struct ThrowsMove {
36   ThrowsMove(ThrowsMove &&) noexcept(false) {}
37 };
38 
39 struct NoCopy {
40   NoCopy(const NoCopy &) = delete;
41 };
42 
43 struct MoveOnly {
44   int value;
45   MoveOnly(int v) : value(v) {}
46   MoveOnly(const MoveOnly &) = delete;
47   MoveOnly(MoveOnly &&) = default;
48 };
49 
50 struct MoveOnlyNT {
51   int value;
52   MoveOnlyNT(int v) : value(v) {}
53   MoveOnlyNT(const MoveOnlyNT &) = delete;
54   MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
55 };
56 
57 struct NTMove {
58   constexpr NTMove(int v) : value(v) {}
59   NTMove(const NTMove &) = delete;
60   NTMove(NTMove &&that) : value(that.value) { that.value = -1; }
61   int value;
62 };
63 
64 static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");
65 static_assert(std::is_move_constructible<NTMove>::value, "");
66 
67 struct TMove {
68   constexpr TMove(int v) : value(v) {}
69   TMove(const TMove &) = delete;
70   TMove(TMove &&) = default;
71   int value;
72 };
73 
74 static_assert(std::is_trivially_move_constructible<TMove>::value, "");
75 
76 struct TMoveNTCopy {
77   constexpr TMoveNTCopy(int v) : value(v) {}
78   TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}
79   TMoveNTCopy(TMoveNTCopy&&) = default;
80   int value;
81 };
82 
83 static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
84 
85 #ifndef TEST_HAS_NO_EXCEPTIONS
86 struct MakeEmptyT {
87   static int alive;
88   MakeEmptyT() { ++alive; }
89   MakeEmptyT(const MakeEmptyT &) {
90     ++alive;
91     // Don't throw from the copy constructor since variant's assignment
92     // operator performs a copy before committing to the assignment.
93   }
94   MakeEmptyT(MakeEmptyT &&) { throw 42; }
95   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
96   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
97   ~MakeEmptyT() { --alive; }
98 };
99 
100 int MakeEmptyT::alive = 0;
101 
102 template <class Variant> void makeEmpty(Variant &v) {
103   Variant v2(std::in_place_type<MakeEmptyT>);
104   try {
105     v = std::move(v2);
106     assert(false);
107   } catch (...) {
108     assert(v.valueless_by_exception());
109   }
110 }
111 #endif // TEST_HAS_NO_EXCEPTIONS
112 
113 void test_move_noexcept() {
114   {
115     using V = std::variant<int, long>;
116     static_assert(std::is_nothrow_move_constructible<V>::value, "");
117   }
118   {
119     using V = std::variant<int, MoveOnly>;
120     static_assert(std::is_nothrow_move_constructible<V>::value, "");
121   }
122   {
123     using V = std::variant<int, MoveOnlyNT>;
124     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
125   }
126   {
127     using V = std::variant<int, ThrowsMove>;
128     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
129   }
130 }
131 
132 void test_move_ctor_sfinae() {
133   {
134     using V = std::variant<int, long>;
135     static_assert(std::is_move_constructible<V>::value, "");
136   }
137   {
138     using V = std::variant<int, MoveOnly>;
139     static_assert(std::is_move_constructible<V>::value, "");
140   }
141   {
142     using V = std::variant<int, MoveOnlyNT>;
143     static_assert(std::is_move_constructible<V>::value, "");
144   }
145   {
146     using V = std::variant<int, NoCopy>;
147     static_assert(!std::is_move_constructible<V>::value, "");
148   }
149 
150   // The following tests are for not-yet-standardized behavior (P0602):
151   {
152     using V = std::variant<int, long>;
153     static_assert(std::is_trivially_move_constructible<V>::value, "");
154   }
155   {
156     using V = std::variant<int, NTMove>;
157     static_assert(!std::is_trivially_move_constructible<V>::value, "");
158     static_assert(std::is_move_constructible<V>::value, "");
159   }
160   {
161     using V = std::variant<int, TMove>;
162     static_assert(std::is_trivially_move_constructible<V>::value, "");
163   }
164   {
165     using V = std::variant<int, TMoveNTCopy>;
166     static_assert(std::is_trivially_move_constructible<V>::value, "");
167   }
168 }
169 
170 template <typename T>
171 struct Result { size_t index; T value; };
172 
173 void test_move_ctor_basic() {
174   {
175     std::variant<int> v(std::in_place_index<0>, 42);
176     std::variant<int> v2 = std::move(v);
177     assert(v2.index() == 0);
178     assert(std::get<0>(v2) == 42);
179   }
180   {
181     std::variant<int, long> v(std::in_place_index<1>, 42);
182     std::variant<int, long> v2 = std::move(v);
183     assert(v2.index() == 1);
184     assert(std::get<1>(v2) == 42);
185   }
186   {
187     std::variant<MoveOnly> v(std::in_place_index<0>, 42);
188     assert(v.index() == 0);
189     std::variant<MoveOnly> v2(std::move(v));
190     assert(v2.index() == 0);
191     assert(std::get<0>(v2).value == 42);
192   }
193   {
194     std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
195     assert(v.index() == 1);
196     std::variant<int, MoveOnly> v2(std::move(v));
197     assert(v2.index() == 1);
198     assert(std::get<1>(v2).value == 42);
199   }
200   {
201     std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
202     assert(v.index() == 0);
203     std::variant<MoveOnlyNT> v2(std::move(v));
204     assert(v2.index() == 0);
205     assert(std::get<0>(v).value == -1);
206     assert(std::get<0>(v2).value == 42);
207   }
208   {
209     std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
210     assert(v.index() == 1);
211     std::variant<int, MoveOnlyNT> v2(std::move(v));
212     assert(v2.index() == 1);
213     assert(std::get<1>(v).value == -1);
214     assert(std::get<1>(v2).value == 42);
215   }
216 
217   // The following tests are for not-yet-standardized behavior (P0602):
218   {
219     struct {
220       constexpr Result<int> operator()() const {
221         std::variant<int> v(std::in_place_index<0>, 42);
222         std::variant<int> v2 = std::move(v);
223         return {v2.index(), std::get<0>(std::move(v2))};
224       }
225     } test;
226     constexpr auto result = test();
227     static_assert(result.index == 0, "");
228     static_assert(result.value == 42, "");
229   }
230   {
231     struct {
232       constexpr Result<long> operator()() const {
233         std::variant<int, long> v(std::in_place_index<1>, 42);
234         std::variant<int, long> v2 = std::move(v);
235         return {v2.index(), std::get<1>(std::move(v2))};
236       }
237     } test;
238     constexpr auto result = test();
239     static_assert(result.index == 1, "");
240     static_assert(result.value == 42, "");
241   }
242   {
243     struct {
244       constexpr Result<TMove> operator()() const {
245         std::variant<TMove> v(std::in_place_index<0>, 42);
246         std::variant<TMove> v2(std::move(v));
247         return {v2.index(), std::get<0>(std::move(v2))};
248       }
249     } test;
250     constexpr auto result = test();
251     static_assert(result.index == 0, "");
252     static_assert(result.value.value == 42, "");
253   }
254   {
255     struct {
256       constexpr Result<TMove> operator()() const {
257         std::variant<int, TMove> v(std::in_place_index<1>, 42);
258         std::variant<int, TMove> v2(std::move(v));
259         return {v2.index(), std::get<1>(std::move(v2))};
260       }
261     } test;
262     constexpr auto result = test();
263     static_assert(result.index == 1, "");
264     static_assert(result.value.value == 42, "");
265   }
266   {
267     struct {
268       constexpr Result<TMoveNTCopy> operator()() const {
269         std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);
270         std::variant<TMoveNTCopy> v2(std::move(v));
271         return {v2.index(), std::get<0>(std::move(v2))};
272       }
273     } test;
274     constexpr auto result = test();
275     static_assert(result.index == 0, "");
276     static_assert(result.value.value == 42, "");
277   }
278   {
279     struct {
280       constexpr Result<TMoveNTCopy> operator()() const {
281         std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);
282         std::variant<int, TMoveNTCopy> v2(std::move(v));
283         return {v2.index(), std::get<1>(std::move(v2))};
284       }
285     } test;
286     constexpr auto result = test();
287     static_assert(result.index == 1, "");
288     static_assert(result.value.value == 42, "");
289   }
290 }
291 
292 void test_move_ctor_valueless_by_exception() {
293 #ifndef TEST_HAS_NO_EXCEPTIONS
294   using V = std::variant<int, MakeEmptyT>;
295   V v1;
296   makeEmpty(v1);
297   V v(std::move(v1));
298   assert(v.valueless_by_exception());
299 #endif // TEST_HAS_NO_EXCEPTIONS
300 }
301 
302 template <size_t Idx>
303 constexpr bool test_constexpr_ctor_extension_imp(
304     std::variant<long, void*, const int> const& v)
305 {
306   auto copy = v;
307   auto v2 = std::move(copy);
308   return v2.index() == v.index() &&
309          v2.index() == Idx &&
310         std::get<Idx>(v2) == std::get<Idx>(v);
311 }
312 
313 void test_constexpr_move_ctor_extension() {
314   // NOTE: This test is for not yet standardized behavior. (P0602)
315   using V = std::variant<long, void*, const int>;
316 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
317   static_assert(std::is_trivially_destructible<V>::value, "");
318   static_assert(std::is_trivially_copy_constructible<V>::value, "");
319   static_assert(std::is_trivially_move_constructible<V>::value, "");
320   static_assert(!std::is_copy_assignable<V>::value, "");
321   static_assert(!std::is_move_assignable<V>::value, "");
322 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
323   static_assert(std::is_trivially_copyable<V>::value, "");
324 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
325   static_assert(std::is_trivially_move_constructible<V>::value, "");
326   static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), "");
327   static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), "");
328   static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
329 }
330 
331 int main() {
332   test_move_ctor_basic();
333   test_move_ctor_valueless_by_exception();
334   test_move_noexcept();
335   test_move_ctor_sfinae();
336   test_constexpr_move_ctor_extension();
337 }
338