1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is dual licensed under the MIT and the University of Illinois Open 7 // Source Licenses. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 // UNSUPPORTED: c++98, c++03, c++11, c++14 12 13 // The following compilers don't generate constexpr special members correctly. 14 // XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 15 // XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 16 17 // XFAIL: availability=macosx10.13 18 // XFAIL: availability=macosx10.12 19 // XFAIL: availability=macosx10.11 20 // XFAIL: availability=macosx10.10 21 // XFAIL: availability=macosx10.9 22 // XFAIL: availability=macosx10.8 23 // XFAIL: availability=macosx10.7 24 25 26 // <variant> 27 28 // template <class ...Types> class variant; 29 30 // variant& operator=(variant&&) noexcept(see below); 31 32 #include <cassert> 33 #include <string> 34 #include <type_traits> 35 #include <utility> 36 #include <variant> 37 38 #include "test_macros.h" 39 #include "variant_test_helpers.hpp" 40 41 struct NoCopy { 42 NoCopy(const NoCopy &) = delete; 43 NoCopy &operator=(const NoCopy &) = default; 44 }; 45 46 struct CopyOnly { 47 CopyOnly(const CopyOnly &) = default; 48 CopyOnly(CopyOnly &&) = delete; 49 CopyOnly &operator=(const CopyOnly &) = default; 50 CopyOnly &operator=(CopyOnly &&) = delete; 51 }; 52 53 struct MoveOnly { 54 MoveOnly(const MoveOnly &) = delete; 55 MoveOnly(MoveOnly &&) = default; 56 MoveOnly &operator=(const MoveOnly &) = delete; 57 MoveOnly &operator=(MoveOnly &&) = default; 58 }; 59 60 struct MoveOnlyNT { 61 MoveOnlyNT(const MoveOnlyNT &) = delete; 62 MoveOnlyNT(MoveOnlyNT &&) {} 63 MoveOnlyNT &operator=(const MoveOnlyNT &) = delete; 64 MoveOnlyNT &operator=(MoveOnlyNT &&) = default; 65 }; 66 67 struct MoveOnlyOddNothrow { 68 MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {} 69 MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete; 70 MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default; 71 MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete; 72 }; 73 74 struct MoveAssignOnly { 75 MoveAssignOnly(MoveAssignOnly &&) = delete; 76 MoveAssignOnly &operator=(MoveAssignOnly &&) = default; 77 }; 78 79 struct MoveAssign { 80 static int move_construct; 81 static int move_assign; 82 static void reset() { move_construct = move_assign = 0; } 83 MoveAssign(int v) : value(v) {} 84 MoveAssign(MoveAssign &&o) : value(o.value) { 85 ++move_construct; 86 o.value = -1; 87 } 88 MoveAssign &operator=(MoveAssign &&o) { 89 value = o.value; 90 ++move_assign; 91 o.value = -1; 92 return *this; 93 } 94 int value; 95 }; 96 97 int MoveAssign::move_construct = 0; 98 int MoveAssign::move_assign = 0; 99 100 struct NTMoveAssign { 101 constexpr NTMoveAssign(int v) : value(v) {} 102 NTMoveAssign(const NTMoveAssign &) = default; 103 NTMoveAssign(NTMoveAssign &&) = default; 104 NTMoveAssign &operator=(const NTMoveAssign &that) = default; 105 NTMoveAssign &operator=(NTMoveAssign &&that) { 106 value = that.value; 107 that.value = -1; 108 return *this; 109 }; 110 int value; 111 }; 112 113 static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, ""); 114 static_assert(std::is_move_assignable<NTMoveAssign>::value, ""); 115 116 struct TMoveAssign { 117 constexpr TMoveAssign(int v) : value(v) {} 118 TMoveAssign(const TMoveAssign &) = delete; 119 TMoveAssign(TMoveAssign &&) = default; 120 TMoveAssign &operator=(const TMoveAssign &) = delete; 121 TMoveAssign &operator=(TMoveAssign &&) = default; 122 int value; 123 }; 124 125 static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, ""); 126 127 struct TMoveAssignNTCopyAssign { 128 constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} 129 TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; 130 TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; 131 TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { 132 value = that.value; 133 return *this; 134 } 135 TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; 136 int value; 137 }; 138 139 static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, ""); 140 141 struct TrivialCopyNontrivialMove { 142 TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; 143 TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} 144 TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; 145 TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { 146 return *this; 147 } 148 }; 149 150 static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, ""); 151 static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, ""); 152 153 154 void test_move_assignment_noexcept() { 155 { 156 using V = std::variant<int>; 157 static_assert(std::is_nothrow_move_assignable<V>::value, ""); 158 } 159 { 160 using V = std::variant<MoveOnly>; 161 static_assert(std::is_nothrow_move_assignable<V>::value, ""); 162 } 163 { 164 using V = std::variant<int, long>; 165 static_assert(std::is_nothrow_move_assignable<V>::value, ""); 166 } 167 { 168 using V = std::variant<int, MoveOnly>; 169 static_assert(std::is_nothrow_move_assignable<V>::value, ""); 170 } 171 { 172 using V = std::variant<MoveOnlyNT>; 173 static_assert(!std::is_nothrow_move_assignable<V>::value, ""); 174 } 175 { 176 using V = std::variant<MoveOnlyOddNothrow>; 177 static_assert(!std::is_nothrow_move_assignable<V>::value, ""); 178 } 179 } 180 181 void test_move_assignment_sfinae() { 182 { 183 using V = std::variant<int, long>; 184 static_assert(std::is_move_assignable<V>::value, ""); 185 } 186 { 187 using V = std::variant<int, CopyOnly>; 188 static_assert(std::is_move_assignable<V>::value, ""); 189 } 190 { 191 using V = std::variant<int, NoCopy>; 192 static_assert(!std::is_move_assignable<V>::value, ""); 193 } 194 { 195 using V = std::variant<int, MoveOnly>; 196 static_assert(std::is_move_assignable<V>::value, ""); 197 } 198 { 199 using V = std::variant<int, MoveOnlyNT>; 200 static_assert(std::is_move_assignable<V>::value, ""); 201 } 202 { 203 // variant only provides move assignment when the types also provide 204 // a move constructor. 205 using V = std::variant<int, MoveAssignOnly>; 206 static_assert(!std::is_move_assignable<V>::value, ""); 207 } 208 209 // The following tests are for not-yet-standardized behavior (P0602): 210 { 211 using V = std::variant<int, long>; 212 static_assert(std::is_trivially_move_assignable<V>::value, ""); 213 } 214 { 215 using V = std::variant<int, NTMoveAssign>; 216 static_assert(!std::is_trivially_move_assignable<V>::value, ""); 217 static_assert(std::is_move_assignable<V>::value, ""); 218 } 219 { 220 using V = std::variant<int, TMoveAssign>; 221 static_assert(std::is_trivially_move_assignable<V>::value, ""); 222 } 223 { 224 using V = std::variant<int, TMoveAssignNTCopyAssign>; 225 static_assert(std::is_trivially_move_assignable<V>::value, ""); 226 } 227 { 228 using V = std::variant<int, TrivialCopyNontrivialMove>; 229 static_assert(!std::is_trivially_move_assignable<V>::value, ""); 230 } 231 { 232 using V = std::variant<int, CopyOnly>; 233 static_assert(std::is_trivially_move_assignable<V>::value, ""); 234 } 235 } 236 237 void test_move_assignment_empty_empty() { 238 #ifndef TEST_HAS_NO_EXCEPTIONS 239 using MET = MakeEmptyT; 240 { 241 using V = std::variant<int, long, MET>; 242 V v1(std::in_place_index<0>); 243 makeEmpty(v1); 244 V v2(std::in_place_index<0>); 245 makeEmpty(v2); 246 V &vref = (v1 = std::move(v2)); 247 assert(&vref == &v1); 248 assert(v1.valueless_by_exception()); 249 assert(v1.index() == std::variant_npos); 250 } 251 #endif // TEST_HAS_NO_EXCEPTIONS 252 } 253 254 void test_move_assignment_non_empty_empty() { 255 #ifndef TEST_HAS_NO_EXCEPTIONS 256 using MET = MakeEmptyT; 257 { 258 using V = std::variant<int, MET>; 259 V v1(std::in_place_index<0>, 42); 260 V v2(std::in_place_index<0>); 261 makeEmpty(v2); 262 V &vref = (v1 = std::move(v2)); 263 assert(&vref == &v1); 264 assert(v1.valueless_by_exception()); 265 assert(v1.index() == std::variant_npos); 266 } 267 { 268 using V = std::variant<int, MET, std::string>; 269 V v1(std::in_place_index<2>, "hello"); 270 V v2(std::in_place_index<0>); 271 makeEmpty(v2); 272 V &vref = (v1 = std::move(v2)); 273 assert(&vref == &v1); 274 assert(v1.valueless_by_exception()); 275 assert(v1.index() == std::variant_npos); 276 } 277 #endif // TEST_HAS_NO_EXCEPTIONS 278 } 279 280 void test_move_assignment_empty_non_empty() { 281 #ifndef TEST_HAS_NO_EXCEPTIONS 282 using MET = MakeEmptyT; 283 { 284 using V = std::variant<int, MET>; 285 V v1(std::in_place_index<0>); 286 makeEmpty(v1); 287 V v2(std::in_place_index<0>, 42); 288 V &vref = (v1 = std::move(v2)); 289 assert(&vref == &v1); 290 assert(v1.index() == 0); 291 assert(std::get<0>(v1) == 42); 292 } 293 { 294 using V = std::variant<int, MET, std::string>; 295 V v1(std::in_place_index<0>); 296 makeEmpty(v1); 297 V v2(std::in_place_type<std::string>, "hello"); 298 V &vref = (v1 = std::move(v2)); 299 assert(&vref == &v1); 300 assert(v1.index() == 2); 301 assert(std::get<2>(v1) == "hello"); 302 } 303 #endif // TEST_HAS_NO_EXCEPTIONS 304 } 305 306 template <typename T> struct Result { size_t index; T value; }; 307 308 void test_move_assignment_same_index() { 309 { 310 using V = std::variant<int>; 311 V v1(43); 312 V v2(42); 313 V &vref = (v1 = std::move(v2)); 314 assert(&vref == &v1); 315 assert(v1.index() == 0); 316 assert(std::get<0>(v1) == 42); 317 } 318 { 319 using V = std::variant<int, long, unsigned>; 320 V v1(43l); 321 V v2(42l); 322 V &vref = (v1 = std::move(v2)); 323 assert(&vref == &v1); 324 assert(v1.index() == 1); 325 assert(std::get<1>(v1) == 42); 326 } 327 { 328 using V = std::variant<int, MoveAssign, unsigned>; 329 V v1(std::in_place_type<MoveAssign>, 43); 330 V v2(std::in_place_type<MoveAssign>, 42); 331 MoveAssign::reset(); 332 V &vref = (v1 = std::move(v2)); 333 assert(&vref == &v1); 334 assert(v1.index() == 1); 335 assert(std::get<1>(v1).value == 42); 336 assert(MoveAssign::move_construct == 0); 337 assert(MoveAssign::move_assign == 1); 338 } 339 #ifndef TEST_HAS_NO_EXCEPTIONS 340 using MET = MakeEmptyT; 341 { 342 using V = std::variant<int, MET, std::string>; 343 V v1(std::in_place_type<MET>); 344 MET &mref = std::get<1>(v1); 345 V v2(std::in_place_type<MET>); 346 try { 347 v1 = std::move(v2); 348 assert(false); 349 } catch (...) { 350 } 351 assert(v1.index() == 1); 352 assert(&std::get<1>(v1) == &mref); 353 } 354 #endif // TEST_HAS_NO_EXCEPTIONS 355 356 // The following tests are for not-yet-standardized behavior (P0602): 357 { 358 struct { 359 constexpr Result<int> operator()() const { 360 using V = std::variant<int>; 361 V v(43); 362 V v2(42); 363 v = std::move(v2); 364 return {v.index(), std::get<0>(v)}; 365 } 366 } test; 367 constexpr auto result = test(); 368 static_assert(result.index == 0, ""); 369 static_assert(result.value == 42, ""); 370 } 371 { 372 struct { 373 constexpr Result<long> operator()() const { 374 using V = std::variant<int, long, unsigned>; 375 V v(43l); 376 V v2(42l); 377 v = std::move(v2); 378 return {v.index(), std::get<1>(v)}; 379 } 380 } test; 381 constexpr auto result = test(); 382 static_assert(result.index == 1, ""); 383 static_assert(result.value == 42l, ""); 384 } 385 { 386 struct { 387 constexpr Result<int> operator()() const { 388 using V = std::variant<int, TMoveAssign, unsigned>; 389 V v(std::in_place_type<TMoveAssign>, 43); 390 V v2(std::in_place_type<TMoveAssign>, 42); 391 v = std::move(v2); 392 return {v.index(), std::get<1>(v).value}; 393 } 394 } test; 395 constexpr auto result = test(); 396 static_assert(result.index == 1, ""); 397 static_assert(result.value == 42, ""); 398 } 399 } 400 401 void test_move_assignment_different_index() { 402 { 403 using V = std::variant<int, long, unsigned>; 404 V v1(43); 405 V v2(42l); 406 V &vref = (v1 = std::move(v2)); 407 assert(&vref == &v1); 408 assert(v1.index() == 1); 409 assert(std::get<1>(v1) == 42); 410 } 411 { 412 using V = std::variant<int, MoveAssign, unsigned>; 413 V v1(std::in_place_type<unsigned>, 43); 414 V v2(std::in_place_type<MoveAssign>, 42); 415 MoveAssign::reset(); 416 V &vref = (v1 = std::move(v2)); 417 assert(&vref == &v1); 418 assert(v1.index() == 1); 419 assert(std::get<1>(v1).value == 42); 420 assert(MoveAssign::move_construct == 1); 421 assert(MoveAssign::move_assign == 0); 422 } 423 #ifndef TEST_HAS_NO_EXCEPTIONS 424 using MET = MakeEmptyT; 425 { 426 using V = std::variant<int, MET, std::string>; 427 V v1(std::in_place_type<int>); 428 V v2(std::in_place_type<MET>); 429 try { 430 v1 = std::move(v2); 431 assert(false); 432 } catch (...) { 433 } 434 assert(v1.valueless_by_exception()); 435 assert(v1.index() == std::variant_npos); 436 } 437 { 438 using V = std::variant<int, MET, std::string>; 439 V v1(std::in_place_type<MET>); 440 V v2(std::in_place_type<std::string>, "hello"); 441 V &vref = (v1 = std::move(v2)); 442 assert(&vref == &v1); 443 assert(v1.index() == 2); 444 assert(std::get<2>(v1) == "hello"); 445 } 446 #endif // TEST_HAS_NO_EXCEPTIONS 447 448 // The following tests are for not-yet-standardized behavior (P0602): 449 { 450 struct { 451 constexpr Result<long> operator()() const { 452 using V = std::variant<int, long, unsigned>; 453 V v(43); 454 V v2(42l); 455 v = std::move(v2); 456 return {v.index(), std::get<1>(v)}; 457 } 458 } test; 459 constexpr auto result = test(); 460 static_assert(result.index == 1, ""); 461 static_assert(result.value == 42l, ""); 462 } 463 { 464 struct { 465 constexpr Result<long> operator()() const { 466 using V = std::variant<int, TMoveAssign, unsigned>; 467 V v(std::in_place_type<unsigned>, 43); 468 V v2(std::in_place_type<TMoveAssign>, 42); 469 v = std::move(v2); 470 return {v.index(), std::get<1>(v).value}; 471 } 472 } test; 473 constexpr auto result = test(); 474 static_assert(result.index == 1, ""); 475 static_assert(result.value == 42, ""); 476 } 477 } 478 479 template <size_t NewIdx, class ValueType> 480 constexpr bool test_constexpr_assign_extension_imp( 481 std::variant<long, void*, int>&& v, ValueType&& new_value) 482 { 483 std::variant<long, void*, int> v2( 484 std::forward<ValueType>(new_value)); 485 const auto cp = v2; 486 v = std::move(v2); 487 return v.index() == NewIdx && 488 std::get<NewIdx>(v) == std::get<NewIdx>(cp); 489 } 490 491 void test_constexpr_move_assignment_extension() { 492 // The following tests are for not-yet-standardized behavior (P0602): 493 using V = std::variant<long, void*, int>; 494 static_assert(std::is_trivially_copyable<V>::value, ""); 495 static_assert(std::is_trivially_move_assignable<V>::value, ""); 496 static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); 497 static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); 498 static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); 499 static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); 500 } 501 502 int main() { 503 test_move_assignment_empty_empty(); 504 test_move_assignment_non_empty_empty(); 505 test_move_assignment_empty_non_empty(); 506 test_move_assignment_same_index(); 507 test_move_assignment_different_index(); 508 test_move_assignment_sfinae(); 509 test_move_assignment_noexcept(); 510 test_constexpr_move_assignment_extension(); 511 } 512