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