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