[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / libcxx / test / std / utilities / variant / variant.visit.member / visit.pass.cpp
blob68706d6c32af4ff10cf8fc356992146d0a18cf82
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, c++17, c++20, c++23
10 // The tested functionality needs deducing this.
11 // UNSUPPORTED: clang-16 || clang-17
12 // XFAIL: apple-clang
14 // <variant>
16 // class variant;
18 // template<class Self, class Visitor>
19 // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
21 #include <cassert>
22 #include <memory>
23 #include <string>
24 #include <type_traits>
25 #include <utility>
26 #include <variant>
28 #include "test_macros.h"
29 #include "variant_test_helpers.h"
31 void test_call_operator_forwarding() {
32 using Fn = ForwardingCallObject;
33 Fn obj{};
34 const Fn& cobj = obj;
36 { // test call operator forwarding - single variant, single arg
37 using V = std::variant<int>;
38 V v(42);
40 v.visit(obj);
41 assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
42 v.visit(cobj);
43 assert(Fn::check_call<int&>(CT_Const | CT_LValue));
44 v.visit(std::move(obj));
45 assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
46 v.visit(std::move(cobj));
47 assert(Fn::check_call<int&>(CT_Const | CT_RValue));
49 { // test call operator forwarding - single variant, multi arg
50 using V = std::variant<int, long, double>;
51 V v(42L);
53 v.visit(obj);
54 assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
55 v.visit(cobj);
56 assert(Fn::check_call<long&>(CT_Const | CT_LValue));
57 v.visit(std::move(obj));
58 assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
59 v.visit(std::move(cobj));
60 assert(Fn::check_call<long&>(CT_Const | CT_RValue));
64 // Applies to non-member `std::visit` only.
65 void test_argument_forwarding() {
66 using Fn = ForwardingCallObject;
67 Fn obj{};
68 const auto val = CT_LValue | CT_NonConst;
70 { // single argument - value type
71 using V = std::variant<int>;
72 V v(42);
73 const V& cv = v;
75 v.visit(obj);
76 assert(Fn::check_call<int&>(val));
77 cv.visit(obj);
78 assert(Fn::check_call<const int&>(val));
79 std::move(v).visit(obj);
80 assert(Fn::check_call<int&&>(val));
81 std::move(cv).visit(obj);
82 assert(Fn::check_call<const int&&>(val));
84 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
85 { // single argument - lvalue reference
86 using V = std::variant<int&>;
87 int x = 42;
88 V v(x);
89 const V& cv = v;
91 v.visit(obj);
92 assert(Fn::check_call<int&>(val));
93 cv.visit(obj);
94 assert(Fn::check_call<int&>(val));
95 std::move(v).visit(obj);
96 assert(Fn::check_call<int&>(val));
97 std::move(cv).visit(obj);
98 assert(Fn::check_call<int&>(val));
99 assert(false);
101 { // single argument - rvalue reference
102 using V = std::variant<int&&>;
103 int x = 42;
104 V v(std::move(x));
105 const V& cv = v;
107 v.visit(obj);
108 assert(Fn::check_call<int&>(val));
109 cvstd::visit(obj);
110 assert(Fn::check_call<int&>(val));
111 std::move(v).visit(obj);
112 assert(Fn::check_call<int&&>(val));
113 std::move(cv).visit(obj);
114 assert(Fn::check_call<int&&>(val));
116 #endif
119 void test_return_type() {
120 using Fn = ForwardingCallObject;
121 Fn obj{};
122 const Fn& cobj = obj;
124 { // test call operator forwarding - single variant, single arg
125 using V = std::variant<int>;
126 V v(42);
128 static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
129 static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
130 static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
131 static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
133 { // test call operator forwarding - single variant, multi arg
134 using V = std::variant<int, long, double>;
135 V v(42L);
137 static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
138 static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
139 static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
140 static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
144 void test_constexpr() {
145 constexpr ReturnFirst obj{};
148 using V = std::variant<int>;
149 constexpr V v(42);
151 static_assert(v.visit(obj) == 42);
154 using V = std::variant<short, long, char>;
155 constexpr V v(42L);
157 static_assert(v.visit(obj) == 42);
161 void test_exceptions() {
162 #ifndef TEST_HAS_NO_EXCEPTIONS
163 ReturnArity obj{};
165 auto test = [&](auto&& v) {
166 try {
167 v.visit(obj);
168 } catch (const std::bad_variant_access&) {
169 return true;
170 } catch (...) {
172 return false;
176 using V = std::variant<int, MakeEmptyT>;
177 V v;
178 makeEmpty(v);
180 assert(test(v));
182 #endif
185 // See https://llvm.org/PR31916
186 void test_caller_accepts_nonconst() {
187 struct A {};
188 struct Visitor {
189 void operator()(A&) {}
191 std::variant<A> v;
193 v.visit(Visitor{});
196 struct MyVariant : std::variant<short, long, float> {};
198 namespace std {
199 template <std::size_t Index>
200 void get(const MyVariant&) {
201 assert(false);
203 } // namespace std
205 void test_derived_from_variant() {
206 auto v1 = MyVariant{42};
207 const auto cv1 = MyVariant{142};
209 v1.visit([](auto x) { assert(x == 42); });
210 cv1.visit([](auto x) { assert(x == 142); });
211 MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
212 std::move(v1).visit([](auto x) { assert(x == 42); });
213 std::move(cv1).visit([](auto x) { assert(x == 142); });
215 // Check that visit does not take index nor valueless_by_exception members from the base class.
216 struct EvilVariantBase {
217 int index;
218 char valueless_by_exception;
221 struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
222 using std::variant<int, long, double>::variant;
225 EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
226 EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
228 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
229 struct ImplVariantBase {
230 struct Callable {
231 bool operator()() const {
232 assert(false);
233 return false;
237 Callable __impl;
240 struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {
241 using std::variant<int, long, double>::variant;
244 EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
245 EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
248 int main(int, char**) {
249 test_call_operator_forwarding();
250 test_argument_forwarding();
251 test_return_type();
252 test_constexpr();
253 test_exceptions();
254 test_caller_accepts_nonconst();
255 test_derived_from_variant();
257 return 0;