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