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: with_system_cxx_lib=macosx10.12 18// XFAIL: with_system_cxx_lib=macosx10.11 19// XFAIL: with_system_cxx_lib=macosx10.10 20// XFAIL: with_system_cxx_lib=macosx10.9 21// XFAIL: with_system_cxx_lib=macosx10.7 22// XFAIL: with_system_cxx_lib=macosx10.8 23 24// <variant> 25 26// template <class ...Types> class variant; 27 28// variant& operator=(variant const&); 29 30#include <cassert> 31#include <string> 32#include <type_traits> 33#include <variant> 34 35#include "test_macros.h" 36 37struct NoCopy { 38 NoCopy(const NoCopy &) = delete; 39 NoCopy &operator=(const NoCopy &) = default; 40}; 41 42struct CopyOnly { 43 CopyOnly(const CopyOnly &) = default; 44 CopyOnly(CopyOnly &&) = delete; 45 CopyOnly &operator=(const CopyOnly &) = default; 46 CopyOnly &operator=(CopyOnly &&) = delete; 47}; 48 49struct MoveOnly { 50 MoveOnly(const MoveOnly &) = delete; 51 MoveOnly(MoveOnly &&) = default; 52 MoveOnly &operator=(const MoveOnly &) = default; 53}; 54 55struct MoveOnlyNT { 56 MoveOnlyNT(const MoveOnlyNT &) = delete; 57 MoveOnlyNT(MoveOnlyNT &&) {} 58 MoveOnlyNT &operator=(const MoveOnlyNT &) = default; 59}; 60 61struct CopyAssign { 62 static int alive; 63 static int copy_construct; 64 static int copy_assign; 65 static int move_construct; 66 static int move_assign; 67 static void reset() { 68 copy_construct = copy_assign = move_construct = move_assign = alive = 0; 69 } 70 CopyAssign(int v) : value(v) { ++alive; } 71 CopyAssign(const CopyAssign &o) : value(o.value) { 72 ++alive; 73 ++copy_construct; 74 } 75 CopyAssign(CopyAssign &&o) noexcept : value(o.value) { 76 o.value = -1; 77 ++alive; 78 ++move_construct; 79 } 80 CopyAssign &operator=(const CopyAssign &o) { 81 value = o.value; 82 ++copy_assign; 83 return *this; 84 } 85 CopyAssign &operator=(CopyAssign &&o) noexcept { 86 value = o.value; 87 o.value = -1; 88 ++move_assign; 89 return *this; 90 } 91 ~CopyAssign() { --alive; } 92 int value; 93}; 94 95int CopyAssign::alive = 0; 96int CopyAssign::copy_construct = 0; 97int CopyAssign::copy_assign = 0; 98int CopyAssign::move_construct = 0; 99int CopyAssign::move_assign = 0; 100 101struct CopyMaybeThrows { 102 CopyMaybeThrows(const CopyMaybeThrows &); 103 CopyMaybeThrows &operator=(const CopyMaybeThrows &); 104}; 105struct CopyDoesThrow { 106 CopyDoesThrow(const CopyDoesThrow &) noexcept(false); 107 CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false); 108}; 109 110 111struct NTCopyAssign { 112 constexpr NTCopyAssign(int v) : value(v) {} 113 NTCopyAssign(const NTCopyAssign &) = default; 114 NTCopyAssign(NTCopyAssign &&) = default; 115 NTCopyAssign &operator=(const NTCopyAssign &that) { 116 value = that.value; 117 return *this; 118 }; 119 NTCopyAssign &operator=(NTCopyAssign &&) = delete; 120 int value; 121}; 122 123static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, ""); 124static_assert(std::is_copy_assignable<NTCopyAssign>::value, ""); 125 126struct TCopyAssign { 127 constexpr TCopyAssign(int v) : value(v) {} 128 TCopyAssign(const TCopyAssign &) = default; 129 TCopyAssign(TCopyAssign &&) = default; 130 TCopyAssign &operator=(const TCopyAssign &) = default; 131 TCopyAssign &operator=(TCopyAssign &&) = delete; 132 int value; 133}; 134 135static_assert(std::is_trivially_copy_assignable<TCopyAssign>::value, ""); 136 137struct TCopyAssignNTMoveAssign { 138 constexpr TCopyAssignNTMoveAssign(int v) : value(v) {} 139 TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default; 140 TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default; 141 TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default; 142 TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) { 143 value = that.value; 144 that.value = -1; 145 return *this; 146 } 147 int value; 148}; 149 150static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, ""); 151 152#ifndef TEST_HAS_NO_EXCEPTIONS 153struct CopyThrows { 154 CopyThrows() = default; 155 CopyThrows(const CopyThrows &) { throw 42; } 156 CopyThrows &operator=(const CopyThrows &) { throw 42; } 157}; 158 159struct CopyCannotThrow { 160 static int alive; 161 CopyCannotThrow() { ++alive; } 162 CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; } 163 CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); } 164 CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default; 165 CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; } 166}; 167 168int CopyCannotThrow::alive = 0; 169 170struct MoveThrows { 171 static int alive; 172 MoveThrows() { ++alive; } 173 MoveThrows(const MoveThrows &) { ++alive; } 174 MoveThrows(MoveThrows &&) { throw 42; } 175 MoveThrows &operator=(const MoveThrows &) { return *this; } 176 MoveThrows &operator=(MoveThrows &&) { throw 42; } 177 ~MoveThrows() { --alive; } 178}; 179 180int MoveThrows::alive = 0; 181 182struct MakeEmptyT { 183 static int alive; 184 MakeEmptyT() { ++alive; } 185 MakeEmptyT(const MakeEmptyT &) { 186 ++alive; 187 // Don't throw from the copy constructor since variant's assignment 188 // operator performs a copy before committing to the assignment. 189 } 190 MakeEmptyT(MakeEmptyT &&) { throw 42; } 191 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } 192 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 193 ~MakeEmptyT() { --alive; } 194}; 195 196int MakeEmptyT::alive = 0; 197 198template <class Variant> void makeEmpty(Variant &v) { 199 Variant v2(std::in_place_type<MakeEmptyT>); 200 try { 201 v = std::move(v2); 202 assert(false); 203 } catch (...) { 204 assert(v.valueless_by_exception()); 205 } 206} 207#endif // TEST_HAS_NO_EXCEPTIONS 208 209void test_copy_assignment_not_noexcept() { 210 { 211 using V = std::variant<CopyMaybeThrows>; 212 static_assert(!std::is_nothrow_copy_assignable<V>::value, ""); 213 } 214 { 215 using V = std::variant<int, CopyDoesThrow>; 216 static_assert(!std::is_nothrow_copy_assignable<V>::value, ""); 217 } 218} 219 220void test_copy_assignment_sfinae() { 221 { 222 using V = std::variant<int, long>; 223 static_assert(std::is_copy_assignable<V>::value, ""); 224 } 225 { 226 using V = std::variant<int, CopyOnly>; 227 static_assert(std::is_copy_assignable<V>::value, ""); 228 } 229 { 230 using V = std::variant<int, NoCopy>; 231 static_assert(!std::is_copy_assignable<V>::value, ""); 232 } 233 { 234 using V = std::variant<int, MoveOnly>; 235 static_assert(!std::is_copy_assignable<V>::value, ""); 236 } 237 { 238 using V = std::variant<int, MoveOnlyNT>; 239 static_assert(!std::is_copy_assignable<V>::value, ""); 240 } 241 242 // The following tests are for not-yet-standardized behavior (P0602): 243 { 244 using V = std::variant<int, long>; 245 static_assert(std::is_trivially_copy_assignable<V>::value, ""); 246 } 247 { 248 using V = std::variant<int, NTCopyAssign>; 249 static_assert(!std::is_trivially_copy_assignable<V>::value, ""); 250 static_assert(std::is_copy_assignable<V>::value, ""); 251 } 252 { 253 using V = std::variant<int, TCopyAssign>; 254 static_assert(std::is_trivially_copy_assignable<V>::value, ""); 255 } 256 { 257 using V = std::variant<int, TCopyAssignNTMoveAssign>; 258 static_assert(std::is_trivially_copy_assignable<V>::value, ""); 259 } 260 { 261 using V = std::variant<int, CopyOnly>; 262 static_assert(std::is_trivially_copy_assignable<V>::value, ""); 263 } 264} 265 266void test_copy_assignment_empty_empty() { 267#ifndef TEST_HAS_NO_EXCEPTIONS 268 using MET = MakeEmptyT; 269 { 270 using V = std::variant<int, long, MET>; 271 V v1(std::in_place_index<0>); 272 makeEmpty(v1); 273 V v2(std::in_place_index<0>); 274 makeEmpty(v2); 275 V &vref = (v1 = v2); 276 assert(&vref == &v1); 277 assert(v1.valueless_by_exception()); 278 assert(v1.index() == std::variant_npos); 279 } 280#endif // TEST_HAS_NO_EXCEPTIONS 281} 282 283void test_copy_assignment_non_empty_empty() { 284#ifndef TEST_HAS_NO_EXCEPTIONS 285 using MET = MakeEmptyT; 286 { 287 using V = std::variant<int, MET>; 288 V v1(std::in_place_index<0>, 42); 289 V v2(std::in_place_index<0>); 290 makeEmpty(v2); 291 V &vref = (v1 = v2); 292 assert(&vref == &v1); 293 assert(v1.valueless_by_exception()); 294 assert(v1.index() == std::variant_npos); 295 } 296 { 297 using V = std::variant<int, MET, std::string>; 298 V v1(std::in_place_index<2>, "hello"); 299 V v2(std::in_place_index<0>); 300 makeEmpty(v2); 301 V &vref = (v1 = v2); 302 assert(&vref == &v1); 303 assert(v1.valueless_by_exception()); 304 assert(v1.index() == std::variant_npos); 305 } 306#endif // TEST_HAS_NO_EXCEPTIONS 307} 308 309void test_copy_assignment_empty_non_empty() { 310#ifndef TEST_HAS_NO_EXCEPTIONS 311 using MET = MakeEmptyT; 312 { 313 using V = std::variant<int, MET>; 314 V v1(std::in_place_index<0>); 315 makeEmpty(v1); 316 V v2(std::in_place_index<0>, 42); 317 V &vref = (v1 = v2); 318 assert(&vref == &v1); 319 assert(v1.index() == 0); 320 assert(std::get<0>(v1) == 42); 321 } 322 { 323 using V = std::variant<int, MET, std::string>; 324 V v1(std::in_place_index<0>); 325 makeEmpty(v1); 326 V v2(std::in_place_type<std::string>, "hello"); 327 V &vref = (v1 = v2); 328 assert(&vref == &v1); 329 assert(v1.index() == 2); 330 assert(std::get<2>(v1) == "hello"); 331 } 332#endif // TEST_HAS_NO_EXCEPTIONS 333} 334 335template <typename T> struct Result { size_t index; T value; }; 336 337void test_copy_assignment_same_index() { 338 { 339 using V = std::variant<int>; 340 V v1(43); 341 V v2(42); 342 V &vref = (v1 = v2); 343 assert(&vref == &v1); 344 assert(v1.index() == 0); 345 assert(std::get<0>(v1) == 42); 346 } 347 { 348 using V = std::variant<int, long, unsigned>; 349 V v1(43l); 350 V v2(42l); 351 V &vref = (v1 = v2); 352 assert(&vref == &v1); 353 assert(v1.index() == 1); 354 assert(std::get<1>(v1) == 42); 355 } 356 { 357 using V = std::variant<int, CopyAssign, unsigned>; 358 V v1(std::in_place_type<CopyAssign>, 43); 359 V v2(std::in_place_type<CopyAssign>, 42); 360 CopyAssign::reset(); 361 V &vref = (v1 = v2); 362 assert(&vref == &v1); 363 assert(v1.index() == 1); 364 assert(std::get<1>(v1).value == 42); 365 assert(CopyAssign::copy_construct == 0); 366 assert(CopyAssign::move_construct == 0); 367 assert(CopyAssign::copy_assign == 1); 368 } 369#ifndef TEST_HAS_NO_EXCEPTIONS 370 using MET = MakeEmptyT; 371 { 372 using V = std::variant<int, MET, std::string>; 373 V v1(std::in_place_type<MET>); 374 MET &mref = std::get<1>(v1); 375 V v2(std::in_place_type<MET>); 376 try { 377 v1 = v2; 378 assert(false); 379 } catch (...) { 380 } 381 assert(v1.index() == 1); 382 assert(&std::get<1>(v1) == &mref); 383 } 384#endif // TEST_HAS_NO_EXCEPTIONS 385 386 // The following tests are for not-yet-standardized behavior (P0602): 387 { 388 struct { 389 constexpr Result<int> operator()() const { 390 using V = std::variant<int>; 391 V v(43); 392 V v2(42); 393 v = v2; 394 return {v.index(), std::get<0>(v)}; 395 } 396 } test; 397 constexpr auto result = test(); 398 static_assert(result.index == 0, ""); 399 static_assert(result.value == 42, ""); 400 } 401 { 402 struct { 403 constexpr Result<long> operator()() const { 404 using V = std::variant<int, long, unsigned>; 405 V v(43l); 406 V v2(42l); 407 v = v2; 408 return {v.index(), std::get<1>(v)}; 409 } 410 } test; 411 constexpr auto result = test(); 412 static_assert(result.index == 1, ""); 413 static_assert(result.value == 42l, ""); 414 } 415 { 416 struct { 417 constexpr Result<int> operator()() const { 418 using V = std::variant<int, TCopyAssign, unsigned>; 419 V v(std::in_place_type<TCopyAssign>, 43); 420 V v2(std::in_place_type<TCopyAssign>, 42); 421 v = v2; 422 return {v.index(), std::get<1>(v).value}; 423 } 424 } test; 425 constexpr auto result = test(); 426 static_assert(result.index == 1, ""); 427 static_assert(result.value == 42, ""); 428 } 429 { 430 struct { 431 constexpr Result<int> operator()() const { 432 using V = std::variant<int, TCopyAssignNTMoveAssign, unsigned>; 433 V v(std::in_place_type<TCopyAssignNTMoveAssign>, 43); 434 V v2(std::in_place_type<TCopyAssignNTMoveAssign>, 42); 435 v = v2; 436 return {v.index(), std::get<1>(v).value}; 437 } 438 } test; 439 constexpr auto result = test(); 440 static_assert(result.index == 1, ""); 441 static_assert(result.value == 42, ""); 442 } 443} 444 445void test_copy_assignment_different_index() { 446 { 447 using V = std::variant<int, long, unsigned>; 448 V v1(43); 449 V v2(42l); 450 V &vref = (v1 = v2); 451 assert(&vref == &v1); 452 assert(v1.index() == 1); 453 assert(std::get<1>(v1) == 42); 454 } 455 { 456 using V = std::variant<int, CopyAssign, unsigned>; 457 CopyAssign::reset(); 458 V v1(std::in_place_type<unsigned>, 43); 459 V v2(std::in_place_type<CopyAssign>, 42); 460 assert(CopyAssign::copy_construct == 0); 461 assert(CopyAssign::move_construct == 0); 462 assert(CopyAssign::alive == 1); 463 V &vref = (v1 = v2); 464 assert(&vref == &v1); 465 assert(v1.index() == 1); 466 assert(std::get<1>(v1).value == 42); 467 assert(CopyAssign::alive == 2); 468 assert(CopyAssign::copy_construct == 1); 469 assert(CopyAssign::move_construct == 1); 470 assert(CopyAssign::copy_assign == 0); 471 } 472#ifndef TEST_HAS_NO_EXCEPTIONS 473 { 474 using V = std::variant<int, CopyThrows, std::string>; 475 V v1(std::in_place_type<std::string>, "hello"); 476 V v2(std::in_place_type<CopyThrows>); 477 try { 478 v1 = v2; 479 assert(false); 480 } catch (...) { /* ... */ 481 } 482 // Test that copy construction is used directly if move construction may throw, 483 // resulting in a valueless variant if copy throws. 484 assert(v1.valueless_by_exception()); 485 } 486 { 487 using V = std::variant<int, MoveThrows, std::string>; 488 V v1(std::in_place_type<std::string>, "hello"); 489 V v2(std::in_place_type<MoveThrows>); 490 assert(MoveThrows::alive == 1); 491 // Test that copy construction is used directly if move construction may throw. 492 v1 = v2; 493 assert(v1.index() == 1); 494 assert(v2.index() == 1); 495 assert(MoveThrows::alive == 2); 496 } 497 { 498 // Test that direct copy construction is preferred when it cannot throw. 499 using V = std::variant<int, CopyCannotThrow, std::string>; 500 V v1(std::in_place_type<std::string>, "hello"); 501 V v2(std::in_place_type<CopyCannotThrow>); 502 assert(CopyCannotThrow::alive == 1); 503 v1 = v2; 504 assert(v1.index() == 1); 505 assert(v2.index() == 1); 506 assert(CopyCannotThrow::alive == 2); 507 } 508 { 509 using V = std::variant<int, CopyThrows, std::string>; 510 V v1(std::in_place_type<CopyThrows>); 511 V v2(std::in_place_type<std::string>, "hello"); 512 V &vref = (v1 = v2); 513 assert(&vref == &v1); 514 assert(v1.index() == 2); 515 assert(std::get<2>(v1) == "hello"); 516 assert(v2.index() == 2); 517 assert(std::get<2>(v2) == "hello"); 518 } 519 { 520 using V = std::variant<int, MoveThrows, std::string>; 521 V v1(std::in_place_type<MoveThrows>); 522 V v2(std::in_place_type<std::string>, "hello"); 523 V &vref = (v1 = v2); 524 assert(&vref == &v1); 525 assert(v1.index() == 2); 526 assert(std::get<2>(v1) == "hello"); 527 assert(v2.index() == 2); 528 assert(std::get<2>(v2) == "hello"); 529 } 530#endif // TEST_HAS_NO_EXCEPTIONS 531 532 // The following tests are for not-yet-standardized behavior (P0602): 533 { 534 struct { 535 constexpr Result<long> operator()() const { 536 using V = std::variant<int, long, unsigned>; 537 V v(43); 538 V v2(42l); 539 v = v2; 540 return {v.index(), std::get<1>(v)}; 541 } 542 } test; 543 constexpr auto result = test(); 544 static_assert(result.index == 1, ""); 545 static_assert(result.value == 42l, ""); 546 } 547 { 548 struct { 549 constexpr Result<int> operator()() const { 550 using V = std::variant<int, TCopyAssign, unsigned>; 551 V v(std::in_place_type<unsigned>, 43); 552 V v2(std::in_place_type<TCopyAssign>, 42); 553 v = v2; 554 return {v.index(), std::get<1>(v).value}; 555 } 556 } test; 557 constexpr auto result = test(); 558 static_assert(result.index == 1, ""); 559 static_assert(result.value == 42, ""); 560 } 561} 562 563template <size_t NewIdx, class ValueType> 564constexpr bool test_constexpr_assign_extension_imp( 565 std::variant<long, void*, int>&& v, ValueType&& new_value) 566{ 567 const std::variant<long, void*, int> cp( 568 std::forward<ValueType>(new_value)); 569 v = cp; 570 return v.index() == NewIdx && 571 std::get<NewIdx>(v) == std::get<NewIdx>(cp); 572} 573 574void test_constexpr_copy_assignment_extension() { 575 // The following tests are for not-yet-standardized behavior (P0602): 576 using V = std::variant<long, void*, int>; 577 static_assert(std::is_trivially_copyable<V>::value, ""); 578 static_assert(std::is_trivially_copy_assignable<V>::value, ""); 579 static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); 580 static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); 581 static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); 582 static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); 583} 584 585int main() { 586 test_copy_assignment_empty_empty(); 587 test_copy_assignment_non_empty_empty(); 588 test_copy_assignment_empty_non_empty(); 589 test_copy_assignment_same_index(); 590 test_copy_assignment_different_index(); 591 test_copy_assignment_sfinae(); 592 test_copy_assignment_not_noexcept(); 593 test_constexpr_copy_assignment_extension(); 594} 595