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