1 //===----------------------------------------------------------------------===//
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
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-17
18 // template<class Self, class Visitor>
19 // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
25 #include <type_traits>
29 #include "test_macros.h"
30 #include "variant_test_helpers.h"
32 void test_call_operator_forwarding() {
33 using Fn
= ForwardingCallObject
;
37 { // test call operator forwarding - single variant, single arg
38 using V
= std::variant
<int>;
42 assert(Fn::check_call
<int&>(CT_NonConst
| CT_LValue
));
44 assert(Fn::check_call
<int&>(CT_Const
| CT_LValue
));
45 v
.visit(std::move(obj
));
46 assert(Fn::check_call
<int&>(CT_NonConst
| CT_RValue
));
47 v
.visit(std::move(cobj
));
48 assert(Fn::check_call
<int&>(CT_Const
| CT_RValue
));
50 { // test call operator forwarding - single variant, multi arg
51 using V
= std::variant
<int, long, double>;
55 assert(Fn::check_call
<long&>(CT_NonConst
| CT_LValue
));
57 assert(Fn::check_call
<long&>(CT_Const
| CT_LValue
));
58 v
.visit(std::move(obj
));
59 assert(Fn::check_call
<long&>(CT_NonConst
| CT_RValue
));
60 v
.visit(std::move(cobj
));
61 assert(Fn::check_call
<long&>(CT_Const
| CT_RValue
));
65 // Applies to non-member `std::visit` only.
66 void test_argument_forwarding() {
67 using Fn
= ForwardingCallObject
;
69 const auto val
= CT_LValue
| CT_NonConst
;
71 { // single argument - value type
72 using V
= std::variant
<int>;
77 assert(Fn::check_call
<int&>(val
));
79 assert(Fn::check_call
<const int&>(val
));
80 std::move(v
).visit(obj
);
81 assert(Fn::check_call
<int&&>(val
));
82 std::move(cv
).visit(obj
);
83 assert(Fn::check_call
<const int&&>(val
));
87 void test_return_type() {
88 using Fn
= ForwardingCallObject
;
92 { // test call operator forwarding - single variant, single arg
93 using V
= std::variant
<int>;
96 static_assert(std::is_same_v
<decltype(v
.visit(obj
)), Fn
&>);
97 static_assert(std::is_same_v
<decltype(v
.visit(cobj
)), const Fn
&>);
98 static_assert(std::is_same_v
<decltype(v
.visit(std::move(obj
))), Fn
&&>);
99 static_assert(std::is_same_v
<decltype(v
.visit(std::move(cobj
))), const Fn
&&>);
101 { // test call operator forwarding - single variant, multi arg
102 using V
= std::variant
<int, long, double>;
105 static_assert(std::is_same_v
<decltype(v
.visit(obj
)), Fn
&>);
106 static_assert(std::is_same_v
<decltype(v
.visit(cobj
)), const Fn
&>);
107 static_assert(std::is_same_v
<decltype(v
.visit(std::move(obj
))), Fn
&&>);
108 static_assert(std::is_same_v
<decltype(v
.visit(std::move(cobj
))), const Fn
&&>);
112 void test_constexpr() {
113 constexpr ReturnFirst obj
{};
116 using V
= std::variant
<int>;
119 static_assert(v
.visit(obj
) == 42);
122 using V
= std::variant
<short, long, char>;
125 static_assert(v
.visit(obj
) == 42);
129 void test_exceptions() {
130 #ifndef TEST_HAS_NO_EXCEPTIONS
133 auto test
= [&](auto&& v
) {
136 } catch (const std::bad_variant_access
&) {
144 using V
= std::variant
<int, MakeEmptyT
>;
153 // See https://llvm.org/PR31916
154 void test_caller_accepts_nonconst() {
157 void operator()(A
&) {}
164 struct MyVariant
: std::variant
<short, long, float> {};
166 // FIXME: This is UB according to [namespace.std]
168 template <std::size_t Index
>
169 void get(const MyVariant
&) {
174 void test_derived_from_variant() {
175 auto v1
= MyVariant
{42};
176 const auto cv1
= MyVariant
{142};
178 v1
.visit([](auto x
) { assert(x
== 42); });
179 cv1
.visit([](auto x
) { assert(x
== 142); });
180 MyVariant
{-1.25f
}.visit([](auto x
) { assert(x
== -1.25f
); });
181 std::move(v1
).visit([](auto x
) { assert(x
== 42); });
182 std::move(cv1
).visit([](auto x
) { assert(x
== 142); });
184 // Check that visit does not take index nor valueless_by_exception members from the base class.
185 struct EvilVariantBase
{
187 char valueless_by_exception
;
190 struct EvilVariant1
: std::variant
<int, long, double>, std::tuple
<int>, EvilVariantBase
{
191 using std::variant
<int, long, double>::variant
;
194 EvilVariant1
{12}.visit([](auto x
) { assert(x
== 12); });
195 EvilVariant1
{12.3}.visit([](auto x
) { assert(x
== 12.3); });
197 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
198 struct ImplVariantBase
{
200 bool operator()() const {
209 struct EvilVariant2
: std::variant
<int, long, double>, ImplVariantBase
{
210 using std::variant
<int, long, double>::variant
;
213 EvilVariant2
{12}.visit([](auto x
) { assert(x
== 12); });
214 EvilVariant2
{12.3}.visit([](auto x
) { assert(x
== 12.3); });
217 int main(int, char**) {
218 test_call_operator_forwarding();
219 test_argument_forwarding();
223 test_caller_accepts_nonconst();
224 test_derived_from_variant();