]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/20_util/variant/run.cc
Fix condition for std::variant to be copy constructible
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / 20_util / variant / run.cc
1 // { dg-options "-std=gnu++17" }
2 // { dg-do run }
3
4 // Copyright (C) 2016-2019 Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING3. If not see
19 // <http://www.gnu.org/licenses/>.
20
21 #include <variant>
22 #include <string>
23 #include <vector>
24 #include <unordered_set>
25 #include <memory_resource>
26 #include <testsuite_hooks.h>
27
28 using namespace std;
29
30 struct AlwaysThrow
31 {
32 AlwaysThrow() = default;
33
34 AlwaysThrow(const AlwaysThrow&)
35 { throw nullptr; }
36
37 AlwaysThrow(AlwaysThrow&&)
38 { throw nullptr; }
39
40 AlwaysThrow& operator=(const AlwaysThrow&)
41 {
42 throw nullptr;
43 return *this;
44 }
45
46 AlwaysThrow& operator=(AlwaysThrow&&)
47 {
48 throw nullptr;
49 return *this;
50 }
51
52 bool operator<(const AlwaysThrow&) const { VERIFY(false); }
53 bool operator<=(const AlwaysThrow&) const { VERIFY(false); }
54 bool operator==(const AlwaysThrow&) const { VERIFY(false); }
55 bool operator!=(const AlwaysThrow&) const { VERIFY(false); }
56 bool operator>=(const AlwaysThrow&) const { VERIFY(false); }
57 bool operator>(const AlwaysThrow&) const { VERIFY(false); }
58 };
59
60 struct DeletedMoves
61 {
62 DeletedMoves() = default;
63 DeletedMoves(const DeletedMoves&) = default;
64 DeletedMoves(DeletedMoves&&) = delete;
65 DeletedMoves& operator=(const DeletedMoves&) = default;
66 DeletedMoves& operator=(DeletedMoves&&) = delete;
67 };
68
69 void default_ctor()
70 {
71 variant<monostate, string> v;
72 VERIFY(holds_alternative<monostate>(v));
73 }
74
75 void copy_ctor()
76 {
77 variant<monostate, string> v("a");
78 VERIFY(holds_alternative<string>(v));
79 variant<monostate, string> u(v);
80 VERIFY(holds_alternative<string>(u));
81 VERIFY(get<string>(u) == "a");
82 }
83
84 void move_ctor()
85 {
86 variant<monostate, string> v("a");
87 VERIFY(holds_alternative<string>(v));
88 variant<monostate, string> u(std::move(v));
89 VERIFY(holds_alternative<string>(u));
90 VERIFY(get<string>(u) == "a");
91 VERIFY(holds_alternative<string>(v));
92
93 variant<vector<int>, DeletedMoves> d{std::in_place_index<0>, {1, 2, 3, 4}};
94 // DeletedMoves is not move constructible, so this uses copy ctor:
95 variant<vector<int>, DeletedMoves> e(std::move(d));
96 VERIFY(std::get<0>(d).size() == 4);
97 VERIFY(std::get<0>(e).size() == 4);
98 }
99
100 void arbitrary_ctor()
101 {
102 variant<int, string> v("a");
103 VERIFY(holds_alternative<string>(v));
104 VERIFY(get<1>(v) == "a");
105 }
106
107 struct ThrowingMoveCtorThrowsCopyCtor
108 {
109 ThrowingMoveCtorThrowsCopyCtor() noexcept = default;
110 ThrowingMoveCtorThrowsCopyCtor(ThrowingMoveCtorThrowsCopyCtor&&) {}
111 ThrowingMoveCtorThrowsCopyCtor(ThrowingMoveCtorThrowsCopyCtor const&)
112 {
113 throw 0;
114 }
115
116 ThrowingMoveCtorThrowsCopyCtor& operator=(ThrowingMoveCtorThrowsCopyCtor&&) noexcept
117 = default;
118 ThrowingMoveCtorThrowsCopyCtor& operator=(ThrowingMoveCtorThrowsCopyCtor const&) noexcept
119 = default;
120 };
121
122 void copy_assign()
123 {
124 variant<monostate, string> v("a");
125 VERIFY(holds_alternative<string>(v));
126 variant<monostate, string> u;
127 u = v;
128 VERIFY(holds_alternative<string>(u));
129 VERIFY(get<string>(u) == "a");
130 {
131 std::variant<int, ThrowingMoveCtorThrowsCopyCtor> v1,
132 v2 = ThrowingMoveCtorThrowsCopyCtor();
133 bool should_throw = false;
134 try
135 {
136 v1 = v2;
137 }
138 catch(int)
139 {
140 should_throw = true;
141 }
142 VERIFY(should_throw);
143 }
144 }
145
146 void move_assign()
147 {
148 variant<monostate, string> v("a");
149 VERIFY(holds_alternative<string>(v));
150 variant<monostate, string> u;
151 u = std::move(v);
152 VERIFY(holds_alternative<string>(u));
153 VERIFY(get<string>(u) == "a");
154 VERIFY(holds_alternative<string>(v));
155
156 variant<vector<int>, DeletedMoves> d{std::in_place_index<0>, {1, 2, 3, 4}};
157 variant<vector<int>, DeletedMoves> e;
158 // DeletedMoves is not move assignable, so this uses copy assignment:
159 e = std::move(d);
160 VERIFY(std::get<0>(d).size() == 4);
161 VERIFY(std::get<0>(e).size() == 4);
162 }
163
164 void arbitrary_assign()
165 {
166 variant<int, string> v;
167 v = "a";
168
169 VERIFY(holds_alternative<string>(variant<int, string>("a")));
170 VERIFY(get<1>(v) == "a");
171 }
172
173 void dtor()
174 {
175 struct A {
176 A(int& called) : called(called) {}
177 ~A() {
178 called++;
179 }
180 int& called;
181 };
182 {
183 int called = 0;
184 { variant<string, A> a(in_place_index<1>, called); }
185 VERIFY(called == 1);
186 }
187 {
188 int called = 0;
189 { variant<string, A> a(in_place_index<0>); }
190 VERIFY(called == 0);
191 }
192 }
193
194 void in_place_index_ctor()
195 {
196 {
197 variant<int, string> v(in_place_index<1>, "a");
198 VERIFY(holds_alternative<string>(v));
199 VERIFY(get<1>(v) == "a");
200 }
201 {
202 variant<int, string> v(in_place_index<1>, {'a', 'b'});
203 VERIFY(holds_alternative<string>(v));
204 VERIFY(get<1>(v) == "ab");
205 }
206 }
207
208 void in_place_type_ctor()
209 {
210 {
211 variant<int, string> v(in_place_type<string>, "a");
212 VERIFY(holds_alternative<string>(v));
213 VERIFY(get<1>(v) == "a");
214 }
215 {
216 variant<int, string> v(in_place_type<string>, {'a', 'b'});
217 VERIFY(holds_alternative<string>(v));
218 VERIFY(get<1>(v) == "ab");
219 }
220 }
221
222 void emplace()
223 {
224 variant<int, string> v;
225 v.emplace<0>(1);
226 VERIFY(get<0>(v) == 1);
227 v.emplace<string>("a");
228 VERIFY(get<string>(v) == "a");
229 v.emplace<1>({'a', 'b'});
230 VERIFY(get<1>(v) == "ab");
231 v.emplace<string>({'a', 'c'});
232 VERIFY(get<string>(v) == "ac");
233 {
234 variant<int, AlwaysThrow> v;
235 AlwaysThrow a;
236 try { v.emplace<1>(a); } catch (nullptr_t) { }
237 VERIFY(v.valueless_by_exception());
238 v.emplace<0>(42);
239 VERIFY(!v.valueless_by_exception());
240 }
241 {
242 variant<int, AlwaysThrow> v;
243 try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { }
244 VERIFY(v.valueless_by_exception());
245 v.emplace<0>(42);
246 VERIFY(!v.valueless_by_exception());
247 }
248 VERIFY(&v.emplace<0>(1) == &std::get<0>(v));
249 VERIFY(&v.emplace<int>(1) == &std::get<int>(v));
250 VERIFY(&v.emplace<1>("a") == &std::get<1>(v));
251 VERIFY(&v.emplace<string>("a") == &std::get<string>(v));
252 {
253 variant<vector<int>> v;
254 VERIFY(&v.emplace<0>({1,2,3}) == &std::get<0>(v));
255 VERIFY(&v.emplace<vector<int>>({1,2,3}) == &std::get<vector<int>>(v));
256 }
257 }
258
259 void test_get()
260 {
261 VERIFY(get<1>(variant<int, string>("a")) == "a");
262 VERIFY(get<string>(variant<int, string>("a")) == "a");
263 {
264 bool caught = false;
265
266 try
267 {
268 get<0>(variant<int, string>("a"));
269 }
270 catch (const bad_variant_access&)
271 {
272 caught = true;
273 }
274 VERIFY(caught);
275 }
276 {
277 bool caught = false;
278
279 try
280 {
281 get<int>(variant<int, string>("a"));
282 }
283 catch (const bad_variant_access&)
284 {
285 caught = true;
286 }
287 VERIFY(caught);
288 }
289 }
290
291 void test_relational()
292 {
293 VERIFY((variant<int, string>(2) < variant<int, string>(3)));
294 VERIFY((variant<int, string>(3) == variant<int, string>(3)));
295 VERIFY((variant<int, string>(3) > variant<int, string>(2)));
296 VERIFY((variant<int, string>(3) <= variant<int, string>(3)));
297 VERIFY((variant<int, string>(2) <= variant<int, string>(3)));
298 VERIFY((variant<int, string>(3) >= variant<int, string>(3)));
299 VERIFY((variant<int, string>(3) >= variant<int, string>(2)));
300 VERIFY((variant<int, string>(2) != variant<int, string>(3)));
301
302 VERIFY((variant<int, string>(2) < variant<int, string>("a")));
303 VERIFY((variant<string, int>(2) > variant<string, int>("a")));
304
305 {
306 variant<int, AlwaysThrow> v, w;
307 try
308 {
309 AlwaysThrow a;
310 v = a;
311 }
312 catch (nullptr_t) { }
313 VERIFY(v.valueless_by_exception());
314 VERIFY(v < w);
315 VERIFY(v <= w);
316 VERIFY(!(v == w));
317 VERIFY(v == v);
318 VERIFY(v != w);
319 VERIFY(w > v);
320 VERIFY(w >= v);
321 }
322 }
323
324 void test_swap()
325 {
326 variant<int, string> a("a"), b("b");
327 a.swap(b);
328 VERIFY(get<1>(a) == "b");
329 VERIFY(get<1>(b) == "a");
330 swap(a, b);
331 VERIFY(get<1>(a) == "a");
332 VERIFY(get<1>(b) == "b");
333 }
334
335 void test_visit()
336 {
337 {
338 struct Visitor
339 {
340 int operator()(int, float) {
341 return 0;
342 }
343 int operator()(int, double) {
344 return 1;
345 }
346 int operator()(char, float) {
347 return 2;
348 }
349 int operator()(char, double) {
350 return 3;
351 }
352 int operator()(int, float) const {
353 return 5;
354 }
355 int operator()(int, double) const {
356 return 6;
357 }
358 int operator()(char, float) const {
359 return 7;
360 }
361 int operator()(char, double) const {
362 return 8;
363 }
364 } visitor1;
365 VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
366 VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0)) == 1);
367 VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
368 VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
369
370 const auto& visitor2 = visitor1;
371 VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0f)) == 5);
372 VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0)) == 6);
373 VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0f)) == 7);
374 VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0)) == 8);
375 }
376
377 {
378 struct Visitor
379 {
380 int operator()(int, float) && {
381 return 0;
382 }
383 int operator()(int, double) && {
384 return 1;
385 }
386 int operator()(char, float) && {
387 return 2;
388 }
389 int operator()(char, double) && {
390 return 3;
391 }
392 };
393 VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
394 VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0)) == 1);
395 VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
396 VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
397 }
398 }
399
400 void test_hash()
401 {
402 unordered_set<variant<int, pmr::string>> s;
403 VERIFY(s.emplace(3).second);
404 VERIFY(s.emplace("asdf").second);
405 VERIFY(s.emplace().second);
406 VERIFY(s.size() == 3);
407 VERIFY(!s.emplace(3).second);
408 VERIFY(!s.emplace("asdf").second);
409 VERIFY(!s.emplace().second);
410 VERIFY(s.size() == 3);
411 {
412 struct A
413 {
414 operator pmr::string()
415 {
416 throw nullptr;
417 }
418 };
419 variant<int, pmr::string> v;
420 try
421 {
422 v.emplace<1>(A{});
423 }
424 catch (nullptr_t)
425 {
426 }
427 VERIFY(v.valueless_by_exception());
428 VERIFY(s.insert(v).second);
429 VERIFY(s.size() == 4);
430 VERIFY(!s.insert(v).second);
431 }
432 }
433
434 void test_valueless_by_exception()
435 {
436 {
437 AlwaysThrow a;
438 bool caught = false;
439 try
440 {
441 variant<int, AlwaysThrow> v(a);
442 }
443 catch (nullptr_t)
444 {
445 caught = true;
446 }
447 VERIFY(caught);
448 }
449 {
450 AlwaysThrow a;
451 bool caught = false;
452 try
453 {
454 variant<int, AlwaysThrow> v(a);
455 }
456 catch (nullptr_t)
457 {
458 caught = true;
459 }
460 VERIFY(caught);
461 }
462 {
463 variant<int, AlwaysThrow> v;
464 bool caught = false;
465 try
466 {
467 AlwaysThrow a;
468 v = a;
469 }
470 catch (nullptr_t)
471 {
472 caught = true;
473 }
474 VERIFY(caught);
475 VERIFY(v.valueless_by_exception());
476 }
477 {
478 variant<int, AlwaysThrow> v;
479 bool caught = false;
480 try
481 {
482 v = AlwaysThrow{};
483 }
484 catch (nullptr_t)
485 {
486 caught = true;
487 }
488 VERIFY(caught);
489 VERIFY(v.valueless_by_exception());
490 }
491 }
492
493 int main()
494 {
495 default_ctor();
496 copy_ctor();
497 move_ctor();
498 arbitrary_ctor();
499 in_place_index_ctor();
500 in_place_type_ctor();
501 copy_assign();
502 move_assign();
503 arbitrary_assign();
504 dtor();
505 emplace();
506 test_get();
507 test_relational();
508 test_swap();
509 test_visit();
510 test_hash();
511 test_valueless_by_exception();
512 }