blob: db7fc19bfb10125bde75ec33a4fbda9d4aad3643 [file] [log] [blame]
Eric Fiselier35ce4852016-10-12 07:46:20 +00001//===----------------------------------------------------------------------===//
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// From LWG2451:
14// template <class U>
15// optional<T>& operator=(optional<U>&& rhs);
16
17#include <optional>
18#include <type_traits>
19#include <memory>
20#include <cassert>
21
22#include "test_macros.h"
23#include "archetypes.hpp"
24
25using std::optional;
26
27struct X
28{
29 static bool throw_now;
30
31 X() = default;
32 X(int &&)
33 {
34 if (throw_now)
35 TEST_THROW(6);
36 }
37};
38
39bool X::throw_now = false;
40
41struct Y1
42{
43 Y1() = default;
44 Y1(const int&) {}
45 Y1& operator=(const Y1&) = delete;
46};
47
48struct Y2
49{
50 Y2() = default;
51 Y2(const int&) = delete;
52 Y2& operator=(const int&) { return *this; }
53};
54
55class B {};
56class D : public B {};
57
58
59template <class T>
60struct AssignableFrom {
61 static int type_constructed;
62 static int type_assigned;
63static int int_constructed;
64 static int int_assigned;
65
66 static void reset() {
67 type_constructed = int_constructed = 0;
68 type_assigned = int_assigned = 0;
69 }
70
71 AssignableFrom() = default;
72
73 explicit AssignableFrom(T) { ++type_constructed; }
74 AssignableFrom& operator=(T) { ++type_assigned; return *this; }
75
76 AssignableFrom(int) { ++int_constructed; }
77 AssignableFrom& operator=(int) { ++int_assigned; return *this; }
78private:
79 AssignableFrom(AssignableFrom const&) = delete;
80 AssignableFrom& operator=(AssignableFrom const&) = delete;
81};
82
83template <class T> int AssignableFrom<T>::type_constructed = 0;
84template <class T> int AssignableFrom<T>::type_assigned = 0;
85template <class T> int AssignableFrom<T>::int_constructed = 0;
86template <class T> int AssignableFrom<T>::int_assigned = 0;
87
88void test_with_test_type() {
89 using T = TestTypes::TestType;
90 T::reset();
91 { // non-empty to empty
92 T::reset_constructors();
93 optional<T> opt;
94 optional<int> other(42);
95 opt = std::move(other);
96 assert(T::alive == 1);
97 assert(T::constructed == 1);
98 assert(T::value_constructed == 1);
99 assert(T::assigned == 0);
100 assert(T::destroyed == 0);
101 assert(static_cast<bool>(other) == true);
102 assert(*other == 42);
103 assert(static_cast<bool>(opt) == true);
104 assert(*opt == T(42));
105 }
106 assert(T::alive == 0);
107 { // non-empty to non-empty
108 optional<T> opt(101);
109 optional<int> other(42);
110 T::reset_constructors();
111 opt = std::move(other);
112 assert(T::alive == 1);
113 assert(T::constructed == 0);
114 assert(T::assigned == 1);
115 assert(T::value_assigned == 1);
116 assert(T::destroyed == 0);
117 assert(static_cast<bool>(other) == true);
118 assert(*other == 42);
119 assert(static_cast<bool>(opt) == true);
120 assert(*opt == T(42));
121 }
122 assert(T::alive == 0);
123 { // empty to non-empty
124 optional<T> opt(101);
125 optional<int> other;
126 T::reset_constructors();
127 opt = std::move(other);
128 assert(T::alive == 0);
129 assert(T::constructed == 0);
130 assert(T::assigned == 0);
131 assert(T::destroyed == 1);
132 assert(static_cast<bool>(other) == false);
133 assert(static_cast<bool>(opt) == false);
134 }
135 assert(T::alive == 0);
136 { // empty to empty
137 optional<T> opt;
138 optional<int> other;
139 T::reset_constructors();
140 opt = std::move(other);
141 assert(T::alive == 0);
142 assert(T::constructed == 0);
143 assert(T::assigned == 0);
144 assert(T::destroyed == 0);
145 assert(static_cast<bool>(other) == false);
146 assert(static_cast<bool>(opt) == false);
147 }
148 assert(T::alive == 0);
149}
150
151
152void test_ambigious_assign() {
153 using OptInt = std::optional<int>;
154 {
155 using T = AssignableFrom<OptInt&&>;
156 T::reset();
157 {
158 OptInt a(42);
159 std::optional<T> t;
160 t = std::move(a);
161 assert(T::type_constructed == 1);
162 assert(T::type_assigned == 0);
163 assert(T::int_constructed == 0);
164 assert(T::int_assigned == 0);
165 }
166 {
167 using Opt = std::optional<T>;
168 static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");
169 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
170 static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
171 }
172 }
173 {
174 using T = AssignableFrom<OptInt const&&>;
175 T::reset();
176 {
177 const OptInt a(42);
178 std::optional<T> t;
179 t = std::move(a);
180 assert(T::type_constructed == 1);
181 assert(T::type_assigned == 0);
182 assert(T::int_constructed == 0);
183 assert(T::int_assigned == 0);
184 }
185 T::reset();
186 {
187 OptInt a(42);
188 std::optional<T> t;
189 t = std::move(a);
190 assert(T::type_constructed == 1);
191 assert(T::type_assigned == 0);
192 assert(T::int_constructed == 0);
193 assert(T::int_assigned == 0);
194 }
195 {
196 using Opt = std::optional<T>;
197 static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");
198 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
199 static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
200 }
201 }
202}
203
204
205int main()
206{
207 test_with_test_type();
208 test_ambigious_assign();
209 {
210 optional<int> opt;
211 optional<short> opt2;
212 opt = std::move(opt2);
213 assert(static_cast<bool>(opt2) == false);
214 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
215 }
216 {
217 optional<int> opt;
218 optional<short> opt2(short{2});
219 opt = std::move(opt2);
220 assert(static_cast<bool>(opt2) == true);
221 assert(*opt2 == 2);
222 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
223 assert(*opt == *opt2);
224 }
225 {
226 optional<int> opt(3);
227 optional<short> opt2;
228 opt = std::move(opt2);
229 assert(static_cast<bool>(opt2) == false);
230 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
231 }
232 {
233 optional<int> opt(3);
234 optional<short> opt2(short{2});
235 opt = std::move(opt2);
236 assert(static_cast<bool>(opt2) == true);
237 assert(*opt2 == 2);
238 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
239 assert(*opt == *opt2);
240 }
241 {
242 optional<std::unique_ptr<B>> opt;
243 optional<std::unique_ptr<D>> other(new D());
244 opt = std::move(other);
245 assert(static_cast<bool>(opt) == true);
246 assert(static_cast<bool>(other) == true);
247 assert(opt->get() != nullptr);
248 assert(other->get() == nullptr);
249 }
250#ifndef TEST_HAS_NO_EXCEPTIONS
251 {
252 optional<X> opt;
253 optional<int> opt2(42);
254 assert(static_cast<bool>(opt2) == true);
255 try
256 {
257 X::throw_now = true;
258 opt = std::move(opt2);
259 assert(false);
260 }
261 catch (int i)
262 {
263 assert(i == 6);
264 assert(static_cast<bool>(opt) == false);
265 }
266 }
267#endif
268}