1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14 10 11 // Throwing bad_variant_access is supported starting in macosx10.13 12 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions 13 14 // <variant> 15 16 // template <class ...Types> class variant; 17 18 // template <class T> 19 // variant& operator=(T&&) noexcept(see below); 20 21 #include <cassert> 22 #include <string> 23 #include <type_traits> 24 #include <variant> 25 #include <memory> 26 27 #include "test_macros.h" 28 #include "variant_test_helpers.h" 29 30 namespace MetaHelpers { 31 32 struct Dummy { 33 Dummy() = default; 34 }; 35 36 struct ThrowsCtorT { 37 ThrowsCtorT(int) noexcept(false) {} 38 ThrowsCtorT &operator=(int) noexcept { return *this; } 39 }; 40 41 struct ThrowsAssignT { 42 ThrowsAssignT(int) noexcept {} 43 ThrowsAssignT &operator=(int) noexcept(false) { return *this; } 44 }; 45 46 struct NoThrowT { 47 NoThrowT(int) noexcept {} 48 NoThrowT &operator=(int) noexcept { return *this; } 49 }; 50 51 } // namespace MetaHelpers 52 53 namespace RuntimeHelpers { 54 #ifndef TEST_HAS_NO_EXCEPTIONS 55 56 struct ThrowsCtorT { 57 int value; 58 ThrowsCtorT() : value(0) {} 59 ThrowsCtorT(int) noexcept(false) { throw 42; } 60 ThrowsCtorT &operator=(int v) noexcept { 61 value = v; 62 return *this; 63 } 64 }; 65 66 struct MoveCrashes { 67 int value; 68 MoveCrashes(int v = 0) noexcept : value{v} {} 69 MoveCrashes(MoveCrashes &&) noexcept { assert(false); } 70 MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } 71 MoveCrashes &operator=(int v) noexcept { 72 value = v; 73 return *this; 74 } 75 }; 76 77 struct ThrowsCtorTandMove { 78 int value; 79 ThrowsCtorTandMove() : value(0) {} 80 ThrowsCtorTandMove(int) noexcept(false) { throw 42; } 81 ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } 82 ThrowsCtorTandMove &operator=(int v) noexcept { 83 value = v; 84 return *this; 85 } 86 }; 87 88 struct ThrowsAssignT { 89 int value; 90 ThrowsAssignT() : value(0) {} 91 ThrowsAssignT(int v) noexcept : value(v) {} 92 ThrowsAssignT &operator=(int) noexcept(false) { throw 42; } 93 }; 94 95 struct NoThrowT { 96 int value; 97 NoThrowT() : value(0) {} 98 NoThrowT(int v) noexcept : value(v) {} 99 NoThrowT &operator=(int v) noexcept { 100 value = v; 101 return *this; 102 } 103 }; 104 105 #endif // !defined(TEST_HAS_NO_EXCEPTIONS) 106 } // namespace RuntimeHelpers 107 108 void test_T_assignment_noexcept() { 109 using namespace MetaHelpers; 110 { 111 using V = std::variant<Dummy, NoThrowT>; 112 static_assert(std::is_nothrow_assignable<V, int>::value, ""); 113 } 114 { 115 using V = std::variant<Dummy, ThrowsCtorT>; 116 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 117 } 118 { 119 using V = std::variant<Dummy, ThrowsAssignT>; 120 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 121 } 122 } 123 124 void test_T_assignment_sfinae() { 125 { 126 using V = std::variant<long, long long>; 127 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 128 } 129 { 130 using V = std::variant<std::string, std::string>; 131 static_assert(!std::is_assignable<V, const char *>::value, "ambiguous"); 132 } 133 { 134 using V = std::variant<std::string, void *>; 135 static_assert(!std::is_assignable<V, int>::value, "no matching operator="); 136 } 137 { 138 using V = std::variant<std::string, float>; 139 static_assert(std::is_assignable<V, int>::value == VariantAllowsNarrowingConversions, 140 "no matching operator="); 141 } 142 { 143 using V = std::variant<std::unique_ptr<int>, bool>; 144 static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value, 145 "no explicit bool in operator="); 146 struct X { 147 operator void*(); 148 }; 149 static_assert(!std::is_assignable<V, X>::value, 150 "no boolean conversion in operator="); 151 static_assert(!std::is_assignable<V, std::false_type>::value, 152 "no converted to bool in operator="); 153 } 154 { 155 struct X {}; 156 struct Y { 157 operator X(); 158 }; 159 using V = std::variant<X>; 160 static_assert(std::is_assignable<V, Y>::value, 161 "regression on user-defined conversions in operator="); 162 } 163 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 164 { 165 using V = std::variant<int, int &&>; 166 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 167 } 168 { 169 using V = std::variant<int, const int &>; 170 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 171 } 172 #endif // TEST_VARIANT_HAS_NO_REFERENCES 173 } 174 175 void test_T_assignment_basic() { 176 { 177 std::variant<int> v(43); 178 v = 42; 179 assert(v.index() == 0); 180 assert(std::get<0>(v) == 42); 181 } 182 { 183 std::variant<int, long> v(43l); 184 v = 42; 185 assert(v.index() == 0); 186 assert(std::get<0>(v) == 42); 187 v = 43l; 188 assert(v.index() == 1); 189 assert(std::get<1>(v) == 43); 190 } 191 #ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS 192 { 193 std::variant<unsigned, long> v; 194 v = 42; 195 assert(v.index() == 1); 196 assert(std::get<1>(v) == 42); 197 v = 43u; 198 assert(v.index() == 0); 199 assert(std::get<0>(v) == 43); 200 } 201 #endif 202 { 203 std::variant<std::string, bool> v = true; 204 v = "bar"; 205 assert(v.index() == 0); 206 assert(std::get<0>(v) == "bar"); 207 } 208 { 209 std::variant<bool, std::unique_ptr<int>> v; 210 v = nullptr; 211 assert(v.index() == 1); 212 assert(std::get<1>(v) == nullptr); 213 } 214 { 215 std::variant<bool volatile, int> v = 42; 216 v = false; 217 assert(v.index() == 0); 218 assert(!std::get<0>(v)); 219 bool lvt = true; 220 v = lvt; 221 assert(v.index() == 0); 222 assert(std::get<0>(v)); 223 } 224 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 225 { 226 using V = std::variant<int &, int &&, long>; 227 int x = 42; 228 V v(43l); 229 v = x; 230 assert(v.index() == 0); 231 assert(&std::get<0>(v) == &x); 232 v = std::move(x); 233 assert(v.index() == 1); 234 assert(&std::get<1>(v) == &x); 235 // 'long' is selected by FUN(const int &) since 'const int &' cannot bind 236 // to 'int&'. 237 const int &cx = x; 238 v = cx; 239 assert(v.index() == 2); 240 assert(std::get<2>(v) == 42); 241 } 242 #endif // TEST_VARIANT_HAS_NO_REFERENCES 243 } 244 245 void test_T_assignment_performs_construction() { 246 using namespace RuntimeHelpers; 247 #ifndef TEST_HAS_NO_EXCEPTIONS 248 { 249 using V = std::variant<std::string, ThrowsCtorT>; 250 V v(std::in_place_type<std::string>, "hello"); 251 try { 252 v = 42; 253 assert(false); 254 } catch (...) { /* ... */ 255 } 256 assert(v.index() == 0); 257 assert(std::get<0>(v) == "hello"); 258 } 259 { 260 using V = std::variant<ThrowsAssignT, std::string>; 261 V v(std::in_place_type<std::string>, "hello"); 262 v = 42; 263 assert(v.index() == 0); 264 assert(std::get<0>(v).value == 42); 265 } 266 #endif // TEST_HAS_NO_EXCEPTIONS 267 } 268 269 void test_T_assignment_performs_assignment() { 270 using namespace RuntimeHelpers; 271 #ifndef TEST_HAS_NO_EXCEPTIONS 272 { 273 using V = std::variant<ThrowsCtorT>; 274 V v; 275 v = 42; 276 assert(v.index() == 0); 277 assert(std::get<0>(v).value == 42); 278 } 279 { 280 using V = std::variant<ThrowsCtorT, std::string>; 281 V v; 282 v = 42; 283 assert(v.index() == 0); 284 assert(std::get<0>(v).value == 42); 285 } 286 { 287 using V = std::variant<ThrowsAssignT>; 288 V v(100); 289 try { 290 v = 42; 291 assert(false); 292 } catch (...) { /* ... */ 293 } 294 assert(v.index() == 0); 295 assert(std::get<0>(v).value == 100); 296 } 297 { 298 using V = std::variant<std::string, ThrowsAssignT>; 299 V v(100); 300 try { 301 v = 42; 302 assert(false); 303 } catch (...) { /* ... */ 304 } 305 assert(v.index() == 1); 306 assert(std::get<1>(v).value == 100); 307 } 308 #endif // TEST_HAS_NO_EXCEPTIONS 309 } 310 311 int main(int, char**) { 312 test_T_assignment_basic(); 313 test_T_assignment_performs_construction(); 314 test_T_assignment_performs_assignment(); 315 test_T_assignment_noexcept(); 316 test_T_assignment_sfinae(); 317 318 return 0; 319 } 320