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 // Throwing bad_variant_access is supported starting in macosx10.13
12 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions
13
14 // <variant>
15 // template <class Visitor, class... Variants>
16 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
17
18 #include <cassert>
19 #include <memory>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 #include <variant>
24
25 #include "test_macros.h"
26 #include "variant_test_helpers.h"
27
test_call_operator_forwarding()28 void test_call_operator_forwarding() {
29 using Fn = ForwardingCallObject;
30 Fn obj{};
31 const Fn &cobj = obj;
32 { // test call operator forwarding - no variant
33 std::visit(obj);
34 assert(Fn::check_call<>(CT_NonConst | CT_LValue));
35 std::visit(cobj);
36 assert(Fn::check_call<>(CT_Const | CT_LValue));
37 std::visit(std::move(obj));
38 assert(Fn::check_call<>(CT_NonConst | CT_RValue));
39 std::visit(std::move(cobj));
40 assert(Fn::check_call<>(CT_Const | CT_RValue));
41 }
42 { // test call operator forwarding - single variant, single arg
43 using V = std::variant<int>;
44 V v(42);
45 std::visit(obj, v);
46 assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
47 std::visit(cobj, v);
48 assert(Fn::check_call<int &>(CT_Const | CT_LValue));
49 std::visit(std::move(obj), v);
50 assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
51 std::visit(std::move(cobj), v);
52 assert(Fn::check_call<int &>(CT_Const | CT_RValue));
53 }
54 { // test call operator forwarding - single variant, multi arg
55 using V = std::variant<int, long, double>;
56 V v(42l);
57 std::visit(obj, v);
58 assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
59 std::visit(cobj, v);
60 assert(Fn::check_call<long &>(CT_Const | CT_LValue));
61 std::visit(std::move(obj), v);
62 assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
63 std::visit(std::move(cobj), v);
64 assert(Fn::check_call<long &>(CT_Const | CT_RValue));
65 }
66 { // test call operator forwarding - multi variant, multi arg
67 using V = std::variant<int, long, double>;
68 using V2 = std::variant<int *, std::string>;
69 V v(42l);
70 V2 v2("hello");
71 std::visit(obj, v, v2);
72 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
73 std::visit(cobj, v, v2);
74 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
75 std::visit(std::move(obj), v, v2);
76 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
77 std::visit(std::move(cobj), v, v2);
78 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
79 }
80 {
81 using V = std::variant<int, long, double, std::string>;
82 V v1(42l), v2("hello"), v3(101), v4(1.1);
83 std::visit(obj, v1, v2, v3, v4);
84 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
85 std::visit(cobj, v1, v2, v3, v4);
86 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
87 std::visit(std::move(obj), v1, v2, v3, v4);
88 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
89 std::visit(std::move(cobj), v1, v2, v3, v4);
90 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
91 }
92 {
93 using V = std::variant<int, long, double, int*, std::string>;
94 V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
95 std::visit(obj, v1, v2, v3, v4);
96 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
97 std::visit(cobj, v1, v2, v3, v4);
98 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
99 std::visit(std::move(obj), v1, v2, v3, v4);
100 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
101 std::visit(std::move(cobj), v1, v2, v3, v4);
102 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
103 }
104 }
105
test_argument_forwarding()106 void test_argument_forwarding() {
107 using Fn = ForwardingCallObject;
108 Fn obj{};
109 const auto Val = CT_LValue | CT_NonConst;
110 { // single argument - value type
111 using V = std::variant<int>;
112 V v(42);
113 const V &cv = v;
114 std::visit(obj, v);
115 assert(Fn::check_call<int &>(Val));
116 std::visit(obj, cv);
117 assert(Fn::check_call<const int &>(Val));
118 std::visit(obj, std::move(v));
119 assert(Fn::check_call<int &&>(Val));
120 std::visit(obj, std::move(cv));
121 assert(Fn::check_call<const int &&>(Val));
122 }
123 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
124 { // single argument - lvalue reference
125 using V = std::variant<int &>;
126 int x = 42;
127 V v(x);
128 const V &cv = v;
129 std::visit(obj, v);
130 assert(Fn::check_call<int &>(Val));
131 std::visit(obj, cv);
132 assert(Fn::check_call<int &>(Val));
133 std::visit(obj, std::move(v));
134 assert(Fn::check_call<int &>(Val));
135 std::visit(obj, std::move(cv));
136 assert(Fn::check_call<int &>(Val));
137 }
138 { // single argument - rvalue reference
139 using V = std::variant<int &&>;
140 int x = 42;
141 V v(std::move(x));
142 const V &cv = v;
143 std::visit(obj, v);
144 assert(Fn::check_call<int &>(Val));
145 std::visit(obj, cv);
146 assert(Fn::check_call<int &>(Val));
147 std::visit(obj, std::move(v));
148 assert(Fn::check_call<int &&>(Val));
149 std::visit(obj, std::move(cv));
150 assert(Fn::check_call<int &&>(Val));
151 }
152 #endif
153 { // multi argument - multi variant
154 using V = std::variant<int, std::string, long>;
155 V v1(42), v2("hello"), v3(43l);
156 std::visit(obj, v1, v2, v3);
157 assert((Fn::check_call<int &, std::string &, long &>(Val)));
158 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
159 assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
160 }
161 {
162 using V = std::variant<int, long, double, std::string>;
163 V v1(42l), v2("hello"), v3(101), v4(1.1);
164 std::visit(obj, v1, v2, v3, v4);
165 assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
166 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
167 assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));
168 }
169 {
170 using V = std::variant<int, long, double, int*, std::string>;
171 V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
172 std::visit(obj, v1, v2, v3, v4);
173 assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
174 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
175 assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
176 }
177 }
178
test_return_type()179 void test_return_type() {
180 using Fn = ForwardingCallObject;
181 Fn obj{};
182 const Fn &cobj = obj;
183 { // test call operator forwarding - no variant
184 static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
185 static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
186 static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
187 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
188 }
189 { // test call operator forwarding - single variant, single arg
190 using V = std::variant<int>;
191 V v(42);
192 static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
193 static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
194 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
195 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
196 }
197 { // test call operator forwarding - single variant, multi arg
198 using V = std::variant<int, long, double>;
199 V v(42l);
200 static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
201 static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
202 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
203 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
204 }
205 { // test call operator forwarding - multi variant, multi arg
206 using V = std::variant<int, long, double>;
207 using V2 = std::variant<int *, std::string>;
208 V v(42l);
209 V2 v2("hello");
210 static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
211 static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
212 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
213 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
214 }
215 {
216 using V = std::variant<int, long, double, std::string>;
217 V v1(42l), v2("hello"), v3(101), v4(1.1);
218 static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
219 static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
220 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
221 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
222 }
223 {
224 using V = std::variant<int, long, double, int*, std::string>;
225 V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
226 static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
227 static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
228 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
229 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
230 }
231 }
232
test_constexpr()233 void test_constexpr() {
234 constexpr ReturnFirst obj{};
235 constexpr ReturnArity aobj{};
236 {
237 using V = std::variant<int>;
238 constexpr V v(42);
239 static_assert(std::visit(obj, v) == 42, "");
240 }
241 {
242 using V = std::variant<short, long, char>;
243 constexpr V v(42l);
244 static_assert(std::visit(obj, v) == 42, "");
245 }
246 {
247 using V1 = std::variant<int>;
248 using V2 = std::variant<int, char *, long long>;
249 using V3 = std::variant<bool, int, int>;
250 constexpr V1 v1;
251 constexpr V2 v2(nullptr);
252 constexpr V3 v3;
253 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
254 }
255 {
256 using V1 = std::variant<int>;
257 using V2 = std::variant<int, char *, long long>;
258 using V3 = std::variant<void *, int, int>;
259 constexpr V1 v1;
260 constexpr V2 v2(nullptr);
261 constexpr V3 v3;
262 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
263 }
264 {
265 using V = std::variant<int, long, double, int *>;
266 constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
267 static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
268 }
269 {
270 using V = std::variant<int, long, double, long long, int *>;
271 constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
272 static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
273 }
274 }
275
test_exceptions()276 void test_exceptions() {
277 #ifndef TEST_HAS_NO_EXCEPTIONS
278 ReturnArity obj{};
279 auto test = [&](auto &&... args) {
280 try {
281 std::visit(obj, args...);
282 } catch (const std::bad_variant_access &) {
283 return true;
284 } catch (...) {
285 }
286 return false;
287 };
288 {
289 using V = std::variant<int, MakeEmptyT>;
290 V v;
291 makeEmpty(v);
292 assert(test(v));
293 }
294 {
295 using V = std::variant<int, MakeEmptyT>;
296 using V2 = std::variant<long, std::string, void *>;
297 V v;
298 makeEmpty(v);
299 V2 v2("hello");
300 assert(test(v, v2));
301 }
302 {
303 using V = std::variant<int, MakeEmptyT>;
304 using V2 = std::variant<long, std::string, void *>;
305 V v;
306 makeEmpty(v);
307 V2 v2("hello");
308 assert(test(v2, v));
309 }
310 {
311 using V = std::variant<int, MakeEmptyT>;
312 using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
313 V v;
314 makeEmpty(v);
315 V2 v2;
316 makeEmpty(v2);
317 assert(test(v, v2));
318 }
319 {
320 using V = std::variant<int, long, double, MakeEmptyT>;
321 V v1(42l), v2(101), v3(202), v4(1.1);
322 makeEmpty(v1);
323 assert(test(v1, v2, v3, v4));
324 }
325 {
326 using V = std::variant<int, long, double, long long, MakeEmptyT>;
327 V v1(42l), v2(101), v3(202), v4(1.1);
328 makeEmpty(v1);
329 makeEmpty(v2);
330 makeEmpty(v3);
331 makeEmpty(v4);
332 assert(test(v1, v2, v3, v4));
333 }
334 #endif
335 }
336
337 // See https://llvm.org/PR31916
test_caller_accepts_nonconst()338 void test_caller_accepts_nonconst() {
339 struct A {};
340 struct Visitor {
341 void operator()(A&) {}
342 };
343 std::variant<A> v;
344 std::visit(Visitor{}, v);
345 }
346
347 struct MyVariant : std::variant<short, long, float> {};
348
349 namespace std {
350 template <size_t Index>
get(const MyVariant &)351 void get(const MyVariant&) {
352 assert(false);
353 }
354 } // namespace std
355
test_derived_from_variant()356 void test_derived_from_variant() {
357 auto v1 = MyVariant{42};
358 const auto cv1 = MyVariant{142};
359 std::visit([](auto x) { assert(x == 42); }, v1);
360 std::visit([](auto x) { assert(x == 142); }, cv1);
361 std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
362 std::visit([](auto x) { assert(x == 42); }, std::move(v1));
363 std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
364
365 // Check that visit does not take index nor valueless_by_exception members from the base class.
366 struct EvilVariantBase {
367 int index;
368 char valueless_by_exception;
369 };
370
371 struct EvilVariant1 : std::variant<int, long, double>,
372 std::tuple<int>,
373 EvilVariantBase {
374 using std::variant<int, long, double>::variant;
375 };
376
377 std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
378 std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
379
380 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
381 struct ImplVariantBase {
382 struct Callable {
383 bool operator()() const { assert(false); return false; }
384 };
385
386 Callable __impl;
387 };
388
389 struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {
390 using std::variant<int, long, double>::variant;
391 };
392
393 std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
394 std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
395 }
396
397 struct any_visitor {
398 template <typename T>
operator ()any_visitor399 void operator()(const T&) const {}
400 };
401
402 template <typename T, typename = decltype(std::visit(
403 std::declval<any_visitor&>(), std::declval<T>()))>
has_visit(int)404 constexpr bool has_visit(int) {
405 return true;
406 }
407
408 template <typename T>
has_visit(...)409 constexpr bool has_visit(...) {
410 return false;
411 }
412
test_sfinae()413 void test_sfinae() {
414 struct BadVariant : std::variant<short>, std::variant<long, float> {};
415 struct BadVariant2 : private std::variant<long, float> {};
416 struct GoodVariant : std::variant<long, float> {};
417 struct GoodVariant2 : GoodVariant {};
418
419 static_assert(!has_visit<int>(0));
420 static_assert(!has_visit<BadVariant>(0));
421 static_assert(!has_visit<BadVariant2>(0));
422 static_assert(has_visit<std::variant<int>>(0));
423 static_assert(has_visit<GoodVariant>(0));
424 static_assert(has_visit<GoodVariant2>(0));
425 }
426
main(int,char **)427 int main(int, char**) {
428 test_call_operator_forwarding();
429 test_argument_forwarding();
430 test_return_type();
431 test_constexpr();
432 test_exceptions();
433 test_caller_accepts_nonconst();
434 test_derived_from_variant();
435 test_sfinae();
436
437 return 0;
438 }
439