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