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