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 // <variant> 14 15 // template <class ...Types> class variant; 16 17 // variant(variant&&) noexcept(see below); 18 19 #include <cassert> 20 #include <string> 21 #include <type_traits> 22 #include <variant> 23 24 #include "test_macros.h" 25 26 struct ThrowsMove { 27 ThrowsMove(ThrowsMove &&) noexcept(false) {} 28 }; 29 30 struct NoCopy { 31 NoCopy(const NoCopy &) = delete; 32 }; 33 34 struct MoveOnly { 35 int value; 36 MoveOnly(int v) : value(v) {} 37 MoveOnly(const MoveOnly &) = delete; 38 MoveOnly(MoveOnly &&) = default; 39 }; 40 41 struct MoveOnlyNT { 42 int value; 43 MoveOnlyNT(int v) : value(v) {} 44 MoveOnlyNT(const MoveOnlyNT &) = delete; 45 MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; } 46 }; 47 48 #ifndef TEST_HAS_NO_EXCEPTIONS 49 struct MakeEmptyT { 50 static int alive; 51 MakeEmptyT() { ++alive; } 52 MakeEmptyT(const MakeEmptyT &) { 53 ++alive; 54 // Don't throw from the copy constructor since variant's assignment 55 // operator performs a copy before committing to the assignment. 56 } 57 MakeEmptyT(MakeEmptyT &&) { throw 42; } 58 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } 59 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 60 ~MakeEmptyT() { --alive; } 61 }; 62 63 int MakeEmptyT::alive = 0; 64 65 template <class Variant> void makeEmpty(Variant &v) { 66 Variant v2(std::in_place_type<MakeEmptyT>); 67 try { 68 v = v2; 69 assert(false); 70 } catch (...) { 71 assert(v.valueless_by_exception()); 72 } 73 } 74 #endif // TEST_HAS_NO_EXCEPTIONS 75 76 void test_move_noexcept() { 77 { 78 using V = std::variant<int, long>; 79 static_assert(std::is_nothrow_move_constructible<V>::value, ""); 80 } 81 { 82 using V = std::variant<int, MoveOnly>; 83 static_assert(std::is_nothrow_move_constructible<V>::value, ""); 84 } 85 { 86 using V = std::variant<int, MoveOnlyNT>; 87 static_assert(!std::is_nothrow_move_constructible<V>::value, ""); 88 } 89 { 90 using V = std::variant<int, ThrowsMove>; 91 static_assert(!std::is_nothrow_move_constructible<V>::value, ""); 92 } 93 } 94 95 void test_move_ctor_sfinae() { 96 { 97 using V = std::variant<int, long>; 98 static_assert(std::is_move_constructible<V>::value, ""); 99 } 100 { 101 using V = std::variant<int, MoveOnly>; 102 static_assert(std::is_move_constructible<V>::value, ""); 103 } 104 { 105 using V = std::variant<int, MoveOnlyNT>; 106 static_assert(std::is_move_constructible<V>::value, ""); 107 } 108 { 109 using V = std::variant<int, NoCopy>; 110 static_assert(!std::is_move_constructible<V>::value, ""); 111 } 112 } 113 114 void test_move_ctor_basic() { 115 { 116 std::variant<int> v(std::in_place_index<0>, 42); 117 std::variant<int> v2 = std::move(v); 118 assert(v2.index() == 0); 119 assert(std::get<0>(v2) == 42); 120 } 121 { 122 std::variant<int, long> v(std::in_place_index<1>, 42); 123 std::variant<int, long> v2 = std::move(v); 124 assert(v2.index() == 1); 125 assert(std::get<1>(v2) == 42); 126 } 127 { 128 std::variant<MoveOnly> v(std::in_place_index<0>, 42); 129 assert(v.index() == 0); 130 std::variant<MoveOnly> v2(std::move(v)); 131 assert(v2.index() == 0); 132 assert(std::get<0>(v2).value == 42); 133 } 134 { 135 std::variant<int, MoveOnly> v(std::in_place_index<1>, 42); 136 assert(v.index() == 1); 137 std::variant<int, MoveOnly> v2(std::move(v)); 138 assert(v2.index() == 1); 139 assert(std::get<1>(v2).value == 42); 140 } 141 { 142 std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42); 143 assert(v.index() == 0); 144 std::variant<MoveOnlyNT> v2(std::move(v)); 145 assert(v2.index() == 0); 146 assert(std::get<0>(v).value == -1); 147 assert(std::get<0>(v2).value == 42); 148 } 149 { 150 std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42); 151 assert(v.index() == 1); 152 std::variant<int, MoveOnlyNT> v2(std::move(v)); 153 assert(v2.index() == 1); 154 assert(std::get<1>(v).value == -1); 155 assert(std::get<1>(v2).value == 42); 156 } 157 } 158 159 void test_move_ctor_valueless_by_exception() { 160 #ifndef TEST_HAS_NO_EXCEPTIONS 161 using V = std::variant<int, MakeEmptyT>; 162 V v1; 163 makeEmpty(v1); 164 V v(std::move(v1)); 165 assert(v.valueless_by_exception()); 166 #endif 167 } 168 169 template <size_t Idx> 170 constexpr bool test_constexpr_ctor_extension_imp( 171 std::variant<long, void*, const int> const& v) 172 { 173 auto copy = v; 174 auto v2 = std::move(copy); 175 return v2.index() == v.index() && 176 v2.index() == Idx && 177 std::get<Idx>(v2) == std::get<Idx>(v); 178 } 179 180 void test_constexpr_move_ctor_extension() { 181 #ifdef _LIBCPP_VERSION 182 using V = std::variant<long, void*, const int>; 183 static_assert(std::is_trivially_copyable<V>::value, ""); 184 static_assert(std::is_trivially_move_constructible<V>::value, ""); 185 static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); 186 static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); 187 static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), ""); 188 #endif 189 } 190 191 int main() { 192 test_move_ctor_basic(); 193 test_move_ctor_valueless_by_exception(); 194 test_move_noexcept(); 195 test_move_ctor_sfinae(); 196 test_constexpr_move_ctor_extension(); 197 } 198