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 const&);
26 
27 #include <cassert>
28 #include <type_traits>
29 #include <variant>
30 
31 #include "test_macros.h"
32 #include "test_workarounds.h"
33 
34 struct NonT {
35   NonT(int v) : value(v) {}
36   NonT(const NonT &o) : value(o.value) {}
37   int value;
38 };
39 static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
40 
41 struct NoCopy {
42   NoCopy(const NoCopy &) = delete;
43 };
44 
45 struct MoveOnly {
46   MoveOnly(const MoveOnly &) = delete;
47   MoveOnly(MoveOnly &&) = default;
48 };
49 
50 struct MoveOnlyNT {
51   MoveOnlyNT(const MoveOnlyNT &) = delete;
52   MoveOnlyNT(MoveOnlyNT &&) {}
53 };
54 
55 struct NTCopy {
56   constexpr NTCopy(int v) : value(v) {}
57   NTCopy(const NTCopy &that) : value(that.value) {}
58   NTCopy(NTCopy &&) = delete;
59   int value;
60 };
61 
62 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
63 static_assert(std::is_copy_constructible<NTCopy>::value, "");
64 
65 struct TCopy {
66   constexpr TCopy(int v) : value(v) {}
67   TCopy(TCopy const &) = default;
68   TCopy(TCopy &&) = delete;
69   int value;
70 };
71 
72 static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
73 
74 struct TCopyNTMove {
75   constexpr TCopyNTMove(int v) : value(v) {}
76   TCopyNTMove(const TCopyNTMove&) = default;
77   TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
78   int value;
79 };
80 
81 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
82 
83 #ifndef TEST_HAS_NO_EXCEPTIONS
84 struct MakeEmptyT {
85   static int alive;
86   MakeEmptyT() { ++alive; }
87   MakeEmptyT(const MakeEmptyT &) {
88     ++alive;
89     // Don't throw from the copy constructor since variant's assignment
90     // operator performs a copy before committing to the assignment.
91   }
92   MakeEmptyT(MakeEmptyT &&) { throw 42; }
93   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
94   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
95   ~MakeEmptyT() { --alive; }
96 };
97 
98 int MakeEmptyT::alive = 0;
99 
100 template <class Variant> void makeEmpty(Variant &v) {
101   Variant v2(std::in_place_type<MakeEmptyT>);
102   try {
103     v = std::move(v2);
104     assert(false);
105   } catch (...) {
106     assert(v.valueless_by_exception());
107   }
108 }
109 #endif // TEST_HAS_NO_EXCEPTIONS
110 
111 void test_copy_ctor_sfinae() {
112   {
113     using V = std::variant<int, long>;
114     static_assert(std::is_copy_constructible<V>::value, "");
115   }
116   {
117     using V = std::variant<int, NoCopy>;
118     static_assert(!std::is_copy_constructible<V>::value, "");
119   }
120   {
121     using V = std::variant<int, MoveOnly>;
122     static_assert(!std::is_copy_constructible<V>::value, "");
123   }
124   {
125     using V = std::variant<int, MoveOnlyNT>;
126     static_assert(!std::is_copy_constructible<V>::value, "");
127   }
128 
129   // The following tests are for not-yet-standardized behavior (P0602):
130   {
131     using V = std::variant<int, long>;
132     static_assert(std::is_trivially_copy_constructible<V>::value, "");
133   }
134   {
135     using V = std::variant<int, NTCopy>;
136     static_assert(!std::is_trivially_copy_constructible<V>::value, "");
137     static_assert(std::is_copy_constructible<V>::value, "");
138   }
139   {
140     using V = std::variant<int, TCopy>;
141     static_assert(std::is_trivially_copy_constructible<V>::value, "");
142   }
143   {
144     using V = std::variant<int, TCopyNTMove>;
145     static_assert(std::is_trivially_copy_constructible<V>::value, "");
146   }
147 }
148 
149 void test_copy_ctor_basic() {
150   {
151     std::variant<int> v(std::in_place_index<0>, 42);
152     std::variant<int> v2 = v;
153     assert(v2.index() == 0);
154     assert(std::get<0>(v2) == 42);
155   }
156   {
157     std::variant<int, long> v(std::in_place_index<1>, 42);
158     std::variant<int, long> v2 = v;
159     assert(v2.index() == 1);
160     assert(std::get<1>(v2) == 42);
161   }
162   {
163     std::variant<NonT> v(std::in_place_index<0>, 42);
164     assert(v.index() == 0);
165     std::variant<NonT> v2(v);
166     assert(v2.index() == 0);
167     assert(std::get<0>(v2).value == 42);
168   }
169   {
170     std::variant<int, NonT> v(std::in_place_index<1>, 42);
171     assert(v.index() == 1);
172     std::variant<int, NonT> v2(v);
173     assert(v2.index() == 1);
174     assert(std::get<1>(v2).value == 42);
175   }
176 
177   // The following tests are for not-yet-standardized behavior (P0602):
178   {
179     constexpr std::variant<int> v(std::in_place_index<0>, 42);
180     static_assert(v.index() == 0, "");
181     constexpr std::variant<int> v2 = v;
182     static_assert(v2.index() == 0, "");
183     static_assert(std::get<0>(v2) == 42, "");
184   }
185   {
186     constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
187     static_assert(v.index() == 1, "");
188     constexpr std::variant<int, long> v2 = v;
189     static_assert(v2.index() == 1, "");
190     static_assert(std::get<1>(v2) == 42, "");
191   }
192   {
193     constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
194     static_assert(v.index() == 0, "");
195     constexpr std::variant<TCopy> v2(v);
196     static_assert(v2.index() == 0, "");
197     static_assert(std::get<0>(v2).value == 42, "");
198   }
199   {
200     constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
201     static_assert(v.index() == 1, "");
202     constexpr std::variant<int, TCopy> v2(v);
203     static_assert(v2.index() == 1, "");
204     static_assert(std::get<1>(v2).value == 42, "");
205   }
206   {
207     constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
208     static_assert(v.index() == 0, "");
209     constexpr std::variant<TCopyNTMove> v2(v);
210     static_assert(v2.index() == 0, "");
211     static_assert(std::get<0>(v2).value == 42, "");
212   }
213   {
214     constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
215     static_assert(v.index() == 1, "");
216     constexpr std::variant<int, TCopyNTMove> v2(v);
217     static_assert(v2.index() == 1, "");
218     static_assert(std::get<1>(v2).value == 42, "");
219   }
220 }
221 
222 void test_copy_ctor_valueless_by_exception() {
223 #ifndef TEST_HAS_NO_EXCEPTIONS
224   using V = std::variant<int, MakeEmptyT>;
225   V v1;
226   makeEmpty(v1);
227   const V &cv1 = v1;
228   V v(cv1);
229   assert(v.valueless_by_exception());
230 #endif // TEST_HAS_NO_EXCEPTIONS
231 }
232 
233 template <size_t Idx>
234 constexpr bool test_constexpr_copy_ctor_extension_imp(
235     std::variant<long, void*, const int> const& v)
236 {
237   auto v2 = v;
238   return v2.index() == v.index() &&
239          v2.index() == Idx &&
240          std::get<Idx>(v2) == std::get<Idx>(v);
241 }
242 
243 void test_constexpr_copy_ctor_extension() {
244   // NOTE: This test is for not yet standardized behavior. (P0602)
245   using V = std::variant<long, void*, const int>;
246 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
247   static_assert(std::is_trivially_destructible<V>::value, "");
248   static_assert(std::is_trivially_copy_constructible<V>::value, "");
249   static_assert(std::is_trivially_move_constructible<V>::value, "");
250   static_assert(!std::is_copy_assignable<V>::value, "");
251   static_assert(!std::is_move_assignable<V>::value, "");
252 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
253   static_assert(std::is_trivially_copyable<V>::value, "");
254 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
255   static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), "");
256   static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), "");
257   static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), "");
258 }
259 
260 int main() {
261   test_copy_ctor_basic();
262   test_copy_ctor_valueless_by_exception();
263   test_copy_ctor_sfinae();
264   test_constexpr_copy_ctor_extension();
265 #if 0
266 // disable this for the moment; it fails on older compilers.
267 //  Need to figure out which compilers will support it.
268 { // This is the motivating example from P0739R0
269   std::variant<int, double> v1(3);
270   std::variant v2 = v1;
271   (void) v2;
272 }
273 #endif
274 }
275