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