339 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410// <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 26using std::optional;27 28struct X29{30 static bool throw_now;31 32 X() = default;33 X(int &&)34 {35 if (throw_now)36 TEST_THROW(6);37 }38};39 40bool X::throw_now = false;41 42struct Y143{44 Y1() = default;45 Y1(const int&) {}46 Y1& operator=(const Y1&) = delete;47};48 49struct Y250{51 Y2() = default;52 Y2(const int&) = delete;53 Y2& operator=(const int&) { return *this; }54};55 56struct B { virtual ~B() = default; };57class D : public B {};58 59 60template <class T>61struct AssignableFrom {62 static int type_constructed;63 static int type_assigned;64static 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; }79private:80 AssignableFrom(AssignableFrom const&) = delete;81 AssignableFrom& operator=(AssignableFrom const&) = delete;82};83 84template <class T> int AssignableFrom<T>::type_constructed = 0;85template <class T> int AssignableFrom<T>::type_assigned = 0;86template <class T> int AssignableFrom<T>::int_constructed = 0;87template <class T> int AssignableFrom<T>::int_assigned = 0;88 89void test_with_test_type() {90 using T = TestTypes::TestType;91 T::reset();92 { // non-empty to empty93 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-empty109 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-empty125 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 empty138 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 153void 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 206TEST_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) noexcept254 {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) noexcept263 {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 301int main(int, char**)302{303#if TEST_STD_VER > 17304 static_assert(test());305#endif306 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_EXCEPTIONS319 {320 optional<X> opt;321 optional<int> opt2(42);322 assert(static_cast<bool>(opt2) == true);323 try324 {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#endif336 337 return 0;338}339