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