1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14 10 // <optional> 11 12 // From LWG2451: 13 // template <class U> 14 // optional<T>& operator=(optional<U>&& rhs); 15 16 #include <optional> 17 18 #include <array> 19 #include <cassert> 20 #include <memory> 21 #include <type_traits> 22 23 #include "test_macros.h" 24 #include "archetypes.h" 25 26 using std::optional; 27 28 struct X 29 { 30 static bool throw_now; 31 32 X() = default; 33 X(int &&) 34 { 35 if (throw_now) 36 TEST_THROW(6); 37 } 38 }; 39 40 bool X::throw_now = false; 41 42 struct Y1 43 { 44 Y1() = default; 45 Y1(const int&) {} 46 Y1& operator=(const Y1&) = delete; 47 }; 48 49 struct Y2 50 { 51 Y2() = default; 52 Y2(const int&) = delete; 53 Y2& operator=(const int&) { return *this; } 54 }; 55 56 struct B { virtual ~B() = default; }; 57 class D : public B {}; 58 59 60 template <class T> 61 struct AssignableFrom { 62 static int type_constructed; 63 static int type_assigned; 64 static int int_constructed; 65 static int int_assigned; 66 67 static void reset() { 68 type_constructed = int_constructed = 0; 69 type_assigned = int_assigned = 0; 70 } 71 72 AssignableFrom() = default; 73 74 explicit AssignableFrom(T) { ++type_constructed; } 75 AssignableFrom& operator=(T) { ++type_assigned; return *this; } 76 77 AssignableFrom(int) { ++int_constructed; } 78 AssignableFrom& operator=(int) { ++int_assigned; return *this; } 79 private: 80 AssignableFrom(AssignableFrom const&) = delete; 81 AssignableFrom& operator=(AssignableFrom const&) = delete; 82 }; 83 84 template <class T> int AssignableFrom<T>::type_constructed = 0; 85 template <class T> int AssignableFrom<T>::type_assigned = 0; 86 template <class T> int AssignableFrom<T>::int_constructed = 0; 87 template <class T> int AssignableFrom<T>::int_assigned = 0; 88 89 void test_with_test_type() { 90 using T = TestTypes::TestType; 91 T::reset(); 92 { // non-empty to empty 93 T::reset_constructors(); 94 optional<T> opt; 95 optional<int> other(42); 96 opt = std::move(other); 97 assert(T::alive == 1); 98 assert(T::constructed == 1); 99 assert(T::value_constructed == 1); 100 assert(T::assigned == 0); 101 assert(T::destroyed == 0); 102 assert(static_cast<bool>(other) == true); 103 assert(*other == 42); 104 assert(static_cast<bool>(opt) == true); 105 assert(*opt == T(42)); 106 } 107 assert(T::alive == 0); 108 { // non-empty to non-empty 109 optional<T> opt(101); 110 optional<int> other(42); 111 T::reset_constructors(); 112 opt = std::move(other); 113 assert(T::alive == 1); 114 assert(T::constructed == 0); 115 assert(T::assigned == 1); 116 assert(T::value_assigned == 1); 117 assert(T::destroyed == 0); 118 assert(static_cast<bool>(other) == true); 119 assert(*other == 42); 120 assert(static_cast<bool>(opt) == true); 121 assert(*opt == T(42)); 122 } 123 assert(T::alive == 0); 124 { // empty to non-empty 125 optional<T> opt(101); 126 optional<int> other; 127 T::reset_constructors(); 128 opt = std::move(other); 129 assert(T::alive == 0); 130 assert(T::constructed == 0); 131 assert(T::assigned == 0); 132 assert(T::destroyed == 1); 133 assert(static_cast<bool>(other) == false); 134 assert(static_cast<bool>(opt) == false); 135 } 136 assert(T::alive == 0); 137 { // empty to empty 138 optional<T> opt; 139 optional<int> other; 140 T::reset_constructors(); 141 opt = std::move(other); 142 assert(T::alive == 0); 143 assert(T::constructed == 0); 144 assert(T::assigned == 0); 145 assert(T::destroyed == 0); 146 assert(static_cast<bool>(other) == false); 147 assert(static_cast<bool>(opt) == false); 148 } 149 assert(T::alive == 0); 150 } 151 152 153 void test_ambiguous_assign() { 154 using OptInt = std::optional<int>; 155 { 156 using T = AssignableFrom<OptInt&&>; 157 T::reset(); 158 { 159 OptInt a(42); 160 std::optional<T> t; 161 t = std::move(a); 162 assert(T::type_constructed == 1); 163 assert(T::type_assigned == 0); 164 assert(T::int_constructed == 0); 165 assert(T::int_assigned == 0); 166 } 167 { 168 using Opt = std::optional<T>; 169 static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, ""); 170 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); 171 static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); 172 } 173 } 174 { 175 using T = AssignableFrom<OptInt const&&>; 176 T::reset(); 177 { 178 const OptInt a(42); 179 std::optional<T> t; 180 t = std::move(a); 181 assert(T::type_constructed == 1); 182 assert(T::type_assigned == 0); 183 assert(T::int_constructed == 0); 184 assert(T::int_assigned == 0); 185 } 186 T::reset(); 187 { 188 OptInt a(42); 189 std::optional<T> t; 190 t = std::move(a); 191 assert(T::type_constructed == 1); 192 assert(T::type_assigned == 0); 193 assert(T::int_constructed == 0); 194 assert(T::int_assigned == 0); 195 } 196 { 197 using Opt = std::optional<T>; 198 static_assert(std::is_assignable<Opt&, OptInt&&>::value, ""); 199 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); 200 static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); 201 } 202 } 203 } 204 205 206 TEST_CONSTEXPR_CXX20 bool test() 207 { 208 { 209 optional<int> opt; 210 optional<short> opt2; 211 opt = std::move(opt2); 212 assert(static_cast<bool>(opt2) == false); 213 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 214 } 215 { 216 optional<int> opt; 217 optional<short> opt2(short{2}); 218 opt = std::move(opt2); 219 assert(static_cast<bool>(opt2) == true); 220 assert(*opt2 == 2); 221 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 222 assert(*opt == *opt2); 223 } 224 { 225 optional<int> opt(3); 226 optional<short> opt2; 227 opt = std::move(opt2); 228 assert(static_cast<bool>(opt2) == false); 229 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 230 } 231 { 232 optional<int> opt(3); 233 optional<short> opt2(short{2}); 234 opt = std::move(opt2); 235 assert(static_cast<bool>(opt2) == true); 236 assert(*opt2 == 2); 237 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 238 assert(*opt == *opt2); 239 } 240 241 enum class state_t { inactive, constructed, copy_assigned, move_assigned }; 242 class StateTracker { 243 public: 244 constexpr StateTracker(state_t& s) 245 : state_(&s) 246 { 247 *state_ = state_t::constructed; 248 } 249 250 StateTracker(StateTracker&&) = default; 251 StateTracker(StateTracker const&) = default; 252 253 constexpr StateTracker& operator=(StateTracker&& other) noexcept 254 { 255 *state_ = state_t::inactive; 256 state_ = other.state_; 257 *state_ = state_t::move_assigned; 258 other.state_ = nullptr; 259 return *this; 260 } 261 262 constexpr StateTracker& operator=(StateTracker const& other) noexcept 263 { 264 *state_ = state_t::inactive; 265 state_ = other.state_; 266 *state_ = state_t::copy_assigned; 267 return *this; 268 } 269 private: 270 state_t* state_; 271 }; 272 { 273 auto state = std::array{state_t::inactive, state_t::inactive}; 274 auto opt1 = std::optional<StateTracker>(state[0]); 275 assert(state[0] == state_t::constructed); 276 277 auto opt2 = std::optional<StateTracker>(state[1]); 278 assert(state[1] == state_t::constructed); 279 280 opt1 = std::move(opt2); 281 assert(state[0] == state_t::inactive); 282 assert(state[1] == state_t::move_assigned); 283 } 284 { 285 auto state = std::array{state_t::inactive, state_t::inactive}; 286 auto opt1 = std::optional<StateTracker>(state[0]); 287 assert(state[0] == state_t::constructed); 288 289 auto opt2 = std::optional<StateTracker>(state[1]); 290 assert(state[1] == state_t::constructed); 291 292 opt1 = opt2; 293 assert(state[0] == state_t::inactive); 294 assert(state[1] == state_t::copy_assigned); 295 } 296 297 return true; 298 } 299 300 301 int main(int, char**) 302 { 303 #if TEST_STD_VER > 17 304 static_assert(test()); 305 #endif 306 test_with_test_type(); 307 test_ambiguous_assign(); 308 test(); 309 { 310 optional<std::unique_ptr<B>> opt; 311 optional<std::unique_ptr<D>> other(new D()); 312 opt = std::move(other); 313 assert(static_cast<bool>(opt) == true); 314 assert(static_cast<bool>(other) == true); 315 assert(opt->get() != nullptr); 316 assert(other->get() == nullptr); 317 } 318 #ifndef TEST_HAS_NO_EXCEPTIONS 319 { 320 optional<X> opt; 321 optional<int> opt2(42); 322 assert(static_cast<bool>(opt2) == true); 323 try 324 { 325 X::throw_now = true; 326 opt = std::move(opt2); 327 assert(false); 328 } 329 catch (int i) 330 { 331 assert(i == 6); 332 assert(static_cast<bool>(opt) == false); 333 } 334 } 335 #endif 336 337 return 0; 338 } 339