1a9e65961SEric Fiselier //===----------------------------------------------------------------------===//
2a9e65961SEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9e65961SEric Fiselier //
7a9e65961SEric Fiselier //===----------------------------------------------------------------------===//
8a9e65961SEric Fiselier 
9*31cbe0f2SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
10a9e65961SEric Fiselier // <optional>
11a9e65961SEric Fiselier 
12a9e65961SEric Fiselier // optional<T>& operator=(optional<T>&& rhs)
13a9e65961SEric Fiselier //     noexcept(is_nothrow_move_assignable<T>::value &&
141d5f6a81SLouis Dionne //              is_nothrow_move_constructible<T>::value); // constexpr in C++20
15a9e65961SEric Fiselier 
16a9e65961SEric Fiselier #include <optional>
17a9e65961SEric Fiselier #include <cassert>
181d5f6a81SLouis Dionne #include <type_traits>
191d5f6a81SLouis Dionne #include <utility>
20a9e65961SEric Fiselier 
21a9e65961SEric Fiselier #include "test_macros.h"
22cc89063bSNico Weber #include "archetypes.h"
23a9e65961SEric Fiselier 
24a9e65961SEric Fiselier using std::optional;
25a9e65961SEric Fiselier 
26a9e65961SEric Fiselier struct X
27a9e65961SEric Fiselier {
28a9e65961SEric Fiselier     static bool throw_now;
29a9e65961SEric Fiselier     static int alive;
30a9e65961SEric Fiselier 
XX31a9e65961SEric Fiselier     X() { ++alive; }
XX32a9e65961SEric Fiselier     X(X&&)
33a9e65961SEric Fiselier     {
34a9e65961SEric Fiselier         if (throw_now)
35a9e65961SEric Fiselier             TEST_THROW(6);
36a9e65961SEric Fiselier         ++alive;
37a9e65961SEric Fiselier     }
38a9e65961SEric Fiselier 
operator =X39a9e65961SEric Fiselier     X& operator=(X&&)
40a9e65961SEric Fiselier     {
41a9e65961SEric Fiselier         if (throw_now)
42a9e65961SEric Fiselier             TEST_THROW(42);
43a9e65961SEric Fiselier         return *this;
44a9e65961SEric Fiselier     }
45a9e65961SEric Fiselier 
~XX46a9e65961SEric Fiselier     ~X() { assert(alive > 0); --alive; }
47a9e65961SEric Fiselier };
48a9e65961SEric Fiselier 
49a9e65961SEric Fiselier struct Y {};
50a9e65961SEric Fiselier 
51a9e65961SEric Fiselier bool X::throw_now = false;
52a9e65961SEric Fiselier int X::alive = 0;
53a9e65961SEric Fiselier 
541d5f6a81SLouis Dionne 
551d5f6a81SLouis Dionne template <class Tp>
assign_empty(optional<Tp> && lhs)561d5f6a81SLouis Dionne constexpr bool assign_empty(optional<Tp>&& lhs) {
571d5f6a81SLouis Dionne     optional<Tp> rhs;
581d5f6a81SLouis Dionne     lhs = std::move(rhs);
591d5f6a81SLouis Dionne     return !lhs.has_value() && !rhs.has_value();
601d5f6a81SLouis Dionne }
611d5f6a81SLouis Dionne 
621d5f6a81SLouis Dionne template <class Tp>
assign_value(optional<Tp> && lhs)631d5f6a81SLouis Dionne constexpr bool assign_value(optional<Tp>&& lhs) {
641d5f6a81SLouis Dionne     optional<Tp> rhs(101);
651d5f6a81SLouis Dionne     lhs = std::move(rhs);
661d5f6a81SLouis Dionne     return lhs.has_value() && rhs.has_value() && *lhs == Tp{101};
671d5f6a81SLouis Dionne }
681d5f6a81SLouis Dionne 
main(int,char **)692df59c50SJF Bastien int main(int, char**)
70a9e65961SEric Fiselier {
71a9e65961SEric Fiselier     {
72a9e65961SEric Fiselier         static_assert(std::is_nothrow_move_assignable<optional<int>>::value, "");
73a9e65961SEric Fiselier         optional<int> opt;
74a9e65961SEric Fiselier         constexpr optional<int> opt2;
75a9e65961SEric Fiselier         opt = std::move(opt2);
76a9e65961SEric Fiselier         static_assert(static_cast<bool>(opt2) == false, "");
77a9e65961SEric Fiselier         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
78a9e65961SEric Fiselier     }
79a9e65961SEric Fiselier     {
80a9e65961SEric Fiselier         optional<int> opt;
81a9e65961SEric Fiselier         constexpr optional<int> opt2(2);
82a9e65961SEric Fiselier         opt = std::move(opt2);
83a9e65961SEric Fiselier         static_assert(static_cast<bool>(opt2) == true, "");
84a9e65961SEric Fiselier         static_assert(*opt2 == 2, "");
85a9e65961SEric Fiselier         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
86a9e65961SEric Fiselier         assert(*opt == *opt2);
87a9e65961SEric Fiselier     }
88a9e65961SEric Fiselier     {
89a9e65961SEric Fiselier         optional<int> opt(3);
90a9e65961SEric Fiselier         constexpr optional<int> opt2;
91a9e65961SEric Fiselier         opt = std::move(opt2);
92a9e65961SEric Fiselier         static_assert(static_cast<bool>(opt2) == false, "");
93a9e65961SEric Fiselier         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
94a9e65961SEric Fiselier     }
95a9e65961SEric Fiselier     {
96a9e65961SEric Fiselier         using T = TestTypes::TestType;
97a9e65961SEric Fiselier         T::reset();
98a9e65961SEric Fiselier         optional<T> opt(3);
99a9e65961SEric Fiselier         optional<T> opt2;
100a9e65961SEric Fiselier         assert(T::alive == 1);
101a9e65961SEric Fiselier         opt = std::move(opt2);
102a9e65961SEric Fiselier         assert(T::alive == 0);
103a9e65961SEric Fiselier         assert(static_cast<bool>(opt2) == false);
104a9e65961SEric Fiselier         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
105a9e65961SEric Fiselier     }
106a9e65961SEric Fiselier     {
107a9e65961SEric Fiselier         optional<int> opt(3);
108a9e65961SEric Fiselier         constexpr optional<int> opt2(2);
109a9e65961SEric Fiselier         opt = std::move(opt2);
110a9e65961SEric Fiselier         static_assert(static_cast<bool>(opt2) == true, "");
111a9e65961SEric Fiselier         static_assert(*opt2 == 2, "");
112a9e65961SEric Fiselier         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
113a9e65961SEric Fiselier         assert(*opt == *opt2);
114a9e65961SEric Fiselier     }
1151d5f6a81SLouis Dionne     {
1161d5f6a81SLouis Dionne         using O = optional<int>;
1171d5f6a81SLouis Dionne #if TEST_STD_VER > 17
1181d5f6a81SLouis Dionne         LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
1191d5f6a81SLouis Dionne         LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
1201d5f6a81SLouis Dionne #endif
1211d5f6a81SLouis Dionne         assert(assign_empty(O{42}));
1221d5f6a81SLouis Dionne         assert(assign_value(O{42}));
1231d5f6a81SLouis Dionne     }
1241d5f6a81SLouis Dionne     {
1251d5f6a81SLouis Dionne         using O = optional<TrivialTestTypes::TestType>;
1261d5f6a81SLouis Dionne #if TEST_STD_VER > 17
1271d5f6a81SLouis Dionne         LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
1281d5f6a81SLouis Dionne         LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
1291d5f6a81SLouis Dionne #endif
1301d5f6a81SLouis Dionne         assert(assign_empty(O{42}));
1311d5f6a81SLouis Dionne         assert(assign_value(O{42}));
1321d5f6a81SLouis Dionne     }
133a9e65961SEric Fiselier #ifndef TEST_HAS_NO_EXCEPTIONS
134a9e65961SEric Fiselier     {
135a9e65961SEric Fiselier         static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");
136a9e65961SEric Fiselier         X::alive = 0;
137a9e65961SEric Fiselier         X::throw_now = false;
138a9e65961SEric Fiselier         optional<X> opt;
139a9e65961SEric Fiselier         optional<X> opt2(X{});
140a9e65961SEric Fiselier         assert(X::alive == 1);
141a9e65961SEric Fiselier         assert(static_cast<bool>(opt2) == true);
142a9e65961SEric Fiselier         try
143a9e65961SEric Fiselier         {
144a9e65961SEric Fiselier             X::throw_now = true;
145a9e65961SEric Fiselier             opt = std::move(opt2);
146a9e65961SEric Fiselier             assert(false);
147a9e65961SEric Fiselier         }
148a9e65961SEric Fiselier         catch (int i)
149a9e65961SEric Fiselier         {
150a9e65961SEric Fiselier             assert(i == 6);
151a9e65961SEric Fiselier             assert(static_cast<bool>(opt) == false);
152a9e65961SEric Fiselier         }
153a9e65961SEric Fiselier         assert(X::alive == 1);
154a9e65961SEric Fiselier     }
155a9e65961SEric Fiselier     assert(X::alive == 0);
156a9e65961SEric Fiselier     {
157a9e65961SEric Fiselier         static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");
158a9e65961SEric Fiselier         X::throw_now = false;
159a9e65961SEric Fiselier         optional<X> opt(X{});
160a9e65961SEric Fiselier         optional<X> opt2(X{});
161a9e65961SEric Fiselier         assert(X::alive == 2);
162a9e65961SEric Fiselier         assert(static_cast<bool>(opt2) == true);
163a9e65961SEric Fiselier         try
164a9e65961SEric Fiselier         {
165a9e65961SEric Fiselier             X::throw_now = true;
166a9e65961SEric Fiselier             opt = std::move(opt2);
167a9e65961SEric Fiselier             assert(false);
168a9e65961SEric Fiselier         }
169a9e65961SEric Fiselier         catch (int i)
170a9e65961SEric Fiselier         {
171a9e65961SEric Fiselier             assert(i == 42);
172a9e65961SEric Fiselier             assert(static_cast<bool>(opt) == true);
173a9e65961SEric Fiselier         }
174a9e65961SEric Fiselier         assert(X::alive == 2);
175a9e65961SEric Fiselier     }
176a9e65961SEric Fiselier     assert(X::alive == 0);
177a9e65961SEric Fiselier #endif // TEST_HAS_NO_EXCEPTIONS
178a9e65961SEric Fiselier     {
179a9e65961SEric Fiselier         static_assert(std::is_nothrow_move_assignable<optional<Y>>::value, "");
180a9e65961SEric Fiselier     }
181a9e65961SEric Fiselier     {
182a9e65961SEric Fiselier         struct ThrowsMove {
183a9e65961SEric Fiselier             ThrowsMove() noexcept {}
184a9e65961SEric Fiselier             ThrowsMove(ThrowsMove const&) noexcept {}
185a9e65961SEric Fiselier             ThrowsMove(ThrowsMove &&) noexcept(false) {}
186a9e65961SEric Fiselier             ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
187a9e65961SEric Fiselier             ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
188a9e65961SEric Fiselier         };
189a9e65961SEric Fiselier         static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
190a9e65961SEric Fiselier         struct ThrowsMoveAssign {
191a9e65961SEric Fiselier             ThrowsMoveAssign() noexcept {}
192a9e65961SEric Fiselier             ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
193a9e65961SEric Fiselier             ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
194a9e65961SEric Fiselier             ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
195a9e65961SEric Fiselier             ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
196a9e65961SEric Fiselier         };
197a9e65961SEric Fiselier         static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
198a9e65961SEric Fiselier         struct NoThrowMove {
199a9e65961SEric Fiselier             NoThrowMove() noexcept(false) {}
200a9e65961SEric Fiselier             NoThrowMove(NoThrowMove const&) noexcept(false) {}
201a9e65961SEric Fiselier             NoThrowMove(NoThrowMove &&) noexcept {}
202a9e65961SEric Fiselier             NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
203a9e65961SEric Fiselier             NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
204a9e65961SEric Fiselier         };
205a9e65961SEric Fiselier         static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
206a9e65961SEric Fiselier     }
2072df59c50SJF Bastien     return 0;
208a9e65961SEric Fiselier }
209