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