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