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