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); 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 // The following tests are for not-yet-standardized behavior (P0602): 151 { 152 using V = std::variant<int, long>; 153 static_assert(std::is_trivially_move_constructible<V>::value, ""); 154 } 155 { 156 using V = std::variant<int, NTMove>; 157 static_assert(!std::is_trivially_move_constructible<V>::value, ""); 158 static_assert(std::is_move_constructible<V>::value, ""); 159 } 160 { 161 using V = std::variant<int, TMove>; 162 static_assert(std::is_trivially_move_constructible<V>::value, ""); 163 } 164 { 165 using V = std::variant<int, TMoveNTCopy>; 166 static_assert(std::is_trivially_move_constructible<V>::value, ""); 167 } 168 } 169 170 template <typename T> 171 struct Result { size_t index; T value; }; 172 173 void test_move_ctor_basic() { 174 { 175 std::variant<int> v(std::in_place_index<0>, 42); 176 std::variant<int> v2 = std::move(v); 177 assert(v2.index() == 0); 178 assert(std::get<0>(v2) == 42); 179 } 180 { 181 std::variant<int, long> v(std::in_place_index<1>, 42); 182 std::variant<int, long> v2 = std::move(v); 183 assert(v2.index() == 1); 184 assert(std::get<1>(v2) == 42); 185 } 186 { 187 std::variant<MoveOnly> v(std::in_place_index<0>, 42); 188 assert(v.index() == 0); 189 std::variant<MoveOnly> v2(std::move(v)); 190 assert(v2.index() == 0); 191 assert(std::get<0>(v2).value == 42); 192 } 193 { 194 std::variant<int, MoveOnly> v(std::in_place_index<1>, 42); 195 assert(v.index() == 1); 196 std::variant<int, MoveOnly> v2(std::move(v)); 197 assert(v2.index() == 1); 198 assert(std::get<1>(v2).value == 42); 199 } 200 { 201 std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42); 202 assert(v.index() == 0); 203 std::variant<MoveOnlyNT> v2(std::move(v)); 204 assert(v2.index() == 0); 205 assert(std::get<0>(v).value == -1); 206 assert(std::get<0>(v2).value == 42); 207 } 208 { 209 std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42); 210 assert(v.index() == 1); 211 std::variant<int, MoveOnlyNT> v2(std::move(v)); 212 assert(v2.index() == 1); 213 assert(std::get<1>(v).value == -1); 214 assert(std::get<1>(v2).value == 42); 215 } 216 217 // The following tests are for not-yet-standardized behavior (P0602): 218 { 219 struct { 220 constexpr Result<int> operator()() const { 221 std::variant<int> v(std::in_place_index<0>, 42); 222 std::variant<int> v2 = std::move(v); 223 return {v2.index(), std::get<0>(std::move(v2))}; 224 } 225 } test; 226 constexpr auto result = test(); 227 static_assert(result.index == 0, ""); 228 static_assert(result.value == 42, ""); 229 } 230 { 231 struct { 232 constexpr Result<long> operator()() const { 233 std::variant<int, long> v(std::in_place_index<1>, 42); 234 std::variant<int, long> v2 = std::move(v); 235 return {v2.index(), std::get<1>(std::move(v2))}; 236 } 237 } test; 238 constexpr auto result = test(); 239 static_assert(result.index == 1, ""); 240 static_assert(result.value == 42, ""); 241 } 242 { 243 struct { 244 constexpr Result<TMove> operator()() const { 245 std::variant<TMove> v(std::in_place_index<0>, 42); 246 std::variant<TMove> v2(std::move(v)); 247 return {v2.index(), std::get<0>(std::move(v2))}; 248 } 249 } test; 250 constexpr auto result = test(); 251 static_assert(result.index == 0, ""); 252 static_assert(result.value.value == 42, ""); 253 } 254 { 255 struct { 256 constexpr Result<TMove> operator()() const { 257 std::variant<int, TMove> v(std::in_place_index<1>, 42); 258 std::variant<int, TMove> v2(std::move(v)); 259 return {v2.index(), std::get<1>(std::move(v2))}; 260 } 261 } test; 262 constexpr auto result = test(); 263 static_assert(result.index == 1, ""); 264 static_assert(result.value.value == 42, ""); 265 } 266 { 267 struct { 268 constexpr Result<TMoveNTCopy> operator()() const { 269 std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42); 270 std::variant<TMoveNTCopy> v2(std::move(v)); 271 return {v2.index(), std::get<0>(std::move(v2))}; 272 } 273 } test; 274 constexpr auto result = test(); 275 static_assert(result.index == 0, ""); 276 static_assert(result.value.value == 42, ""); 277 } 278 { 279 struct { 280 constexpr Result<TMoveNTCopy> operator()() const { 281 std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42); 282 std::variant<int, TMoveNTCopy> v2(std::move(v)); 283 return {v2.index(), std::get<1>(std::move(v2))}; 284 } 285 } test; 286 constexpr auto result = test(); 287 static_assert(result.index == 1, ""); 288 static_assert(result.value.value == 42, ""); 289 } 290 } 291 292 void test_move_ctor_valueless_by_exception() { 293 #ifndef TEST_HAS_NO_EXCEPTIONS 294 using V = std::variant<int, MakeEmptyT>; 295 V v1; 296 makeEmpty(v1); 297 V v(std::move(v1)); 298 assert(v.valueless_by_exception()); 299 #endif // TEST_HAS_NO_EXCEPTIONS 300 } 301 302 template <size_t Idx> 303 constexpr bool test_constexpr_ctor_extension_imp( 304 std::variant<long, void*, const int> const& v) 305 { 306 auto copy = v; 307 auto v2 = std::move(copy); 308 return v2.index() == v.index() && 309 v2.index() == Idx && 310 std::get<Idx>(v2) == std::get<Idx>(v); 311 } 312 313 void test_constexpr_move_ctor_extension() { 314 // NOTE: This test is for not yet standardized behavior. (P0602) 315 using V = std::variant<long, void*, const int>; 316 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 317 static_assert(std::is_trivially_destructible<V>::value, ""); 318 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 319 static_assert(std::is_trivially_move_constructible<V>::value, ""); 320 static_assert(!std::is_copy_assignable<V>::value, ""); 321 static_assert(!std::is_move_assignable<V>::value, ""); 322 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 323 static_assert(std::is_trivially_copyable<V>::value, ""); 324 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 325 static_assert(std::is_trivially_move_constructible<V>::value, ""); 326 static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); 327 static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); 328 static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), ""); 329 } 330 331 int main() { 332 test_move_ctor_basic(); 333 test_move_ctor_valueless_by_exception(); 334 test_move_noexcept(); 335 test_move_ctor_sfinae(); 336 test_constexpr_move_ctor_extension(); 337 } 338