]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/20_util/variant/run.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / 20_util / variant / run.cc
1 // { dg-options "-std=gnu++17" }
2 // { dg-do run { target c++17 } }
3
4 // Copyright (C) 2016-2021 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 <ext/throw_allocator.h>
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 // P0608R3
108 variant<string, bool> x = "abc";
109 VERIFY(x.index() == 0);
110 }
111
112 {
113 // P0608R3
114 struct U {
115 U(char16_t c) : c(c) { }
116 char16_t c;
117 };
118 variant<char, U> x = u'\u2043';
119 VERIFY(x.index() == 1);
120 VERIFY(std::get<1>(x).c == u'\u2043');
121
122 struct Double {
123 Double(double& d) : d(d) { }
124 double& d;
125 };
126 double d = 3.14;
127 variant<int, Double> y = d;
128 VERIFY(y.index() == 1);
129 VERIFY(std::get<1>(y).d == d);
130 }
131
132 {
133 // P0608R3
134 variant<float, int> v1 = 'a';
135 VERIFY(std::get<1>(v1) == int('a'));
136 variant<float, long> v2 = 0;
137 VERIFY(std::get<1>(v2) == 0L);
138 struct big_int { big_int(int) { } };
139 variant<float, big_int> v3 = 0;
140 VERIFY(v3.index() == 1);
141 }
142
143 {
144 // P1957R2 Converting from T* to bool should be considered narrowing
145 struct ConvertibleToBool
146 {
147 operator bool() const { return true; }
148 };
149 variant<bool> v1 = ConvertibleToBool();
150 VERIFY(std::get<0>(v1) == true);
151 variant<bool, int> v2 = ConvertibleToBool();
152 VERIFY(std::get<0>(v2) == true);
153 variant<int, bool> v3 = ConvertibleToBool();
154 VERIFY(std::get<1>(v3) == true);
155 }
156 }
157
158 struct ThrowingMoveCtorThrowsCopyCtor
159 {
160 ThrowingMoveCtorThrowsCopyCtor() noexcept = default;
161 ThrowingMoveCtorThrowsCopyCtor(ThrowingMoveCtorThrowsCopyCtor&&) {}
162 ThrowingMoveCtorThrowsCopyCtor(ThrowingMoveCtorThrowsCopyCtor const&)
163 {
164 throw 0;
165 }
166
167 ThrowingMoveCtorThrowsCopyCtor& operator=(ThrowingMoveCtorThrowsCopyCtor&&) noexcept
168 = default;
169 ThrowingMoveCtorThrowsCopyCtor& operator=(ThrowingMoveCtorThrowsCopyCtor const&) noexcept
170 = default;
171 };
172
173 void copy_assign()
174 {
175 variant<monostate, string> v("a");
176 VERIFY(holds_alternative<string>(v));
177 variant<monostate, string> u;
178 u = v;
179 VERIFY(holds_alternative<string>(u));
180 VERIFY(get<string>(u) == "a");
181 {
182 std::variant<int, ThrowingMoveCtorThrowsCopyCtor> v1,
183 v2 = ThrowingMoveCtorThrowsCopyCtor();
184 bool should_throw = false;
185 try
186 {
187 v1 = v2;
188 }
189 catch(int)
190 {
191 should_throw = true;
192 }
193 VERIFY(should_throw);
194 }
195 }
196
197 void move_assign()
198 {
199 variant<monostate, string> v("a");
200 VERIFY(holds_alternative<string>(v));
201 variant<monostate, string> u;
202 u = std::move(v);
203 VERIFY(holds_alternative<string>(u));
204 VERIFY(get<string>(u) == "a");
205 VERIFY(holds_alternative<string>(v));
206
207 variant<vector<int>, DeletedMoves> d{std::in_place_index<0>, {1, 2, 3, 4}};
208 variant<vector<int>, DeletedMoves> e;
209 // DeletedMoves is not move assignable, so this uses copy assignment:
210 e = std::move(d);
211 VERIFY(std::get<0>(d).size() == 4);
212 VERIFY(std::get<0>(e).size() == 4);
213 }
214
215 void arbitrary_assign()
216 {
217 variant<int, string> v;
218 v = "a";
219
220 VERIFY(holds_alternative<string>(variant<int, string>("a")));
221 VERIFY(get<1>(v) == "a");
222
223 {
224 // P0608R3
225 using T1 = variant<float, int>;
226 T1 v1;
227 v1 = 0;
228 VERIFY(v1.index() == 1);
229
230 using T2 = variant<float, long>;
231 T2 v2;
232 v2 = 0;
233 VERIFY(v2.index() == 1);
234
235 struct big_int {
236 big_int(int) { }
237 };
238 using T3 = variant<float, big_int>;
239 T3 v3;
240 v3 = 0;
241 VERIFY(v3.index() == 1);
242 }
243
244 {
245 // P1957R2 Converting from T* to bool should be considered narrowing
246 struct ConvertibleToBool
247 {
248 operator bool() const { return true; }
249 };
250 variant<bool> v1;
251 v1 = ConvertibleToBool();
252 VERIFY(std::get<0>(v1) == true);
253 variant<bool, int> v2;
254 v2 = ConvertibleToBool();
255 VERIFY(std::get<0>(v2) == true);
256 variant<int, bool> v3;
257 v3 = ConvertibleToBool();
258 VERIFY(std::get<1>(v3) == true);
259 }
260 }
261
262 void dtor()
263 {
264 struct A {
265 A(int& called) : called(called) {}
266 ~A() {
267 called++;
268 }
269 int& called;
270 };
271 {
272 int called = 0;
273 { variant<string, A> a(in_place_index<1>, called); }
274 VERIFY(called == 1);
275 }
276 {
277 int called = 0;
278 { variant<string, A> a(in_place_index<0>); }
279 VERIFY(called == 0);
280 }
281 }
282
283 void in_place_index_ctor()
284 {
285 {
286 variant<int, string> v(in_place_index<1>, "a");
287 VERIFY(holds_alternative<string>(v));
288 VERIFY(get<1>(v) == "a");
289 }
290 {
291 variant<int, string> v(in_place_index<1>, {'a', 'b'});
292 VERIFY(holds_alternative<string>(v));
293 VERIFY(get<1>(v) == "ab");
294 }
295 }
296
297 void in_place_type_ctor()
298 {
299 {
300 variant<int, string> v(in_place_type<string>, "a");
301 VERIFY(holds_alternative<string>(v));
302 VERIFY(get<1>(v) == "a");
303 }
304 {
305 variant<int, string> v(in_place_type<string>, {'a', 'b'});
306 VERIFY(holds_alternative<string>(v));
307 VERIFY(get<1>(v) == "ab");
308 }
309 }
310
311 void emplace()
312 {
313 variant<int, string> v;
314 v.emplace<0>(1);
315 VERIFY(get<0>(v) == 1);
316 v.emplace<string>("a");
317 VERIFY(get<string>(v) == "a");
318 v.emplace<1>({'a', 'b'});
319 VERIFY(get<1>(v) == "ab");
320 v.emplace<string>({'a', 'c'});
321 VERIFY(get<string>(v) == "ac");
322 {
323 variant<int, AlwaysThrow> v;
324 AlwaysThrow a;
325 try { v.emplace<1>(a); } catch (nullptr_t) { }
326 VERIFY(v.valueless_by_exception());
327 v.emplace<0>(42);
328 VERIFY(!v.valueless_by_exception());
329 }
330 {
331 variant<int, AlwaysThrow> v;
332 try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { }
333 VERIFY(v.valueless_by_exception());
334 v.emplace<0>(42);
335 VERIFY(!v.valueless_by_exception());
336 }
337 VERIFY(&v.emplace<0>(1) == &std::get<0>(v));
338 VERIFY(&v.emplace<int>(1) == &std::get<int>(v));
339 VERIFY(&v.emplace<1>("a") == &std::get<1>(v));
340 VERIFY(&v.emplace<string>("a") == &std::get<string>(v));
341 {
342 variant<vector<int>> v;
343 VERIFY(&v.emplace<0>({1,2,3}) == &std::get<0>(v));
344 VERIFY(&v.emplace<vector<int>>({1,2,3}) == &std::get<vector<int>>(v));
345 }
346
347 {
348 // Ensure no copies of the vector are made, only moves.
349 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c21
350
351 // static_assert(__detail::__variant::_Never_valueless_alt<vector<AlwaysThrow>>::value);
352 variant<int, DeletedMoves, vector<AlwaysThrow>> v;
353 v.emplace<2>(1);
354 v.emplace<vector<AlwaysThrow>>(1);
355 v.emplace<0>(0);
356
357 // To test the emplace(initializer_list<U>, Args&&...) members we
358 // can't use AlwaysThrow because elements in an initialier_list
359 // are always copied. Use throw_allocator instead.
360 using Vector = vector<int, __gnu_cxx::throw_allocator_limit<int>>;
361 // static_assert(__detail::__variant::_Never_valueless_alt<Vector>::value);
362 variant<int, DeletedMoves, Vector> vv;
363 Vector::allocator_type::set_limit(1);
364 vv.emplace<2>(1, 1);
365 Vector::allocator_type::set_limit(1);
366 vv.emplace<Vector>(1, 1);
367 Vector::allocator_type::set_limit(1);
368 vv.emplace<0>(0);
369 Vector::allocator_type::set_limit(1);
370 vv.emplace<2>({1, 2, 3});
371 Vector::allocator_type::set_limit(1);
372 vv.emplace<Vector>({1, 2, 3, 4});
373 try {
374 Vector::allocator_type::set_limit(0);
375 vv.emplace<2>(1, 1);
376 VERIFY(false);
377 } catch (const __gnu_cxx::forced_error&) {
378 }
379 VERIFY(vv.valueless_by_exception());
380 }
381 }
382
383 void test_get()
384 {
385 VERIFY(get<1>(variant<int, string>("a")) == "a");
386 VERIFY(get<string>(variant<int, string>("a")) == "a");
387 {
388 bool caught = false;
389
390 try
391 {
392 get<0>(variant<int, string>("a"));
393 }
394 catch (const bad_variant_access&)
395 {
396 caught = true;
397 }
398 VERIFY(caught);
399 }
400 {
401 bool caught = false;
402
403 try
404 {
405 get<int>(variant<int, string>("a"));
406 }
407 catch (const bad_variant_access&)
408 {
409 caught = true;
410 }
411 VERIFY(caught);
412 }
413 }
414
415 void test_relational()
416 {
417 VERIFY((variant<int, string>(2) < variant<int, string>(3)));
418 VERIFY((variant<int, string>(3) == variant<int, string>(3)));
419 VERIFY((variant<int, string>(3) > variant<int, string>(2)));
420 VERIFY((variant<int, string>(3) <= variant<int, string>(3)));
421 VERIFY((variant<int, string>(2) <= variant<int, string>(3)));
422 VERIFY((variant<int, string>(3) >= variant<int, string>(3)));
423 VERIFY((variant<int, string>(3) >= variant<int, string>(2)));
424 VERIFY((variant<int, string>(2) != variant<int, string>(3)));
425
426 VERIFY((variant<int, string>(2) < variant<int, string>("a")));
427 VERIFY((variant<string, int>(2) > variant<string, int>("a")));
428
429 {
430 variant<int, AlwaysThrow> v, w;
431 try
432 {
433 AlwaysThrow a;
434 v = a;
435 }
436 catch (nullptr_t) { }
437 VERIFY(v.valueless_by_exception());
438 VERIFY(v < w);
439 VERIFY(v <= w);
440 VERIFY(!(v == w));
441 VERIFY(v == v);
442 VERIFY(v != w);
443 VERIFY(w > v);
444 VERIFY(w >= v);
445 }
446 }
447
448 void test_swap()
449 {
450 variant<int, string> a("a"), b("b");
451 a.swap(b);
452 VERIFY(get<1>(a) == "b");
453 VERIFY(get<1>(b) == "a");
454 swap(a, b);
455 VERIFY(get<1>(a) == "a");
456 VERIFY(get<1>(b) == "b");
457 }
458
459 void test_visit()
460 {
461 {
462 struct Visitor
463 {
464 int operator()(int, float) {
465 return 0;
466 }
467 int operator()(int, double) {
468 return 1;
469 }
470 int operator()(char, float) {
471 return 2;
472 }
473 int operator()(char, double) {
474 return 3;
475 }
476 int operator()(int, float) const {
477 return 5;
478 }
479 int operator()(int, double) const {
480 return 6;
481 }
482 int operator()(char, float) const {
483 return 7;
484 }
485 int operator()(char, double) const {
486 return 8;
487 }
488 } visitor1;
489 VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
490 VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0)) == 1);
491 VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
492 VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
493
494 const auto& visitor2 = visitor1;
495 VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0f)) == 5);
496 VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0)) == 6);
497 VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0f)) == 7);
498 VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0)) == 8);
499 }
500
501 {
502 struct Visitor
503 {
504 int operator()(int, float) && {
505 return 0;
506 }
507 int operator()(int, double) && {
508 return 1;
509 }
510 int operator()(char, float) && {
511 return 2;
512 }
513 int operator()(char, double) && {
514 return 3;
515 }
516 };
517 VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
518 VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0)) == 1);
519 VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
520 VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
521 }
522 }
523
524 struct Hashable
525 {
526 Hashable(const char* s) : s(s) { }
527 // Non-trivial special member functions:
528 Hashable(const Hashable&) { }
529 Hashable(Hashable&&) noexcept { }
530 ~Hashable() { }
531
532 string s;
533
534 bool operator==(const Hashable& rhs) const noexcept
535 { return s == rhs.s; }
536 };
537
538 namespace std {
539 template<> struct hash<Hashable> {
540 size_t operator()(const Hashable& h) const noexcept
541 { return hash<std::string>()(h.s); }
542 };
543 }
544
545 void test_hash()
546 {
547 unordered_set<variant<int, Hashable>> s;
548 VERIFY(s.emplace(3).second);
549 VERIFY(s.emplace("asdf").second);
550 VERIFY(s.emplace().second);
551 VERIFY(s.size() == 3);
552 VERIFY(!s.emplace(3).second);
553 VERIFY(!s.emplace("asdf").second);
554 VERIFY(!s.emplace().second);
555 VERIFY(s.size() == 3);
556 {
557 struct A
558 {
559 operator Hashable()
560 {
561 throw nullptr;
562 }
563 };
564 variant<int, Hashable> v;
565 try
566 {
567 v.emplace<1>(A{});
568 }
569 catch (nullptr_t)
570 {
571 }
572 VERIFY(v.valueless_by_exception());
573 VERIFY(s.insert(v).second);
574 VERIFY(s.size() == 4);
575 VERIFY(!s.insert(v).second);
576 }
577 }
578
579 void test_valueless_by_exception()
580 {
581 {
582 AlwaysThrow a;
583 bool caught = false;
584 try
585 {
586 variant<int, AlwaysThrow> v(a);
587 }
588 catch (nullptr_t)
589 {
590 caught = true;
591 }
592 VERIFY(caught);
593 }
594 {
595 AlwaysThrow a;
596 bool caught = false;
597 try
598 {
599 variant<int, AlwaysThrow> v(a);
600 }
601 catch (nullptr_t)
602 {
603 caught = true;
604 }
605 VERIFY(caught);
606 }
607 {
608 variant<int, AlwaysThrow> v;
609 bool caught = false;
610 try
611 {
612 AlwaysThrow a;
613 v = a;
614 }
615 catch (nullptr_t)
616 {
617 caught = true;
618 }
619 VERIFY(caught);
620 VERIFY(v.valueless_by_exception());
621 }
622 {
623 variant<int, AlwaysThrow> v;
624 bool caught = false;
625 try
626 {
627 v = AlwaysThrow{};
628 }
629 catch (nullptr_t)
630 {
631 caught = true;
632 }
633 VERIFY(caught);
634 VERIFY(v.valueless_by_exception());
635 }
636 }
637
638 int main()
639 {
640 default_ctor();
641 copy_ctor();
642 move_ctor();
643 arbitrary_ctor();
644 in_place_index_ctor();
645 in_place_type_ctor();
646 copy_assign();
647 move_assign();
648 arbitrary_assign();
649 dtor();
650 emplace();
651 test_get();
652 test_relational();
653 test_swap();
654 test_visit();
655 test_hash();
656 test_valueless_by_exception();
657 }