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 // XFAIL: apple-clang 12 13 // <variant> 14 15 // class variant; 16 17 // template<class Self, class Visitor> 18 // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 19 20 #include <cassert> 21 #include <memory> 22 #include <string> 23 #include <tuple> 24 #include <type_traits> 25 #include <utility> 26 #include <variant> 27 28 #include "test_macros.h" 29 #include "variant_test_helpers.h" 30 31 void test_call_operator_forwarding() { 32 using Fn = ForwardingCallObject; 33 Fn obj{}; 34 const Fn& cobj = obj; 35 36 { // test call operator forwarding - single variant, single arg 37 using V = std::variant<int>; 38 V v(42); 39 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)); 48 } 49 { // test call operator forwarding - single variant, multi arg 50 using V = std::variant<int, long, double>; 51 V v(42L); 52 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)); 61 } 62 } 63 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; 69 70 { // single argument - value type 71 using V = std::variant<int>; 72 V v(42); 73 const V& cv = v; 74 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)); 83 } 84 } 85 86 void test_return_type() { 87 using Fn = ForwardingCallObject; 88 Fn obj{}; 89 const Fn& cobj = obj; 90 91 { // test call operator forwarding - single variant, single arg 92 using V = std::variant<int>; 93 V v(42); 94 95 static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>); 96 static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>); 97 static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>); 98 static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>); 99 } 100 { // test call operator forwarding - single variant, multi arg 101 using V = std::variant<int, long, double>; 102 V v(42L); 103 104 static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>); 105 static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>); 106 static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>); 107 static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>); 108 } 109 } 110 111 void test_constexpr() { 112 constexpr ReturnFirst obj{}; 113 114 { 115 using V = std::variant<int>; 116 constexpr V v(42); 117 118 static_assert(v.visit(obj) == 42); 119 } 120 { 121 using V = std::variant<short, long, char>; 122 constexpr V v(42L); 123 124 static_assert(v.visit(obj) == 42); 125 } 126 } 127 128 void test_exceptions() { 129 #ifndef TEST_HAS_NO_EXCEPTIONS 130 ReturnArity obj{}; 131 132 auto test = [&](auto&& v) { 133 try { 134 v.visit(obj); 135 } catch (const std::bad_variant_access&) { 136 return true; 137 } catch (...) { 138 } 139 return false; 140 }; 141 142 { 143 using V = std::variant<int, MakeEmptyT>; 144 V v; 145 makeEmpty(v); 146 147 assert(test(v)); 148 } 149 #endif 150 } 151 152 // See https://llvm.org/PR31916 153 void test_caller_accepts_nonconst() { 154 struct A {}; 155 struct Visitor { 156 void operator()(A&) {} 157 }; 158 std::variant<A> v; 159 160 v.visit(Visitor{}); 161 } 162 163 struct MyVariant : std::variant<short, long, float> {}; 164 165 // FIXME: This is UB according to [namespace.std] 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