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 // optional<T>& operator=(optional<T>&& rhs) 13 // noexcept(is_nothrow_move_assignable<T>::value && 14 // is_nothrow_move_constructible<T>::value); // constexpr in C++20 15 16 #include <optional> 17 #include <cassert> 18 #include <type_traits> 19 #include <utility> 20 21 #include "test_macros.h" 22 #include "archetypes.h" 23 24 using std::optional; 25 26 struct X 27 { 28 static bool throw_now; 29 static int alive; 30 31 X() { ++alive; } 32 X(X&&) 33 { 34 if (throw_now) 35 TEST_THROW(6); 36 ++alive; 37 } 38 39 X& operator=(X&&) 40 { 41 if (throw_now) 42 TEST_THROW(42); 43 return *this; 44 } 45 46 ~X() { assert(alive > 0); --alive; } 47 }; 48 49 struct Y {}; 50 51 bool X::throw_now = false; 52 int X::alive = 0; 53 54 55 template <class Tp> 56 constexpr bool assign_empty(optional<Tp>&& lhs) { 57 optional<Tp> rhs; 58 lhs = std::move(rhs); 59 return !lhs.has_value() && !rhs.has_value(); 60 } 61 62 template <class Tp> 63 constexpr bool assign_value(optional<Tp>&& lhs) { 64 optional<Tp> rhs(101); 65 lhs = std::move(rhs); 66 return lhs.has_value() && rhs.has_value() && *lhs == Tp{101}; 67 } 68 69 int main(int, char**) 70 { 71 { 72 static_assert(std::is_nothrow_move_assignable<optional<int>>::value, ""); 73 optional<int> opt; 74 constexpr optional<int> opt2; 75 opt = std::move(opt2); 76 static_assert(static_cast<bool>(opt2) == false, ""); 77 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 78 } 79 { 80 optional<int> opt; 81 constexpr optional<int> opt2(2); 82 opt = std::move(opt2); 83 static_assert(static_cast<bool>(opt2) == true, ""); 84 static_assert(*opt2 == 2, ""); 85 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 86 assert(*opt == *opt2); 87 } 88 { 89 optional<int> opt(3); 90 constexpr optional<int> opt2; 91 opt = std::move(opt2); 92 static_assert(static_cast<bool>(opt2) == false, ""); 93 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 94 } 95 { 96 using T = TestTypes::TestType; 97 T::reset(); 98 optional<T> opt(3); 99 optional<T> opt2; 100 assert(T::alive == 1); 101 opt = std::move(opt2); 102 assert(T::alive == 0); 103 assert(static_cast<bool>(opt2) == false); 104 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 105 } 106 { 107 optional<int> opt(3); 108 constexpr optional<int> opt2(2); 109 opt = std::move(opt2); 110 static_assert(static_cast<bool>(opt2) == true, ""); 111 static_assert(*opt2 == 2, ""); 112 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 113 assert(*opt == *opt2); 114 } 115 { 116 using O = optional<int>; 117 #if TEST_STD_VER > 17 118 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); 119 LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); 120 #endif 121 assert(assign_empty(O{42})); 122 assert(assign_value(O{42})); 123 } 124 { 125 using O = optional<TrivialTestTypes::TestType>; 126 #if TEST_STD_VER > 17 127 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); 128 LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); 129 #endif 130 assert(assign_empty(O{42})); 131 assert(assign_value(O{42})); 132 } 133 #ifndef TEST_HAS_NO_EXCEPTIONS 134 { 135 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, ""); 136 X::alive = 0; 137 X::throw_now = false; 138 optional<X> opt; 139 optional<X> opt2(X{}); 140 assert(X::alive == 1); 141 assert(static_cast<bool>(opt2) == true); 142 try 143 { 144 X::throw_now = true; 145 opt = std::move(opt2); 146 assert(false); 147 } 148 catch (int i) 149 { 150 assert(i == 6); 151 assert(static_cast<bool>(opt) == false); 152 } 153 assert(X::alive == 1); 154 } 155 assert(X::alive == 0); 156 { 157 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, ""); 158 X::throw_now = false; 159 optional<X> opt(X{}); 160 optional<X> opt2(X{}); 161 assert(X::alive == 2); 162 assert(static_cast<bool>(opt2) == true); 163 try 164 { 165 X::throw_now = true; 166 opt = std::move(opt2); 167 assert(false); 168 } 169 catch (int i) 170 { 171 assert(i == 42); 172 assert(static_cast<bool>(opt) == true); 173 } 174 assert(X::alive == 2); 175 } 176 assert(X::alive == 0); 177 #endif // TEST_HAS_NO_EXCEPTIONS 178 { 179 static_assert(std::is_nothrow_move_assignable<optional<Y>>::value, ""); 180 } 181 { 182 struct ThrowsMove { 183 ThrowsMove() noexcept {} 184 ThrowsMove(ThrowsMove const&) noexcept {} 185 ThrowsMove(ThrowsMove &&) noexcept(false) {} 186 ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; } 187 ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; } 188 }; 189 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, ""); 190 struct ThrowsMoveAssign { 191 ThrowsMoveAssign() noexcept {} 192 ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {} 193 ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {} 194 ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; } 195 ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; } 196 }; 197 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, ""); 198 struct NoThrowMove { 199 NoThrowMove() noexcept(false) {} 200 NoThrowMove(NoThrowMove const&) noexcept(false) {} 201 NoThrowMove(NoThrowMove &&) noexcept {} 202 NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; } 203 NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; } 204 }; 205 static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, ""); 206 } 207 return 0; 208 } 209