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