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