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