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