1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 // UNSUPPORTED: c++03, c++11, c++14 11 12 // Throwing bad_variant_access is supported starting in macosx10.13 13 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.12 && !no-exceptions 14 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.11 && !no-exceptions 15 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.10 && !no-exceptions 16 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.9 && !no-exceptions 17 18 // <variant> 19 20 // template <class ...Types> class variant; 21 22 // variant(variant const&); // constexpr in C++20 23 24 #include <cassert> 25 #include <type_traits> 26 #include <variant> 27 28 #include "test_macros.h" 29 #include "test_workarounds.h" 30 31 struct NonT { 32 NonT(int v) : value(v) {} 33 NonT(const NonT &o) : value(o.value) {} 34 int value; 35 }; 36 static_assert(!std::is_trivially_copy_constructible<NonT>::value, ""); 37 38 struct NoCopy { 39 NoCopy(const NoCopy &) = delete; 40 }; 41 42 struct MoveOnly { 43 MoveOnly(const MoveOnly &) = delete; 44 MoveOnly(MoveOnly &&) = default; 45 }; 46 47 struct MoveOnlyNT { 48 MoveOnlyNT(const MoveOnlyNT &) = delete; 49 MoveOnlyNT(MoveOnlyNT &&) {} 50 }; 51 52 struct NTCopy { 53 constexpr NTCopy(int v) : value(v) {} 54 NTCopy(const NTCopy &that) : value(that.value) {} 55 NTCopy(NTCopy &&) = delete; 56 int value; 57 }; 58 59 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, ""); 60 static_assert(std::is_copy_constructible<NTCopy>::value, ""); 61 62 struct TCopy { 63 constexpr TCopy(int v) : value(v) {} 64 TCopy(TCopy const &) = default; 65 TCopy(TCopy &&) = delete; 66 int value; 67 }; 68 69 static_assert(std::is_trivially_copy_constructible<TCopy>::value, ""); 70 71 struct TCopyNTMove { 72 constexpr TCopyNTMove(int v) : value(v) {} 73 TCopyNTMove(const TCopyNTMove&) = default; 74 TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } 75 int value; 76 }; 77 78 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, ""); 79 80 #ifndef TEST_HAS_NO_EXCEPTIONS 81 struct MakeEmptyT { 82 static int alive; 83 MakeEmptyT() { ++alive; } 84 MakeEmptyT(const MakeEmptyT &) { 85 ++alive; 86 // Don't throw from the copy constructor since variant's assignment 87 // operator performs a copy before committing to the assignment. 88 } 89 MakeEmptyT(MakeEmptyT &&) { throw 42; } 90 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } 91 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 92 ~MakeEmptyT() { --alive; } 93 }; 94 95 int MakeEmptyT::alive = 0; 96 97 template <class Variant> void makeEmpty(Variant &v) { 98 Variant v2(std::in_place_type<MakeEmptyT>); 99 try { 100 v = std::move(v2); 101 assert(false); 102 } catch (...) { 103 assert(v.valueless_by_exception()); 104 } 105 } 106 #endif // TEST_HAS_NO_EXCEPTIONS 107 108 void test_copy_ctor_sfinae() { 109 { 110 using V = std::variant<int, long>; 111 static_assert(std::is_copy_constructible<V>::value, ""); 112 } 113 { 114 using V = std::variant<int, NoCopy>; 115 static_assert(!std::is_copy_constructible<V>::value, ""); 116 } 117 { 118 using V = std::variant<int, MoveOnly>; 119 static_assert(!std::is_copy_constructible<V>::value, ""); 120 } 121 { 122 using V = std::variant<int, MoveOnlyNT>; 123 static_assert(!std::is_copy_constructible<V>::value, ""); 124 } 125 126 // Make sure we properly propagate triviality (see P0602R4). 127 #if TEST_STD_VER > 17 128 { 129 using V = std::variant<int, long>; 130 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 131 } 132 { 133 using V = std::variant<int, NTCopy>; 134 static_assert(!std::is_trivially_copy_constructible<V>::value, ""); 135 static_assert(std::is_copy_constructible<V>::value, ""); 136 } 137 { 138 using V = std::variant<int, TCopy>; 139 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 140 } 141 { 142 using V = std::variant<int, TCopyNTMove>; 143 static_assert(std::is_trivially_copy_constructible<V>::value, ""); 144 } 145 #endif // > C++17 146 } 147 148 void test_copy_ctor_basic() { 149 { 150 std::variant<int> v(std::in_place_index<0>, 42); 151 std::variant<int> v2 = v; 152 assert(v2.index() == 0); 153 assert(std::get<0>(v2) == 42); 154 } 155 { 156 std::variant<int, long> v(std::in_place_index<1>, 42); 157 std::variant<int, long> v2 = v; 158 assert(v2.index() == 1); 159 assert(std::get<1>(v2) == 42); 160 } 161 { 162 std::variant<NonT> v(std::in_place_index<0>, 42); 163 assert(v.index() == 0); 164 std::variant<NonT> v2(v); 165 assert(v2.index() == 0); 166 assert(std::get<0>(v2).value == 42); 167 } 168 { 169 std::variant<int, NonT> v(std::in_place_index<1>, 42); 170 assert(v.index() == 1); 171 std::variant<int, NonT> v2(v); 172 assert(v2.index() == 1); 173 assert(std::get<1>(v2).value == 42); 174 } 175 176 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). 177 #if TEST_STD_VER > 17 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 #endif // > C++17 221 } 222 223 void test_copy_ctor_valueless_by_exception() { 224 #ifndef TEST_HAS_NO_EXCEPTIONS 225 using V = std::variant<int, MakeEmptyT>; 226 V v1; 227 makeEmpty(v1); 228 const V &cv1 = v1; 229 V v(cv1); 230 assert(v.valueless_by_exception()); 231 #endif // TEST_HAS_NO_EXCEPTIONS 232 } 233 234 template <size_t Idx> 235 constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) { 236 auto v2 = v; 237 return v2.index() == v.index() && 238 v2.index() == Idx && 239 std::get<Idx>(v2) == std::get<Idx>(v); 240 } 241 242 void test_constexpr_copy_ctor() { 243 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). 244 #if TEST_STD_VER > 17 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_imp<0>(V(42l)), ""); 256 static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), ""); 257 static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), ""); 258 #endif // > C++17 259 } 260 261 int main(int, char**) { 262 test_copy_ctor_basic(); 263 test_copy_ctor_valueless_by_exception(); 264 test_copy_ctor_sfinae(); 265 test_constexpr_copy_ctor(); 266 #if 0 267 // disable this for the moment; it fails on older compilers. 268 // Need to figure out which compilers will support it. 269 { // This is the motivating example from P0739R0 270 std::variant<int, double> v1(3); 271 std::variant v2 = v1; 272 (void) v2; 273 } 274 #endif 275 276 return 0; 277 } 278