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// template <class T>
16// variant& operator=(T&&) noexcept(see below);
17
18#include <cassert>
19#include <string>
20#include <type_traits>
21#include <variant>
22#include <vector>
23#include <memory>
24
25#include "test_macros.h"
26#include "variant_test_helpers.h"
27
28namespace MetaHelpers {
29
30struct Dummy {
31 Dummy() = default;
32};
33
34struct ThrowsCtorT {
35 ThrowsCtorT(int) noexcept(false) {}
36 ThrowsCtorT &operator=(int) noexcept { return *this; }
37};
38
39struct ThrowsAssignT {
40 ThrowsAssignT(int) noexcept {}
41 ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
42};
43
44struct NoThrowT {
45 NoThrowT(int) noexcept {}
46 NoThrowT &operator=(int) noexcept { return *this; }
47};
48
49} // namespace MetaHelpers
50
51namespace RuntimeHelpers {
52#ifndef TEST_HAS_NO_EXCEPTIONS
53
54struct ThrowsCtorT {
55 int value;
56 ThrowsCtorT() : value(0) {}
57 ThrowsCtorT(int) noexcept(false) { throw 42; }
58 ThrowsCtorT &operator=(int v) noexcept {
59 value = v;
60 return *this;
61 }
62};
63
64struct MoveCrashes {
65 int value;
66 MoveCrashes(int v = 0) noexcept : value{v} {}
67 MoveCrashes(MoveCrashes &&) noexcept { assert(false); }
68 MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; }
69 MoveCrashes &operator=(int v) noexcept {
70 value = v;
71 return *this;
72 }
73};
74
75struct ThrowsCtorTandMove {
76 int value;
77 ThrowsCtorTandMove() : value(0) {}
78 ThrowsCtorTandMove(int) noexcept(false) { throw 42; }
79 ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); }
80 ThrowsCtorTandMove &operator=(int v) noexcept {
81 value = v;
82 return *this;
83 }
84};
85
86struct ThrowsAssignT {
87 int value;
88 ThrowsAssignT() : value(0) {}
89 ThrowsAssignT(int v) noexcept : value(v) {}
90 ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
91};
92
93struct NoThrowT {
94 int value;
95 NoThrowT() : value(0) {}
96 NoThrowT(int v) noexcept : value(v) {}
97 NoThrowT &operator=(int v) noexcept {
98 value = v;
99 return *this;
100 }
101};
102
103#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
104} // namespace RuntimeHelpers
105
106void test_T_assignment_noexcept() {
107 using namespace MetaHelpers;
108 {
109 using V = std::variant<Dummy, NoThrowT>;
110 static_assert(std::is_nothrow_assignable<V, int>::value, "");
111 }
112 {
113 using V = std::variant<Dummy, ThrowsCtorT>;
114 static_assert(!std::is_nothrow_assignable<V, int>::value, "");
115 }
116 {
117 using V = std::variant<Dummy, ThrowsAssignT>;
118 static_assert(!std::is_nothrow_assignable<V, int>::value, "");
119 }
120}
121
122void test_T_assignment_sfinae() {
123 {
124 using V = std::variant<long, long long>;
125 static_assert(!std::is_assignable<V, int>::value, "ambiguous");
126 }
127 {
128 using V = std::variant<std::string, std::string>;
129 static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
130 }
131 {
132 using V = std::variant<std::string, void *>;
133 static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
134 }
135 {
136 using V = std::variant<std::string, float>;
137 static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
138 }
139 {
140 using V = std::variant<std::unique_ptr<int>, bool>;
141 static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value,
142 "no explicit bool in operator=");
143 struct X {
144 operator void*();
145 };
146 static_assert(!std::is_assignable<V, X>::value, "no boolean conversion in operator=");
147 static_assert(std::is_assignable<V, std::false_type>::value, "converted to bool in operator=");
148 }
149 {
150 struct X {};
151 struct Y {
152 operator X();
153 };
154 using V = std::variant<X>;
155 static_assert(std::is_assignable<V, Y>::value,
156 "regression on user-defined conversions in operator=");
157 }
158}
159
160void test_T_assignment_basic() {
161 {
162 std::variant<int> v(43);
163 v = 42;
164 assert(v.index() == 0);
165 assert(std::get<0>(v) == 42);
166 }
167 {
168 std::variant<int, long> v(43l);
169 v = 42;
170 assert(v.index() == 0);
171 assert(std::get<0>(v) == 42);
172 v = 43l;
173 assert(v.index() == 1);
174 assert(std::get<1>(v) == 43);
175 }
176 {
177 std::variant<unsigned, long> v;
178 v = 42;
179 assert(v.index() == 1);
180 assert(std::get<1>(v) == 42);
181 v = 43u;
182 assert(v.index() == 0);
183 assert(std::get<0>(v) == 43);
184 }
185 {
186 std::variant<std::string, bool> v = true;
187 v = "bar";
188 assert(v.index() == 0);
189 assert(std::get<0>(v) == "bar");
190 }
191 {
192 std::variant<bool, std::unique_ptr<int>> v;
193 v = nullptr;
194 assert(v.index() == 1);
195 assert(std::get<1>(v) == nullptr);
196 }
197}
198
199void test_T_assignment_performs_construction() {
200 using namespace RuntimeHelpers;
201#ifndef TEST_HAS_NO_EXCEPTIONS
202 {
203 using V = std::variant<std::string, ThrowsCtorT>;
204 V v(std::in_place_type<std::string>, "hello");
205 try {
206 v = 42;
207 assert(false);
208 } catch (...) { /* ... */
209 }
210 assert(v.index() == 0);
211 assert(std::get<0>(v) == "hello");
212 }
213 {
214 using V = std::variant<ThrowsAssignT, std::string>;
215 V v(std::in_place_type<std::string>, "hello");
216 v = 42;
217 assert(v.index() == 0);
218 assert(std::get<0>(v).value == 42);
219 }
220#endif // TEST_HAS_NO_EXCEPTIONS
221}
222
223void test_T_assignment_performs_assignment() {
224 using namespace RuntimeHelpers;
225#ifndef TEST_HAS_NO_EXCEPTIONS
226 {
227 using V = std::variant<ThrowsCtorT>;
228 V v;
229 v = 42;
230 assert(v.index() == 0);
231 assert(std::get<0>(v).value == 42);
232 }
233 {
234 using V = std::variant<ThrowsCtorT, std::string>;
235 V v;
236 v = 42;
237 assert(v.index() == 0);
238 assert(std::get<0>(v).value == 42);
239 }
240 {
241 using V = std::variant<ThrowsAssignT>;
242 V v(100);
243 try {
244 v = 42;
245 assert(false);
246 } catch (...) { /* ... */
247 }
248 assert(v.index() == 0);
249 assert(std::get<0>(v).value == 100);
250 }
251 {
252 using V = std::variant<std::string, ThrowsAssignT>;
253 V v(100);
254 try {
255 v = 42;
256 assert(false);
257 } catch (...) { /* ... */
258 }
259 assert(v.index() == 1);
260 assert(std::get<1>(v).value == 100);
261 }
262#endif // TEST_HAS_NO_EXCEPTIONS
263}
264
265void test_T_assignment_vector_bool() {
266 std::vector<bool> vec = {true};
267 std::variant<bool, int> v;
268 v = vec[0];
269 assert(v.index() == 0);
270 assert(std::get<0>(v) == true);
271}
272
273int main(int, char**) {
274 test_T_assignment_basic();
275 test_T_assignment_performs_construction();
276 test_T_assignment_performs_assignment();
277 test_T_assignment_noexcept();
278 test_T_assignment_sfinae();
279 test_T_assignment_vector_bool();
280
281 return 0;
282}
283

source code of libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp