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