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// constexpr optional<T>& operator=(optional<T>&& rhs)
13// noexcept(is_nothrow_move_assignable<T>::value &&
14// is_nothrow_move_constructible<T>::value);
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
24using std::optional;
25
26struct 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
49struct Y {};
50
51bool X::throw_now = false;
52int X::alive = 0;
53
54
55template <class Tp>
56constexpr 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
62template <class Tp>
63constexpr 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
69int 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 static_assert(assign_empty(lhs: O{42}));
118 static_assert(assign_value(lhs: O{42}));
119 assert(assign_empty(O{42}));
120 assert(assign_value(O{42}));
121 }
122 {
123 using O = optional<TrivialTestTypes::TestType>;
124 static_assert(assign_empty(O{42}));
125 static_assert(assign_value(O{42}));
126 assert(assign_empty(O{42}));
127 assert(assign_value(O{42}));
128 }
129#ifndef TEST_HAS_NO_EXCEPTIONS
130 {
131 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");
132 X::alive = 0;
133 X::throw_now = false;
134 optional<X> opt;
135 optional<X> opt2(X{});
136 assert(X::alive == 1);
137 assert(static_cast<bool>(opt2) == true);
138 try
139 {
140 X::throw_now = true;
141 opt = std::move(opt2);
142 assert(false);
143 }
144 catch (int i)
145 {
146 assert(i == 6);
147 assert(static_cast<bool>(opt) == false);
148 }
149 assert(X::alive == 1);
150 }
151 assert(X::alive == 0);
152 {
153 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");
154 X::throw_now = false;
155 optional<X> opt(X{});
156 optional<X> opt2(X{});
157 assert(X::alive == 2);
158 assert(static_cast<bool>(opt2) == true);
159 try
160 {
161 X::throw_now = true;
162 opt = std::move(opt2);
163 assert(false);
164 }
165 catch (int i)
166 {
167 assert(i == 42);
168 assert(static_cast<bool>(opt) == true);
169 }
170 assert(X::alive == 2);
171 }
172 assert(X::alive == 0);
173#endif // TEST_HAS_NO_EXCEPTIONS
174 {
175 static_assert(std::is_nothrow_move_assignable<optional<Y>>::value, "");
176 }
177 {
178 struct ThrowsMove {
179 ThrowsMove() noexcept {}
180 ThrowsMove(ThrowsMove const&) noexcept {}
181 ThrowsMove(ThrowsMove &&) noexcept(false) {}
182 ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
183 ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
184 };
185 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
186 struct ThrowsMoveAssign {
187 ThrowsMoveAssign() noexcept {}
188 ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
189 ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
190 ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
191 ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
192 };
193 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
194 struct NoThrowMove {
195 NoThrowMove() noexcept(false) {}
196 NoThrowMove(NoThrowMove const&) noexcept(false) {}
197 NoThrowMove(NoThrowMove &&) noexcept {}
198 NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
199 NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
200 };
201 static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
202 }
203 return 0;
204}
205

source code of libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp