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 // <variant>
12
13 // template <class ...Types> class variant;
14
15 // constexpr variant(variant const&);
16
17 #include <cassert>
18 #include <type_traits>
19 #include <variant>
20
21 #include "test_macros.h"
22 #include "test_workarounds.h"
23
24 struct NonT {
NonTNonT25 constexpr NonT(int v) : value(v) {}
NonTNonT26 constexpr NonT(const NonT& o) : value(o.value) {}
27 int value;
28 };
29 static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
30
31 struct NoCopy {
32 NoCopy(const NoCopy&) = delete;
33 };
34
35 struct MoveOnly {
36 MoveOnly(const MoveOnly&) = delete;
37 MoveOnly(MoveOnly&&) = default;
38 };
39
40 struct MoveOnlyNT {
41 MoveOnlyNT(const MoveOnlyNT&) = delete;
MoveOnlyNTMoveOnlyNT42 MoveOnlyNT(MoveOnlyNT&&) {}
43 };
44
45 struct NTCopy {
NTCopyNTCopy46 constexpr NTCopy(int v) : value(v) {}
NTCopyNTCopy47 NTCopy(const NTCopy& that) : value(that.value) {}
48 NTCopy(NTCopy&&) = delete;
49 int value;
50 };
51
52 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
53 static_assert(std::is_copy_constructible<NTCopy>::value, "");
54
55 struct TCopy {
TCopyTCopy56 constexpr TCopy(int v) : value(v) {}
57 TCopy(TCopy const&) = default;
58 TCopy(TCopy&&) = delete;
59 int value;
60 };
61
62 static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
63
64 struct TCopyNTMove {
TCopyNTMoveTCopyNTMove65 constexpr TCopyNTMove(int v) : value(v) {}
66 TCopyNTMove(const TCopyNTMove&) = default;
TCopyNTMoveTCopyNTMove67 TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
68 int value;
69 };
70
71 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
72
73 #ifndef TEST_HAS_NO_EXCEPTIONS
74 struct MakeEmptyT {
75 static int alive;
MakeEmptyTMakeEmptyT76 MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT77 MakeEmptyT(const MakeEmptyT&) {
78 ++alive;
79 // Don't throw from the copy constructor since variant's assignment
80 // operator performs a copy before committing to the assignment.
81 }
MakeEmptyTMakeEmptyT82 MakeEmptyT(MakeEmptyT&&) { throw 42; }
operator =MakeEmptyT83 MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
operator =MakeEmptyT84 MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyTMakeEmptyT85 ~MakeEmptyT() { --alive; }
86 };
87
88 int MakeEmptyT::alive = 0;
89
90 template <class Variant>
makeEmpty(Variant & v)91 void makeEmpty(Variant& v) {
92 Variant v2(std::in_place_type<MakeEmptyT>);
93 try {
94 v = std::move(v2);
95 assert(false);
96 } catch (...) {
97 assert(v.valueless_by_exception());
98 }
99 }
100 #endif // TEST_HAS_NO_EXCEPTIONS
101
test_copy_ctor_sfinae()102 constexpr void test_copy_ctor_sfinae() {
103 {
104 using V = std::variant<int, long>;
105 static_assert(std::is_copy_constructible<V>::value, "");
106 }
107 {
108 using V = std::variant<int, NoCopy>;
109 static_assert(!std::is_copy_constructible<V>::value, "");
110 }
111 {
112 using V = std::variant<int, MoveOnly>;
113 static_assert(!std::is_copy_constructible<V>::value, "");
114 }
115 {
116 using V = std::variant<int, MoveOnlyNT>;
117 static_assert(!std::is_copy_constructible<V>::value, "");
118 }
119
120 // Make sure we properly propagate triviality (see P0602R4).
121 {
122 using V = std::variant<int, long>;
123 static_assert(std::is_trivially_copy_constructible<V>::value, "");
124 }
125 {
126 using V = std::variant<int, NTCopy>;
127 static_assert(!std::is_trivially_copy_constructible<V>::value, "");
128 static_assert(std::is_copy_constructible<V>::value, "");
129 }
130 {
131 using V = std::variant<int, TCopy>;
132 static_assert(std::is_trivially_copy_constructible<V>::value, "");
133 }
134 {
135 using V = std::variant<int, TCopyNTMove>;
136 static_assert(std::is_trivially_copy_constructible<V>::value, "");
137 }
138 }
139
test_copy_ctor_basic()140 TEST_CONSTEXPR_CXX20 void test_copy_ctor_basic() {
141 {
142 std::variant<int> v(std::in_place_index<0>, 42);
143 std::variant<int> v2 = v;
144 assert(v2.index() == 0);
145 assert(std::get<0>(v2) == 42);
146 }
147 {
148 std::variant<int, long> v(std::in_place_index<1>, 42);
149 std::variant<int, long> v2 = v;
150 assert(v2.index() == 1);
151 assert(std::get<1>(v2) == 42);
152 }
153 {
154 std::variant<NonT> v(std::in_place_index<0>, 42);
155 assert(v.index() == 0);
156 std::variant<NonT> v2(v);
157 assert(v2.index() == 0);
158 assert(std::get<0>(v2).value == 42);
159 }
160 {
161 std::variant<int, NonT> v(std::in_place_index<1>, 42);
162 assert(v.index() == 1);
163 std::variant<int, NonT> v2(v);
164 assert(v2.index() == 1);
165 assert(std::get<1>(v2).value == 42);
166 }
167
168 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
169 {
170 constexpr std::variant<int> v(std::in_place_index<0>, 42);
171 static_assert(v.index() == 0, "");
172 constexpr std::variant<int> v2 = v;
173 static_assert(v2.index() == 0, "");
174 static_assert(std::get<0>(v2) == 42, "");
175 }
176 {
177 constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
178 static_assert(v.index() == 1, "");
179 constexpr std::variant<int, long> v2 = v;
180 static_assert(v2.index() == 1, "");
181 static_assert(std::get<1>(v2) == 42, "");
182 }
183 {
184 constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
185 static_assert(v.index() == 0, "");
186 constexpr std::variant<TCopy> v2(v);
187 static_assert(v2.index() == 0, "");
188 static_assert(std::get<0>(v2).value == 42, "");
189 }
190 {
191 constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
192 static_assert(v.index() == 1, "");
193 constexpr std::variant<int, TCopy> v2(v);
194 static_assert(v2.index() == 1, "");
195 static_assert(std::get<1>(v2).value == 42, "");
196 }
197 {
198 constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
199 static_assert(v.index() == 0, "");
200 constexpr std::variant<TCopyNTMove> v2(v);
201 static_assert(v2.index() == 0, "");
202 static_assert(std::get<0>(v2).value == 42, "");
203 }
204 {
205 constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
206 static_assert(v.index() == 1, "");
207 constexpr std::variant<int, TCopyNTMove> v2(v);
208 static_assert(v2.index() == 1, "");
209 static_assert(std::get<1>(v2).value == 42, "");
210 }
211 }
212
test_copy_ctor_valueless_by_exception()213 void test_copy_ctor_valueless_by_exception() {
214 #ifndef TEST_HAS_NO_EXCEPTIONS
215 using V = std::variant<int, MakeEmptyT>;
216 V v1;
217 makeEmpty(v1);
218 const V& cv1 = v1;
219 V v(cv1);
220 assert(v.valueless_by_exception());
221 #endif // TEST_HAS_NO_EXCEPTIONS
222 }
223
224 template <std::size_t Idx, class T>
test_constexpr_copy_ctor_imp(const T & v)225 constexpr void test_constexpr_copy_ctor_imp(const T& v) {
226 auto v2 = v;
227 assert(v2.index() == v.index());
228 assert(v2.index() == Idx);
229 assert(std::get<Idx>(v2) == std::get<Idx>(v));
230 }
231
test_constexpr_copy_ctor_trivial()232 constexpr void test_constexpr_copy_ctor_trivial() {
233 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
234 using V = std::variant<long, void*, const int>;
235 #ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
236 static_assert(std::is_trivially_destructible<V>::value, "");
237 static_assert(std::is_trivially_copy_constructible<V>::value, "");
238 static_assert(std::is_trivially_move_constructible<V>::value, "");
239 static_assert(!std::is_copy_assignable<V>::value, "");
240 static_assert(!std::is_move_assignable<V>::value, "");
241 #else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
242 static_assert(std::is_trivially_copyable<V>::value, "");
243 #endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
244 static_assert(std::is_trivially_copy_constructible<V>::value, "");
245 test_constexpr_copy_ctor_imp<0>(V(42l));
246 test_constexpr_copy_ctor_imp<1>(V(nullptr));
247 test_constexpr_copy_ctor_imp<2>(V(101));
248 }
249
250 struct NonTrivialCopyCtor {
251 int i = 0;
NonTrivialCopyCtorNonTrivialCopyCtor252 constexpr NonTrivialCopyCtor(int ii) : i(ii) {}
NonTrivialCopyCtorNonTrivialCopyCtor253 constexpr NonTrivialCopyCtor(const NonTrivialCopyCtor& other) : i(other.i) {}
254 constexpr NonTrivialCopyCtor(NonTrivialCopyCtor&& other) = default;
255 TEST_CONSTEXPR_CXX20 ~NonTrivialCopyCtor() = default;
operator ==(const NonTrivialCopyCtor & x,const NonTrivialCopyCtor & y)256 friend constexpr bool operator==(const NonTrivialCopyCtor& x, const NonTrivialCopyCtor& y) { return x.i == y.i; }
257 };
258
test_constexpr_copy_ctor_non_trivial()259 TEST_CONSTEXPR_CXX20 void test_constexpr_copy_ctor_non_trivial() {
260 // Test !is_trivially_move_constructible
261 using V = std::variant<long, NonTrivialCopyCtor, void*>;
262 static_assert(!std::is_trivially_copy_constructible<V>::value, "");
263 test_constexpr_copy_ctor_imp<0>(V(42l));
264 test_constexpr_copy_ctor_imp<1>(V(NonTrivialCopyCtor(5)));
265 test_constexpr_copy_ctor_imp<2>(V(nullptr));
266 }
267
non_constexpr_test()268 void non_constexpr_test() { test_copy_ctor_valueless_by_exception(); }
269
cxx17_constexpr_test()270 constexpr bool cxx17_constexpr_test() {
271 test_copy_ctor_sfinae();
272 test_constexpr_copy_ctor_trivial();
273
274 return true;
275 }
276
cxx20_constexpr_test()277 TEST_CONSTEXPR_CXX20 bool cxx20_constexpr_test() {
278 test_copy_ctor_basic();
279 test_constexpr_copy_ctor_non_trivial();
280
281 return true;
282 }
283
main(int,char **)284 int main(int, char**) {
285 non_constexpr_test();
286 cxx17_constexpr_test();
287 cxx20_constexpr_test();
288
289 static_assert(cxx17_constexpr_test());
290 #if TEST_STD_VER >= 20
291 static_assert(cxx20_constexpr_test());
292 #endif
293 return 0;
294 }
295