1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is dual licensed under the MIT and the University of Illinois Open 7 // Source Licenses. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 // UNSUPPORTED: c++98, c++03, c++11, c++14 12 13 // XFAIL: with_system_cxx_lib=macosx10.12 14 // XFAIL: with_system_cxx_lib=macosx10.11 15 // XFAIL: with_system_cxx_lib=macosx10.10 16 // XFAIL: with_system_cxx_lib=macosx10.9 17 // XFAIL: with_system_cxx_lib=macosx10.7 18 // XFAIL: with_system_cxx_lib=macosx10.8 19 20 // <variant> 21 22 // template <class ...Types> class variant; 23 24 // template <class T> 25 // variant& operator=(T&&) noexcept(see below); 26 27 #include <cassert> 28 #include <string> 29 #include <type_traits> 30 #include <variant> 31 32 #include "test_macros.h" 33 #include "variant_test_helpers.hpp" 34 35 namespace MetaHelpers { 36 37 struct Dummy { 38 Dummy() = default; 39 }; 40 41 struct ThrowsCtorT { 42 ThrowsCtorT(int) noexcept(false) {} 43 ThrowsCtorT &operator=(int) noexcept { return *this; } 44 }; 45 46 struct ThrowsAssignT { 47 ThrowsAssignT(int) noexcept {} 48 ThrowsAssignT &operator=(int) noexcept(false) { return *this; } 49 }; 50 51 struct NoThrowT { 52 NoThrowT(int) noexcept {} 53 NoThrowT &operator=(int) noexcept { return *this; } 54 }; 55 56 } // namespace MetaHelpers 57 58 namespace RuntimeHelpers { 59 #ifndef TEST_HAS_NO_EXCEPTIONS 60 61 struct ThrowsCtorT { 62 int value; 63 ThrowsCtorT() : value(0) {} 64 ThrowsCtorT(int) noexcept(false) { throw 42; } 65 ThrowsCtorT &operator=(int v) noexcept { 66 value = v; 67 return *this; 68 } 69 }; 70 71 struct MoveCrashes { 72 int value; 73 MoveCrashes(int v = 0) noexcept : value{v} {} 74 MoveCrashes(MoveCrashes &&) noexcept { assert(false); } 75 MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } 76 MoveCrashes &operator=(int v) noexcept { 77 value = v; 78 return *this; 79 } 80 }; 81 82 struct ThrowsCtorTandMove { 83 int value; 84 ThrowsCtorTandMove() : value(0) {} 85 ThrowsCtorTandMove(int) noexcept(false) { throw 42; } 86 ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } 87 ThrowsCtorTandMove &operator=(int v) noexcept { 88 value = v; 89 return *this; 90 } 91 }; 92 93 struct ThrowsAssignT { 94 int value; 95 ThrowsAssignT() : value(0) {} 96 ThrowsAssignT(int v) noexcept : value(v) {} 97 ThrowsAssignT &operator=(int) noexcept(false) { throw 42; } 98 }; 99 100 struct NoThrowT { 101 int value; 102 NoThrowT() : value(0) {} 103 NoThrowT(int v) noexcept : value(v) {} 104 NoThrowT &operator=(int v) noexcept { 105 value = v; 106 return *this; 107 } 108 }; 109 110 #endif // !defined(TEST_HAS_NO_EXCEPTIONS) 111 } // namespace RuntimeHelpers 112 113 void test_T_assignment_noexcept() { 114 using namespace MetaHelpers; 115 { 116 using V = std::variant<Dummy, NoThrowT>; 117 static_assert(std::is_nothrow_assignable<V, int>::value, ""); 118 } 119 { 120 using V = std::variant<Dummy, ThrowsCtorT>; 121 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 122 } 123 { 124 using V = std::variant<Dummy, ThrowsAssignT>; 125 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 126 } 127 } 128 129 void test_T_assignment_sfinae() { 130 { 131 using V = std::variant<long, unsigned>; 132 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 133 } 134 { 135 using V = std::variant<std::string, std::string>; 136 static_assert(!std::is_assignable<V, const char *>::value, "ambiguous"); 137 } 138 { 139 using V = std::variant<std::string, void *>; 140 static_assert(!std::is_assignable<V, int>::value, "no matching operator="); 141 } 142 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 143 { 144 using V = std::variant<int, int &&>; 145 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 146 } 147 { 148 using V = std::variant<int, const int &>; 149 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 150 } 151 #endif // TEST_VARIANT_HAS_NO_REFERENCES 152 } 153 154 void test_T_assignment_basic() { 155 { 156 std::variant<int> v(43); 157 v = 42; 158 assert(v.index() == 0); 159 assert(std::get<0>(v) == 42); 160 } 161 { 162 std::variant<int, long> v(43l); 163 v = 42; 164 assert(v.index() == 0); 165 assert(std::get<0>(v) == 42); 166 v = 43l; 167 assert(v.index() == 1); 168 assert(std::get<1>(v) == 43); 169 } 170 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 171 { 172 using V = std::variant<int &, int &&, long>; 173 int x = 42; 174 V v(43l); 175 v = x; 176 assert(v.index() == 0); 177 assert(&std::get<0>(v) == &x); 178 v = std::move(x); 179 assert(v.index() == 1); 180 assert(&std::get<1>(v) == &x); 181 // 'long' is selected by FUN(const int &) since 'const int &' cannot bind 182 // to 'int&'. 183 const int &cx = x; 184 v = cx; 185 assert(v.index() == 2); 186 assert(std::get<2>(v) == 42); 187 } 188 #endif // TEST_VARIANT_HAS_NO_REFERENCES 189 } 190 191 void test_T_assignment_performs_construction() { 192 using namespace RuntimeHelpers; 193 #ifndef TEST_HAS_NO_EXCEPTIONS 194 { 195 using V = std::variant<std::string, ThrowsCtorT>; 196 V v(std::in_place_type<std::string>, "hello"); 197 try { 198 v = 42; 199 assert(false); 200 } catch (...) { /* ... */ 201 } 202 assert(v.index() == 0); 203 assert(std::get<0>(v) == "hello"); 204 } 205 { 206 using V = std::variant<ThrowsAssignT, std::string>; 207 V v(std::in_place_type<std::string>, "hello"); 208 v = 42; 209 assert(v.index() == 0); 210 assert(std::get<0>(v).value == 42); 211 } 212 #endif // TEST_HAS_NO_EXCEPTIONS 213 } 214 215 void test_T_assignment_performs_assignment() { 216 using namespace RuntimeHelpers; 217 #ifndef TEST_HAS_NO_EXCEPTIONS 218 { 219 using V = std::variant<ThrowsCtorT>; 220 V v; 221 v = 42; 222 assert(v.index() == 0); 223 assert(std::get<0>(v).value == 42); 224 } 225 { 226 using V = std::variant<ThrowsCtorT, std::string>; 227 V v; 228 v = 42; 229 assert(v.index() == 0); 230 assert(std::get<0>(v).value == 42); 231 } 232 { 233 using V = std::variant<ThrowsAssignT>; 234 V v(100); 235 try { 236 v = 42; 237 assert(false); 238 } catch (...) { /* ... */ 239 } 240 assert(v.index() == 0); 241 assert(std::get<0>(v).value == 100); 242 } 243 { 244 using V = std::variant<std::string, ThrowsAssignT>; 245 V v(100); 246 try { 247 v = 42; 248 assert(false); 249 } catch (...) { /* ... */ 250 } 251 assert(v.index() == 1); 252 assert(std::get<1>(v).value == 100); 253 } 254 #endif // TEST_HAS_NO_EXCEPTIONS 255 } 256 257 int main() { 258 test_T_assignment_basic(); 259 test_T_assignment_performs_construction(); 260 test_T_assignment_performs_assignment(); 261 test_T_assignment_noexcept(); 262 test_T_assignment_sfinae(); 263 } 264