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 // <variant> 18 19 // template <class ...Types> class variant; 20 21 // variant& operator=(variant&&) noexcept(see below); 22 23 #include <type_traits> 24 #include <variant> 25 26 #include "test_macros.h" 27 28 struct NTMoveAssign { 29 constexpr NTMoveAssign(int v) : value(v) {} 30 NTMoveAssign(const NTMoveAssign &) = default; 31 NTMoveAssign(NTMoveAssign &&) = default; 32 NTMoveAssign &operator=(const NTMoveAssign &that) = default; 33 NTMoveAssign &operator=(NTMoveAssign &&that) { 34 value = that.value; 35 that.value = -1; 36 return *this; 37 }; 38 int value; 39 }; 40 41 static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, ""); 42 static_assert(std::is_move_assignable<NTMoveAssign>::value, ""); 43 44 struct TMoveAssign { 45 constexpr TMoveAssign(int v) : value(v) {} 46 TMoveAssign(const TMoveAssign &) = delete; 47 TMoveAssign(TMoveAssign &&) = default; 48 TMoveAssign &operator=(const TMoveAssign &) = delete; 49 TMoveAssign &operator=(TMoveAssign &&) = default; 50 int value; 51 }; 52 53 static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, ""); 54 55 struct TMoveAssignNTCopyAssign { 56 constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} 57 TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; 58 TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; 59 TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { 60 value = that.value; 61 return *this; 62 } 63 TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; 64 int value; 65 }; 66 67 static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, ""); 68 69 void test_move_assignment_sfinae() { 70 { 71 using V = std::variant<int, long>; 72 static_assert(std::is_trivially_move_assignable<V>::value, ""); 73 } 74 { 75 using V = std::variant<int, NTMoveAssign>; 76 static_assert(!std::is_trivially_move_assignable<V>::value, ""); 77 static_assert(std::is_move_assignable<V>::value, ""); 78 } 79 { 80 using V = std::variant<int, TMoveAssign>; 81 static_assert(std::is_trivially_move_assignable<V>::value, ""); 82 } 83 { 84 using V = std::variant<int, TMoveAssignNTCopyAssign>; 85 static_assert(std::is_trivially_move_assignable<V>::value, ""); 86 } 87 } 88 89 template <typename T> struct Result { size_t index; T value; }; 90 91 void test_move_assignment_same_index() { 92 { 93 struct { 94 constexpr Result<int> operator()() const { 95 using V = std::variant<int>; 96 V v(43); 97 V v2(42); 98 v = std::move(v2); 99 return {v.index(), std::get<0>(v)}; 100 } 101 } test; 102 constexpr auto result = test(); 103 static_assert(result.index == 0, ""); 104 static_assert(result.value == 42, ""); 105 } 106 { 107 struct { 108 constexpr Result<long> operator()() const { 109 using V = std::variant<int, long, unsigned>; 110 V v(43l); 111 V v2(42l); 112 v = std::move(v2); 113 return {v.index(), std::get<1>(v)}; 114 } 115 } test; 116 constexpr auto result = test(); 117 static_assert(result.index == 1, ""); 118 static_assert(result.value == 42l, ""); 119 } 120 { 121 struct { 122 constexpr Result<int> operator()() const { 123 using V = std::variant<int, TMoveAssign, unsigned>; 124 V v(std::in_place_type<TMoveAssign>, 43); 125 V v2(std::in_place_type<TMoveAssign>, 42); 126 v = std::move(v2); 127 return {v.index(), std::get<1>(v).value}; 128 } 129 } test; 130 constexpr auto result = test(); 131 static_assert(result.index == 1, ""); 132 static_assert(result.value == 42, ""); 133 } 134 } 135 136 void test_move_assignment_different_index() { 137 { 138 struct { 139 constexpr Result<long> operator()() const { 140 using V = std::variant<int, long, unsigned>; 141 V v(43); 142 V v2(42l); 143 v = std::move(v2); 144 return {v.index(), std::get<1>(v)}; 145 } 146 } test; 147 constexpr auto result = test(); 148 static_assert(result.index == 1, ""); 149 static_assert(result.value == 42l, ""); 150 } 151 { 152 struct { 153 constexpr Result<long> operator()() const { 154 using V = std::variant<int, TMoveAssign, unsigned>; 155 V v(std::in_place_type<unsigned>, 43); 156 V v2(std::in_place_type<TMoveAssign>, 42); 157 v = std::move(v2); 158 return {v.index(), std::get<1>(v).value}; 159 } 160 } test; 161 constexpr auto result = test(); 162 static_assert(result.index == 1, ""); 163 static_assert(result.value == 42, ""); 164 } 165 } 166 167 168 template <size_t NewIdx, class ValueType> 169 constexpr bool test_constexpr_assign_extension_imp( 170 std::variant<long, void*, int>&& v, ValueType&& new_value) 171 { 172 std::variant<long, void*, int> v2( 173 std::forward<ValueType>(new_value)); 174 const auto cp = v2; 175 v = std::move(v2); 176 return v.index() == NewIdx && 177 std::get<NewIdx>(v) == std::get<NewIdx>(cp); 178 } 179 180 void test_constexpr_move_assignment_extension() { 181 #ifdef _LIBCPP_VERSION 182 using V = std::variant<long, void*, int>; 183 static_assert(std::is_trivially_copyable<V>::value, ""); 184 static_assert(std::is_trivially_move_assignable<V>::value, ""); 185 static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); 186 static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); 187 static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); 188 static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); 189 #endif 190 } 191 192 int main() { 193 test_move_assignment_same_index(); 194 test_move_assignment_different_index(); 195 test_move_assignment_sfinae(); 196 test_constexpr_move_assignment_extension(); 197 } 198