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 // XFAIL: availability=macosx10.13 14 // XFAIL: availability=macosx10.12 15 // XFAIL: availability=macosx10.11 16 // XFAIL: availability=macosx10.10 17 // XFAIL: availability=macosx10.9 18 // XFAIL: availability=macosx10.8 19 // XFAIL: availability=macosx10.7 20 21 // <variant> 22 23 // template <class ...Types> class variant; 24 25 // variant(variant&&) noexcept(see below); // constexpr in C++20 26 27 #include <cassert> 28 #include <string> 29 #include <type_traits> 30 #include <variant> 31 32 #include "test_macros.h" 33 #include "test_workarounds.h" 34 35 struct ThrowsMove { 36 ThrowsMove(ThrowsMove &&) noexcept(false) {} 37 }; 38 39 struct NoCopy { 40 NoCopy(const NoCopy &) = delete; 41 }; 42 43 struct MoveOnly { 44 int value; 45 MoveOnly(int v) : value(v) {} 46 MoveOnly(const MoveOnly &) = delete; 47 MoveOnly(MoveOnly &&) = default; 48 }; 49 50 struct MoveOnlyNT { 51 int value; 52 MoveOnlyNT(int v) : value(v) {} 53 MoveOnlyNT(const MoveOnlyNT &) = delete; 54 MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; } 55 }; 56 57 struct NTMove { 58 constexpr NTMove(int v) : value(v) {} 59 NTMove(const NTMove &) = delete; 60 NTMove(NTMove &&that) : value(that.value) { that.value = -1; } 61 int value; 62 }; 63 64 static_assert(!std::is_trivially_move_constructible<NTMove>::value, ""); 65 static_assert(std::is_move_constructible<NTMove>::value, ""); 66 67 struct TMove { 68 constexpr TMove(int v) : value(v) {} 69 TMove(const TMove &) = delete; 70 TMove(TMove &&) = default; 71 int value; 72 }; 73 74 static_assert(std::is_trivially_move_constructible<TMove>::value, ""); 75 76 struct TMoveNTCopy { 77 constexpr TMoveNTCopy(int v) : value(v) {} 78 TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {} 79 TMoveNTCopy(TMoveNTCopy&&) = default; 80 int value; 81 }; 82 83 static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, ""); 84 85 #ifndef TEST_HAS_NO_EXCEPTIONS 86 struct MakeEmptyT { 87 static int alive; 88 MakeEmptyT() { ++alive; } 89 MakeEmptyT(const MakeEmptyT &) { 90 ++alive; 91 // Don't throw from the copy constructor since variant's assignment 92 // operator performs a copy before committing to the assignment. 93 } 94 MakeEmptyT(MakeEmptyT &&) { throw 42; } 95 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } 96 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 97 ~MakeEmptyT() { --alive; } 98 }; 99 100 int MakeEmptyT::alive = 0; 101 102 template <class Variant> void makeEmpty(Variant &v) { 103 Variant v2(std::in_place_type<MakeEmptyT>); 104 try { 105 v = std::move(v2); 106 assert(false); 107 } catch (...) { 108 assert(v.valueless_by_exception()); 109 } 110 } 111 #endif // TEST_HAS_NO_EXCEPTIONS 112 113 void test_move_noexcept() { 114 { 115 using V = std::variant<int, long>; 116 static_assert(std::is_nothrow_move_constructible<V>::value, ""); 117 } 118 { 119 using V = std::variant<int, MoveOnly>; 120 static_assert(std::is_nothrow_move_constructible<V>::value, ""); 121 } 122 { 123 using V = std::variant<int, MoveOnlyNT>; 124 static_assert(!std::is_nothrow_move_constructible<V>::value, ""); 125 } 126 { 127 using V = std::variant<int, ThrowsMove>; 128 static_assert(!std::is_nothrow_move_constructible<V>::value, ""); 129 } 130 } 131 132 void test_move_ctor_sfinae() { 133 { 134 using V = std::variant<int, long>; 135 static_assert(std::is_move_constructible<V>::value, ""); 136 } 137 { 138 using V = std::variant<int, MoveOnly>; 139 static_assert(std::is_move_constructible<V>::value, ""); 140 } 141 { 142 using V = std::variant<int, MoveOnlyNT>; 143 static_assert(std::is_move_constructible<V>::value, ""); 144 } 145 { 146 using V = std::variant<int, NoCopy>; 147 static_assert(!std::is_move_constructible<V>::value, ""); 148 } 149 150 // Make sure we properly propagate triviality (see P0602R4). 151 #if TEST_STD_VER > 17 152 { 153 using V = std::variant<int, long>; 154 static_assert(std::is_trivially_move_constructible<V>::value, ""); 155 } 156 { 157 using V = std::variant<int, NTMove>; 158 static_assert(!std::is_trivially_move_constructible<V>::value, ""); 159 static_assert(std::is_move_constructible<V>::value, ""); 160 } 161 { 162 using V = std::variant<int, TMove>; 163 static_assert(std::is_trivially_move_constructible<V>::value, ""); 164 } 165 { 166 using V = std::variant<int, TMoveNTCopy>; 167 static_assert(std::is_trivially_move_constructible<V>::value, ""); 168 } 169 #endif // > C++17 170 } 171 172 template <typename T> 173 struct Result { size_t index; T value; }; 174 175 void test_move_ctor_basic() { 176 { 177 std::variant<int> v(std::in_place_index<0>, 42); 178 std::variant<int> v2 = std::move(v); 179 assert(v2.index() == 0); 180 assert(std::get<0>(v2) == 42); 181 } 182 { 183 std::variant<int, long> v(std::in_place_index<1>, 42); 184 std::variant<int, long> v2 = std::move(v); 185 assert(v2.index() == 1); 186 assert(std::get<1>(v2) == 42); 187 } 188 { 189 std::variant<MoveOnly> v(std::in_place_index<0>, 42); 190 assert(v.index() == 0); 191 std::variant<MoveOnly> v2(std::move(v)); 192 assert(v2.index() == 0); 193 assert(std::get<0>(v2).value == 42); 194 } 195 { 196 std::variant<int, MoveOnly> v(std::in_place_index<1>, 42); 197 assert(v.index() == 1); 198 std::variant<int, MoveOnly> v2(std::move(v)); 199 assert(v2.index() == 1); 200 assert(std::get<1>(v2).value == 42); 201 } 202 { 203 std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42); 204 assert(v.index() == 0); 205 std::variant<MoveOnlyNT> v2(std::move(v)); 206 assert(v2.index() == 0); 207 assert(std::get<0>(v).value == -1); 208 assert(std::get<0>(v2).value == 42); 209 } 210 { 211 std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42); 212 assert(v.index() == 1); 213 std::variant<int, MoveOnlyNT> v2(std::move(v)); 214 assert(v2.index() == 1); 215 assert(std::get<1>(v).value == -1); 216 assert(std::get<1>(v2).value == 42); 217 } 218 219 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). 220 #if TEST_STD_VER > 17 221 { 222 struct { 223 constexpr Result<int> operator()() const { 224 std::variant<int> v(std::in_place_index<0>, 42); 225 std::variant<int> v2 = std::move(v); 226 return {v2.index(), std::get<0>(std::move(v2))}; 227 } 228 } test; 229 constexpr auto result = test(); 230 static_assert(result.index == 0, ""); 231 static_assert(result.value == 42, ""); 232 } 233 { 234 struct { 235 constexpr Result<long> operator()() const { 236 std::variant<int, long> v(std::in_place_index<1>, 42); 237 std::variant<int, long> v2 = std::move(v); 238 return {v2.index(), std::get<1>(std::move(v2))}; 239 } 240 } test; 241 constexpr auto result = test(); 242 static_assert(result.index == 1, ""); 243 static_assert(result.value == 42, ""); 244 } 245 { 246 struct { 247 constexpr Result<TMove> operator()() const { 248 std::variant<TMove> v(std::in_place_index<0>, 42); 249 std::variant<TMove> v2(std::move(v)); 250 return {v2.index(), std::get<0>(std::move(v2))}; 251 } 252 } test; 253 constexpr auto result = test(); 254 static_assert(result.index == 0, ""); 255 static_assert(result.value.value == 42, ""); 256 } 257 { 258 struct { 259 constexpr Result<TMove> operator()() const { 260 std::variant<int, TMove> v(std::in_place_index<1>, 42); 261 std::variant<int, TMove> v2(std::move(v)); 262 return {v2.index(), std::get<1>(std::move(v2))}; 263 } 264 } test; 265 constexpr auto result = test(); 266 static_assert(result.index == 1, ""); 267 static_assert(result.value.value == 42, ""); 268 } 269 { 270 struct { 271 constexpr Result<TMoveNTCopy> operator()() const { 272 std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42); 273 std::variant<TMoveNTCopy> v2(std::move(v)); 274 return {v2.index(), std::get<0>(std::move(v2))}; 275 } 276 } test; 277 constexpr auto result = test(); 278 static_assert(result.index == 0, ""); 279 static_assert(result.value.value == 42, ""); 280 } 281 { 282 struct { 283 constexpr Result<TMoveNTCopy> operator()() const { 284 std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42); 285 std::variant<int, TMoveNTCopy> v2(std::move(v)); 286 return {v2.index(), std::get<1>(std::move(v2))}; 287 } 288 } test; 289 constexpr auto result = test(); 290 static_assert(result.index == 1, ""); 291 static_assert(result.value.value == 42, ""); 292 } 293 #endif // > C++17 294 } 295 296 void test_move_ctor_valueless_by_exception() { 297 #ifndef TEST_HAS_NO_EXCEPTIONS 298 using V = std::variant<int, MakeEmptyT>; 299 V v1; 300 makeEmpty(v1); 301 V v(std::move(v1)); 302 assert(v.valueless_by_exception()); 303 #endif // TEST_HAS_NO_EXCEPTIONS 304 } 305 306 template <size_t Idx> 307 constexpr bool test_constexpr_ctor_imp(std::variant<long, void*, const int> const& v) { 308 auto copy = v; 309 auto v2 = std::move(copy); 310 return v2.index() == v.index() && 311 v2.index() == Idx && 312 std::get<Idx>(v2) == std::get<Idx>(v); 313 } 314 315 void test_constexpr_move_ctor() { 316 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). 317 #if TEST_STD_VER > 17 318 using V = std::variant<long, void*, const int>; 319 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 320 static_assert(std::is_trivially_destructible<V>::value, ""); 321 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 322 static_assert(std::is_trivially_move_constructible<V>::value, ""); 323 static_assert(!std::is_copy_assignable<V>::value, ""); 324 static_assert(!std::is_move_assignable<V>::value, ""); 325 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 326 static_assert(std::is_trivially_copyable<V>::value, ""); 327 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 328 static_assert(std::is_trivially_move_constructible<V>::value, ""); 329 static_assert(test_constexpr_ctor_imp<0>(V(42l)), ""); 330 static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), ""); 331 static_assert(test_constexpr_ctor_imp<2>(V(101)), ""); 332 #endif // > C++17 333 } 334 335 int main() { 336 test_move_ctor_basic(); 337 test_move_ctor_valueless_by_exception(); 338 test_move_noexcept(); 339 test_move_ctor_sfinae(); 340 test_constexpr_move_ctor(); 341 } 342