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