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 const&); 26 27 #include <cassert> 28 #include <type_traits> 29 #include <variant> 30 31 #include "test_macros.h" 32 #include "test_workarounds.h" 33 34 struct NonT { 35 NonT(int v) : value(v) {} 36 NonT(const NonT &o) : value(o.value) {} 37 int value; 38 }; 39 static_assert(!std::is_trivially_copy_constructible<NonT>::value, ""); 40 41 struct NoCopy { 42 NoCopy(const NoCopy &) = delete; 43 }; 44 45 struct MoveOnly { 46 MoveOnly(const MoveOnly &) = delete; 47 MoveOnly(MoveOnly &&) = default; 48 }; 49 50 struct MoveOnlyNT { 51 MoveOnlyNT(const MoveOnlyNT &) = delete; 52 MoveOnlyNT(MoveOnlyNT &&) {} 53 }; 54 55 struct NTCopy { 56 constexpr NTCopy(int v) : value(v) {} 57 NTCopy(const NTCopy &that) : value(that.value) {} 58 NTCopy(NTCopy &&) = delete; 59 int value; 60 }; 61 62 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, ""); 63 static_assert(std::is_copy_constructible<NTCopy>::value, ""); 64 65 struct TCopy { 66 constexpr TCopy(int v) : value(v) {} 67 TCopy(TCopy const &) = default; 68 TCopy(TCopy &&) = delete; 69 int value; 70 }; 71 72 static_assert(std::is_trivially_copy_constructible<TCopy>::value, ""); 73 74 struct TCopyNTMove { 75 constexpr TCopyNTMove(int v) : value(v) {} 76 TCopyNTMove(const TCopyNTMove&) = default; 77 TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } 78 int value; 79 }; 80 81 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, ""); 82 83 #ifndef TEST_HAS_NO_EXCEPTIONS 84 struct MakeEmptyT { 85 static int alive; 86 MakeEmptyT() { ++alive; } 87 MakeEmptyT(const MakeEmptyT &) { 88 ++alive; 89 // Don't throw from the copy constructor since variant's assignment 90 // operator performs a copy before committing to the assignment. 91 } 92 MakeEmptyT(MakeEmptyT &&) { throw 42; } 93 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } 94 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 95 ~MakeEmptyT() { --alive; } 96 }; 97 98 int MakeEmptyT::alive = 0; 99 100 template <class Variant> void makeEmpty(Variant &v) { 101 Variant v2(std::in_place_type<MakeEmptyT>); 102 try { 103 v = std::move(v2); 104 assert(false); 105 } catch (...) { 106 assert(v.valueless_by_exception()); 107 } 108 } 109 #endif // TEST_HAS_NO_EXCEPTIONS 110 111 void test_copy_ctor_sfinae() { 112 { 113 using V = std::variant<int, long>; 114 static_assert(std::is_copy_constructible<V>::value, ""); 115 } 116 { 117 using V = std::variant<int, NoCopy>; 118 static_assert(!std::is_copy_constructible<V>::value, ""); 119 } 120 { 121 using V = std::variant<int, MoveOnly>; 122 static_assert(!std::is_copy_constructible<V>::value, ""); 123 } 124 { 125 using V = std::variant<int, MoveOnlyNT>; 126 static_assert(!std::is_copy_constructible<V>::value, ""); 127 } 128 129 // The following tests are for not-yet-standardized behavior (P0602): 130 { 131 using V = std::variant<int, long>; 132 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 133 } 134 { 135 using V = std::variant<int, NTCopy>; 136 static_assert(!std::is_trivially_copy_constructible<V>::value, ""); 137 static_assert(std::is_copy_constructible<V>::value, ""); 138 } 139 { 140 using V = std::variant<int, TCopy>; 141 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 142 } 143 { 144 using V = std::variant<int, TCopyNTMove>; 145 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 146 } 147 } 148 149 void test_copy_ctor_basic() { 150 { 151 std::variant<int> v(std::in_place_index<0>, 42); 152 std::variant<int> v2 = v; 153 assert(v2.index() == 0); 154 assert(std::get<0>(v2) == 42); 155 } 156 { 157 std::variant<int, long> v(std::in_place_index<1>, 42); 158 std::variant<int, long> v2 = v; 159 assert(v2.index() == 1); 160 assert(std::get<1>(v2) == 42); 161 } 162 { 163 std::variant<NonT> v(std::in_place_index<0>, 42); 164 assert(v.index() == 0); 165 std::variant<NonT> v2(v); 166 assert(v2.index() == 0); 167 assert(std::get<0>(v2).value == 42); 168 } 169 { 170 std::variant<int, NonT> v(std::in_place_index<1>, 42); 171 assert(v.index() == 1); 172 std::variant<int, NonT> v2(v); 173 assert(v2.index() == 1); 174 assert(std::get<1>(v2).value == 42); 175 } 176 177 // The following tests are for not-yet-standardized behavior (P0602): 178 { 179 constexpr std::variant<int> v(std::in_place_index<0>, 42); 180 static_assert(v.index() == 0, ""); 181 constexpr std::variant<int> v2 = v; 182 static_assert(v2.index() == 0, ""); 183 static_assert(std::get<0>(v2) == 42, ""); 184 } 185 { 186 constexpr std::variant<int, long> v(std::in_place_index<1>, 42); 187 static_assert(v.index() == 1, ""); 188 constexpr std::variant<int, long> v2 = v; 189 static_assert(v2.index() == 1, ""); 190 static_assert(std::get<1>(v2) == 42, ""); 191 } 192 { 193 constexpr std::variant<TCopy> v(std::in_place_index<0>, 42); 194 static_assert(v.index() == 0, ""); 195 constexpr std::variant<TCopy> v2(v); 196 static_assert(v2.index() == 0, ""); 197 static_assert(std::get<0>(v2).value == 42, ""); 198 } 199 { 200 constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42); 201 static_assert(v.index() == 1, ""); 202 constexpr std::variant<int, TCopy> v2(v); 203 static_assert(v2.index() == 1, ""); 204 static_assert(std::get<1>(v2).value == 42, ""); 205 } 206 { 207 constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42); 208 static_assert(v.index() == 0, ""); 209 constexpr std::variant<TCopyNTMove> v2(v); 210 static_assert(v2.index() == 0, ""); 211 static_assert(std::get<0>(v2).value == 42, ""); 212 } 213 { 214 constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42); 215 static_assert(v.index() == 1, ""); 216 constexpr std::variant<int, TCopyNTMove> v2(v); 217 static_assert(v2.index() == 1, ""); 218 static_assert(std::get<1>(v2).value == 42, ""); 219 } 220 } 221 222 void test_copy_ctor_valueless_by_exception() { 223 #ifndef TEST_HAS_NO_EXCEPTIONS 224 using V = std::variant<int, MakeEmptyT>; 225 V v1; 226 makeEmpty(v1); 227 const V &cv1 = v1; 228 V v(cv1); 229 assert(v.valueless_by_exception()); 230 #endif // TEST_HAS_NO_EXCEPTIONS 231 } 232 233 template <size_t Idx> 234 constexpr bool test_constexpr_copy_ctor_extension_imp( 235 std::variant<long, void*, const int> const& v) 236 { 237 auto v2 = v; 238 return v2.index() == v.index() && 239 v2.index() == Idx && 240 std::get<Idx>(v2) == std::get<Idx>(v); 241 } 242 243 void test_constexpr_copy_ctor_extension() { 244 // NOTE: This test is for not yet standardized behavior. (P0602) 245 using V = std::variant<long, void*, const int>; 246 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 247 static_assert(std::is_trivially_destructible<V>::value, ""); 248 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 249 static_assert(std::is_trivially_move_constructible<V>::value, ""); 250 static_assert(!std::is_copy_assignable<V>::value, ""); 251 static_assert(!std::is_move_assignable<V>::value, ""); 252 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 253 static_assert(std::is_trivially_copyable<V>::value, ""); 254 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE 255 static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); 256 static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); 257 static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); 258 } 259 260 int main() { 261 test_copy_ctor_basic(); 262 test_copy_ctor_valueless_by_exception(); 263 test_copy_ctor_sfinae(); 264 test_constexpr_copy_ctor_extension(); 265 #if 0 266 // disable this for the moment; it fails on older compilers. 267 // Need to figure out which compilers will support it. 268 { // This is the motivating example from P0739R0 269 std::variant<int, double> v1(3); 270 std::variant v2 = v1; 271 (void) v2; 272 } 273 #endif 274 } 275