diff options
Diffstat (limited to 'test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp')
-rw-r--r-- | test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp | 199 |
1 files changed, 191 insertions, 8 deletions
diff --git a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp index c1ba87be76d1..c410b4b8f3ef 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -10,6 +10,10 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 +// The following compilers don't generate constexpr special members correctly. +// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 +// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 + // XFAIL: with_system_cxx_lib=macosx10.12 // XFAIL: with_system_cxx_lib=macosx10.11 // XFAIL: with_system_cxx_lib=macosx10.10 @@ -91,6 +95,60 @@ struct MoveAssign { int MoveAssign::move_construct = 0; int MoveAssign::move_assign = 0; +struct NTMoveAssign { + constexpr NTMoveAssign(int v) : value(v) {} + NTMoveAssign(const NTMoveAssign &) = default; + NTMoveAssign(NTMoveAssign &&) = default; + NTMoveAssign &operator=(const NTMoveAssign &that) = default; + NTMoveAssign &operator=(NTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + }; + int value; +}; + +static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, ""); +static_assert(std::is_move_assignable<NTMoveAssign>::value, ""); + +struct TMoveAssign { + constexpr TMoveAssign(int v) : value(v) {} + TMoveAssign(const TMoveAssign &) = delete; + TMoveAssign(TMoveAssign &&) = default; + TMoveAssign &operator=(const TMoveAssign &) = delete; + TMoveAssign &operator=(TMoveAssign &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, ""); + +struct TMoveAssignNTCopyAssign { + constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} + TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; + TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; + TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { + value = that.value; + return *this; + } + TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, ""); + +struct TrivialCopyNontrivialMove { + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { + return *this; + } +}; + +static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, ""); +static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, ""); + + void test_move_assignment_noexcept() { { using V = std::variant<int>; @@ -124,10 +182,8 @@ void test_move_assignment_sfinae() { static_assert(std::is_move_assignable<V>::value, ""); } { - // variant only provides move assignment when both the move constructor - // and move assignment operator are well formed. using V = std::variant<int, CopyOnly>; - static_assert(!std::is_move_assignable<V>::value, ""); + static_assert(std::is_move_assignable<V>::value, ""); } { using V = std::variant<int, NoCopy>; @@ -147,6 +203,33 @@ void test_move_assignment_sfinae() { using V = std::variant<int, MoveAssignOnly>; static_assert(!std::is_move_assignable<V>::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant<int, long>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, NTMoveAssign>; + static_assert(!std::is_trivially_move_assignable<V>::value, ""); + static_assert(std::is_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TMoveAssign>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TMoveAssignNTCopyAssign>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TrivialCopyNontrivialMove>; + static_assert(!std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, CopyOnly>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } } void test_move_assignment_empty_empty() { @@ -163,7 +246,7 @@ void test_move_assignment_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_non_empty_empty() { @@ -189,7 +272,7 @@ void test_move_assignment_non_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_empty_non_empty() { @@ -215,9 +298,11 @@ void test_move_assignment_empty_non_empty() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } +template <typename T> struct Result { size_t index; T value; }; + void test_move_assignment_same_index() { { using V = std::variant<int>; @@ -264,7 +349,51 @@ void test_move_assignment_same_index() { assert(v1.index() == 1); assert(&std::get<1>(v1) == &mref); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int>; + V v(43); + V v2(42); + v = std::move(v2); + return {v.index(), std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43l); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int, TMoveAssign, unsigned>; + V v(std::in_place_type<TMoveAssign>, 43); + V v2(std::in_place_type<TMoveAssign>, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } void test_move_assignment_different_index() { @@ -312,7 +441,60 @@ void test_move_assignment_different_index() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, TMoveAssign, unsigned>; + V v(std::in_place_type<unsigned>, 43); + V v2(std::in_place_type<TMoveAssign>, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template <size_t NewIdx, class ValueType> +constexpr bool test_constexpr_assign_extension_imp( + std::variant<long, void*, int>&& v, ValueType&& new_value) +{ + std::variant<long, void*, int> v2( + std::forward<ValueType>(new_value)); + const auto cp = v2; + v = std::move(v2); + return v.index() == NewIdx && + std::get<NewIdx>(v) == std::get<NewIdx>(cp); +} + +void test_constexpr_move_assignment_extension() { + // The following tests are for not-yet-standardized behavior (P0602): + using V = std::variant<long, void*, int>; + static_assert(std::is_trivially_copyable<V>::value, ""); + static_assert(std::is_trivially_move_assignable<V>::value, ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); } int main() { @@ -323,4 +505,5 @@ int main() { test_move_assignment_different_index(); test_move_assignment_sfinae(); test_move_assignment_noexcept(); + test_constexpr_move_assignment_extension(); } |