// -*- C++ -*- //===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14 // Clang 3.8 doesn't generate constexpr special members correctly. // XFAIL: clang-3.8, apple-clang-7, apple-clang-8 // // template class variant; // variant& operator=(variant&&) noexcept(see below); #include #include #include "test_macros.h" 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::value, ""); static_assert(std::is_move_assignable::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::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, ""); void test_move_assignment_sfinae() { { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); } { using V = std::variant; static_assert(!std::is_trivially_move_assignable::value, ""); static_assert(std::is_move_assignable::value, ""); } { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); } { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); } } template struct Result { size_t index; T value; }; void test_move_assignment_same_index() { { struct { constexpr Result operator()() const { using V = std::variant; 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 operator()() const { using V = std::variant; 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 operator()() const { using V = std::variant; V v(std::in_place_type, 43); V v2(std::in_place_type, 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() { { struct { constexpr Result operator()() const { using V = std::variant; 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 operator()() const { using V = std::variant; V v(std::in_place_type, 43); V v2(std::in_place_type, 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 constexpr bool test_constexpr_assign_extension_imp( std::variant&& v, ValueType&& new_value) { std::variant v2( std::forward(new_value)); const auto cp = v2; v = std::move(v2); return v.index() == NewIdx && std::get(v) == std::get(cp); } void test_constexpr_move_assignment_extension() { #ifdef _LIBCPP_VERSION using V = std::variant; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_assignable::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), ""); #endif } int main() { test_move_assignment_same_index(); test_move_assignment_different_index(); test_move_assignment_sfinae(); test_constexpr_move_assignment_extension(); }