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, c++17, c++20, c++23 10 // The tested functionality needs deducing this. 11 // UNSUPPORTED: clang-16 || clang-17 12 // XFAIL: apple-clang 13 14 // <variant> 15 16 // class variant; 17 18 // template<class Self, class Visitor> 19 // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 20 21 #include <cassert> 22 #include <memory> 23 #include <string> 24 #include <tuple> 25 #include <type_traits> 26 #include <utility> 27 #include <variant> 28 29 #include "test_macros.h" 30 #include "variant_test_helpers.h" 31 32 void test_call_operator_forwarding() { 33 using Fn = ForwardingCallObject; 34 Fn obj{}; 35 const Fn& cobj = obj; 36 37 { // test call operator forwarding - single variant, single arg 38 using V = std::variant<int>; 39 V v(42); 40 41 v.visit(obj); 42 assert(Fn::check_call<int&>(CT_NonConst | CT_LValue)); 43 v.visit(cobj); 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)); 49 } 50 { // test call operator forwarding - single variant, multi arg 51 using V = std::variant<int, long, double>; 52 V v(42L); 53 54 v.visit(obj); 55 assert(Fn::check_call<long&>(CT_NonConst | CT_LValue)); 56 v.visit(cobj); 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)); 62 } 63 } 64 65 // Applies to non-member `std::visit` only. 66 void test_argument_forwarding() { 67 using Fn = ForwardingCallObject; 68 Fn obj{}; 69 const auto val = CT_LValue | CT_NonConst; 70 71 { // single argument - value type 72 using V = std::variant<int>; 73 V v(42); 74 const V& cv = v; 75 76 v.visit(obj); 77 assert(Fn::check_call<int&>(val)); 78 cv.visit(obj); 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)); 84 } 85 } 86 87 void test_return_type() { 88 using Fn = ForwardingCallObject; 89 Fn obj{}; 90 const Fn& cobj = obj; 91 92 { // test call operator forwarding - single variant, single arg 93 using V = std::variant<int>; 94 V v(42); 95 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&&>); 100 } 101 { // test call operator forwarding - single variant, multi arg 102 using V = std::variant<int, long, double>; 103 V v(42L); 104 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&&>); 109 } 110 } 111 112 void test_constexpr() { 113 constexpr ReturnFirst obj{}; 114 115 { 116 using V = std::variant<int>; 117 constexpr V v(42); 118 119 static_assert(v.visit(obj) == 42); 120 } 121 { 122 using V = std::variant<short, long, char>; 123 constexpr V v(42L); 124 125 static_assert(v.visit(obj) == 42); 126 } 127 } 128 129 void test_exceptions() { 130 #ifndef TEST_HAS_NO_EXCEPTIONS 131 ReturnArity obj{}; 132 133 auto test = [&](auto&& v) { 134 try { 135 v.visit(obj); 136 } catch (const std::bad_variant_access&) { 137 return true; 138 } catch (...) { 139 } 140 return false; 141 }; 142 143 { 144 using V = std::variant<int, MakeEmptyT>; 145 V v; 146 makeEmpty(v); 147 148 assert(test(v)); 149 } 150 #endif 151 } 152 153 // See https://llvm.org/PR31916 154 void test_caller_accepts_nonconst() { 155 struct A {}; 156 struct Visitor { 157 void operator()(A&) {} 158 }; 159 std::variant<A> v; 160 161 v.visit(Visitor{}); 162 } 163 164 struct MyVariant : std::variant<short, long, float> {}; 165 166 namespace std { 167 template <std::size_t Index> 168 void get(const MyVariant&) { 169 assert(false); 170 } 171 } // namespace std 172 173 void test_derived_from_variant() { 174 auto v1 = MyVariant{42}; 175 const auto cv1 = MyVariant{142}; 176 177 v1.visit([](auto x) { assert(x == 42); }); 178 cv1.visit([](auto x) { assert(x == 142); }); 179 MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); 180 std::move(v1).visit([](auto x) { assert(x == 42); }); 181 std::move(cv1).visit([](auto x) { assert(x == 142); }); 182 183 // Check that visit does not take index nor valueless_by_exception members from the base class. 184 struct EvilVariantBase { 185 int index; 186 char valueless_by_exception; 187 }; 188 189 struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase { 190 using std::variant<int, long, double>::variant; 191 }; 192 193 EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); 194 EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); 195 196 // Check that visit unambiguously picks the variant, even if the other base has __impl member. 197 struct ImplVariantBase { 198 struct Callable { 199 bool operator()() const { 200 assert(false); 201 return false; 202 } 203 }; 204 205 Callable __impl; 206 }; 207 208 struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase { 209 using std::variant<int, long, double>::variant; 210 }; 211 212 EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); 213 EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); 214 } 215 216 int main(int, char**) { 217 test_call_operator_forwarding(); 218 test_argument_forwarding(); 219 test_return_type(); 220 test_constexpr(); 221 test_exceptions(); 222 test_caller_accepts_nonconst(); 223 test_derived_from_variant(); 224 225 return 0; 226 } 227