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