]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/20_util/variant/exception_safety.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / 20_util / variant / exception_safety.cc
1 // Copyright (C) 2019-2021 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
17
18 // { dg-options "-std=gnu++17" }
19 // { dg-do run { target c++17 } }
20
21 #include <variant>
22 #include <vector>
23 #include <string>
24 #include <memory_resource>
25 #include <memory>
26 #include <functional>
27 #include <any>
28 #include <optional>
29 #include <testsuite_hooks.h>
30
31 void
32 test01()
33 {
34 #if _GLIBCXX_USE_CXX11_ABI
35 std::variant<int, std::pmr::string, std::pmr::vector<int>> v(1);
36 VERIFY( v.index() == 0 );
37
38 try
39 {
40 std::pmr::string s = "how long is a piece of SSO string?";
41 v.emplace<1>(s, std::pmr::null_memory_resource());
42 VERIFY( false );
43 }
44 catch(const std::bad_alloc&)
45 {
46 VERIFY( v.valueless_by_exception() );
47 }
48
49 v.emplace<0>(2);
50 VERIFY( v.index() == 0 );
51
52 try
53 {
54 v.emplace<2>({1, 2, 3}, std::pmr::null_memory_resource());
55 VERIFY( false );
56 }
57 catch(const std::bad_alloc&)
58 {
59 VERIFY( v.valueless_by_exception() );
60 }
61 #endif
62 }
63
64 void
65 test02()
66 {
67 struct X
68 {
69 X(int i) : i(1) { if (i > 2) throw 3; }
70 X(std::initializer_list<int> l) : i(2) { if (l.size() > 2) throw 3; }
71 int i;
72 };
73 static_assert( std::is_trivially_copyable_v<X> );
74
75 std::variant<std::monostate, int, X> v(111);
76 VERIFY( v.index() == 1 );
77
78 try
79 {
80 v.emplace<X>(3);
81 VERIFY( false );
82 }
83 catch(int)
84 {
85 VERIFY( !v.valueless_by_exception() );
86 VERIFY( v.index() == 1 );
87 VERIFY( std::get<int>(v) == 111 );
88 }
89
90 v.emplace<X>(1);
91 VERIFY( v.index() == 2 );
92 VERIFY( std::get<X>(v).i == 1 );
93
94 try
95 {
96 v.emplace<X>(3);
97 VERIFY( false );
98 }
99 catch(int)
100 {
101 VERIFY( !v.valueless_by_exception() );
102 VERIFY( v.index() == 2 );
103 VERIFY( std::get<X>(v).i == 1 );
104 }
105
106 try
107 {
108 v.emplace<X>({1, 2, 3});
109 VERIFY( false );
110 }
111 catch(int)
112 {
113 VERIFY( !v.valueless_by_exception() );
114 VERIFY( v.index() == 2 );
115 VERIFY( std::get<X>(v).i == 1 );
116 }
117 }
118
119 template<typename T, typename V>
120 bool bad_emplace(V& v)
121 {
122 struct X {
123 operator T() const { throw 1; }
124 };
125
126 const auto index = v.index();
127
128 try
129 {
130 if (std::is_same_v<T, std::any>)
131 {
132 // Need to test std::any differently, because emplace<std::any>(X{})
133 // would create a std::any with a contained X, instead of using
134 // X::operator any() to convert to std::any.
135 struct ThrowOnCopy {
136 ThrowOnCopy() { }
137 ThrowOnCopy(const ThrowOnCopy&) { throw 1; }
138 } t;
139 v.template emplace<std::any>(t);
140 }
141 else
142 v.template emplace<T>(X{});
143 }
144 catch (int)
145 {
146 return v.index() == index;
147 }
148 return false;
149 }
150
151 void
152 test03()
153 {
154 struct TriviallyCopyable { int i = 0; };
155
156 std::variant<std::monostate, int, TriviallyCopyable, std::optional<int>,
157 std::string, std::vector<int>, std::function<void()>, std::any,
158 std::shared_ptr<int>, std::weak_ptr<int>, std::unique_ptr<int>> v(1);
159 VERIFY( v.index() == 1 );
160
161 VERIFY( bad_emplace<int>(v) );
162 VERIFY( bad_emplace<TriviallyCopyable>(v) );
163 VERIFY( bad_emplace<std::optional<int>>(v) );
164 VERIFY( bad_emplace<std::string>(v) );
165 VERIFY( bad_emplace<std::vector<int>>(v) );
166 VERIFY( bad_emplace<std::function<void()>>(v) );
167 VERIFY( bad_emplace<std::any>(v) );
168 VERIFY( bad_emplace<std::shared_ptr<int>>(v) );
169 VERIFY( bad_emplace<std::weak_ptr<int>>(v) );
170 VERIFY( bad_emplace<std::unique_ptr<int>>(v) );
171 }
172
173 void
174 test04()
175 {
176 // LWG 2904. Make variant move-assignment more exception safe
177
178 struct ThrowOnCopy
179 {
180 ThrowOnCopy() { }
181 ThrowOnCopy(const ThrowOnCopy&) { throw 1; }
182 ThrowOnCopy& operator=(const ThrowOnCopy&) { throw "shouldn't happen"; }
183 ThrowOnCopy(ThrowOnCopy&&) noexcept { }
184 };
185
186 std::variant<int, ThrowOnCopy> v1(std::in_place_type<ThrowOnCopy>), v2(2);
187 try
188 {
189 v2 = v1; // uses variant<Types...>::operator=(const variant&)
190 VERIFY( false );
191 }
192 catch (int)
193 {
194 VERIFY( !v2.valueless_by_exception() );
195 VERIFY( v2.index() == 0 );
196 VERIFY( std::get<0>(v2) == 2 );
197 }
198
199 try
200 {
201 ThrowOnCopy toc;
202 v2 = toc; // uses variant<Types...>::operator=(T&&)
203 VERIFY( false );
204 }
205 catch (int)
206 {
207 VERIFY( !v2.valueless_by_exception() );
208 VERIFY( v2.index() == 0 );
209 VERIFY( std::get<0>(v2) == 2 );
210 }
211 }
212
213 int
214 main()
215 {
216 test01();
217 test02();
218 test03();
219 test04();
220 }