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