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 | |
11 | // <optional> |
12 | |
13 | // constexpr optional(optional<T>&& rhs); |
14 | |
15 | #include <optional> |
16 | #include <type_traits> |
17 | #include <cassert> |
18 | |
19 | #include "test_macros.h" |
20 | #include "archetypes.h" |
21 | |
22 | using std::optional; |
23 | |
24 | template <class T, class ...InitArgs> |
25 | void test(InitArgs&&... args) |
26 | { |
27 | const optional<T> orig(std::forward<InitArgs>(args)...); |
28 | optional<T> rhs(orig); |
29 | bool rhs_engaged = static_cast<bool>(rhs); |
30 | optional<T> lhs = std::move(rhs); |
31 | assert(static_cast<bool>(lhs) == rhs_engaged); |
32 | if (rhs_engaged) |
33 | assert(*lhs == *orig); |
34 | } |
35 | |
36 | template <class T, class ...InitArgs> |
37 | constexpr bool constexpr_test(InitArgs&&... args) |
38 | { |
39 | static_assert( std::is_trivially_copy_constructible_v<T>, "" ); // requirement |
40 | const optional<T> orig(std::forward<InitArgs>(args)...); |
41 | optional<T> rhs(orig); |
42 | optional<T> lhs = std::move(rhs); |
43 | return (lhs.has_value() == orig.has_value()) && |
44 | (lhs.has_value() ? *lhs == *orig : true); |
45 | } |
46 | |
47 | void test_throwing_ctor() { |
48 | #ifndef TEST_HAS_NO_EXCEPTIONS |
49 | struct Z { |
50 | Z() : count(0) {} |
51 | Z(Z&& o) : count(o.count + 1) |
52 | { if (count == 2) throw 6; } |
53 | int count; |
54 | }; |
55 | Z z; |
56 | optional<Z> rhs(std::move(z)); |
57 | try |
58 | { |
59 | optional<Z> lhs(std::move(rhs)); |
60 | assert(false); |
61 | } |
62 | catch (int i) |
63 | { |
64 | assert(i == 6); |
65 | } |
66 | #endif |
67 | } |
68 | |
69 | |
70 | template <class T, class ...InitArgs> |
71 | void test_ref(InitArgs&&... args) |
72 | { |
73 | optional<T> rhs(std::forward<InitArgs>(args)...); |
74 | bool rhs_engaged = static_cast<bool>(rhs); |
75 | optional<T> lhs = std::move(rhs); |
76 | assert(static_cast<bool>(lhs) == rhs_engaged); |
77 | if (rhs_engaged) |
78 | assert(&(*lhs) == &(*rhs)); |
79 | } |
80 | |
81 | void test_reference_extension() |
82 | { |
83 | #if defined(_LIBCPP_VERSION) && 0 // FIXME these extensions are currently disabled. |
84 | using T = TestTypes::TestType; |
85 | T::reset(); |
86 | { |
87 | T t; |
88 | T::reset_constructors(); |
89 | test_ref<T&>(); |
90 | test_ref<T&>(t); |
91 | assert(T::alive == 1); |
92 | assert(T::constructed == 0); |
93 | assert(T::assigned == 0); |
94 | assert(T::destroyed == 0); |
95 | } |
96 | assert(T::destroyed == 1); |
97 | assert(T::alive == 0); |
98 | { |
99 | T t; |
100 | const T& ct = t; |
101 | T::reset_constructors(); |
102 | test_ref<T const&>(); |
103 | test_ref<T const&>(t); |
104 | test_ref<T const&>(ct); |
105 | assert(T::alive == 1); |
106 | assert(T::constructed == 0); |
107 | assert(T::assigned == 0); |
108 | assert(T::destroyed == 0); |
109 | } |
110 | assert(T::alive == 0); |
111 | assert(T::destroyed == 1); |
112 | { |
113 | T t; |
114 | T::reset_constructors(); |
115 | test_ref<T&&>(); |
116 | test_ref<T&&>(std::move(t)); |
117 | assert(T::alive == 1); |
118 | assert(T::constructed == 0); |
119 | assert(T::assigned == 0); |
120 | assert(T::destroyed == 0); |
121 | } |
122 | assert(T::alive == 0); |
123 | assert(T::destroyed == 1); |
124 | { |
125 | T t; |
126 | const T& ct = t; |
127 | T::reset_constructors(); |
128 | test_ref<T const&&>(); |
129 | test_ref<T const&&>(std::move(t)); |
130 | test_ref<T const&&>(std::move(ct)); |
131 | assert(T::alive == 1); |
132 | assert(T::constructed == 0); |
133 | assert(T::assigned == 0); |
134 | assert(T::destroyed == 0); |
135 | } |
136 | assert(T::alive == 0); |
137 | assert(T::destroyed == 1); |
138 | { |
139 | static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, "" ); |
140 | static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, "" ); |
141 | } |
142 | #endif |
143 | } |
144 | |
145 | |
146 | int main(int, char**) |
147 | { |
148 | test<int>(); |
149 | test<int>(args: 3); |
150 | static_assert(constexpr_test<int>(), "" ); |
151 | static_assert(constexpr_test<int>(args: 3), "" ); |
152 | |
153 | { |
154 | optional<const int> o(42); |
155 | optional<const int> o2(std::move(o)); |
156 | assert(*o2 == 42); |
157 | } |
158 | { |
159 | using T = TestTypes::TestType; |
160 | T::reset(); |
161 | optional<T> rhs; |
162 | assert(T::alive == 0); |
163 | const optional<T> lhs(std::move(rhs)); |
164 | assert(lhs.has_value() == false); |
165 | assert(rhs.has_value() == false); |
166 | assert(T::alive == 0); |
167 | } |
168 | TestTypes::TestType::reset(); |
169 | { |
170 | using T = TestTypes::TestType; |
171 | T::reset(); |
172 | optional<T> rhs(42); |
173 | assert(T::alive == 1); |
174 | assert(T::value_constructed == 1); |
175 | assert(T::move_constructed == 0); |
176 | const optional<T> lhs(std::move(rhs)); |
177 | assert(lhs.has_value()); |
178 | assert(rhs.has_value()); |
179 | assert(lhs.value().value == 42); |
180 | assert(rhs.value().value == -1); |
181 | assert(T::move_constructed == 1); |
182 | assert(T::alive == 2); |
183 | } |
184 | TestTypes::TestType::reset(); |
185 | { |
186 | using namespace ConstexprTestTypes; |
187 | test<TestType>(); |
188 | test<TestType>(42); |
189 | } |
190 | { |
191 | using namespace TrivialTestTypes; |
192 | test<TestType>(); |
193 | test<TestType>(42); |
194 | } |
195 | { |
196 | test_throwing_ctor(); |
197 | } |
198 | { |
199 | struct ThrowsMove { |
200 | ThrowsMove() noexcept(false) {} |
201 | ThrowsMove(ThrowsMove const&) noexcept(false) {} |
202 | ThrowsMove(ThrowsMove &&) noexcept(false) {} |
203 | }; |
204 | static_assert(!std::is_nothrow_move_constructible<optional<ThrowsMove>>::value, "" ); |
205 | struct NoThrowMove { |
206 | NoThrowMove() noexcept(false) {} |
207 | NoThrowMove(NoThrowMove const&) noexcept(false) {} |
208 | NoThrowMove(NoThrowMove &&) noexcept(true) {} |
209 | }; |
210 | static_assert(std::is_nothrow_move_constructible<optional<NoThrowMove>>::value, "" ); |
211 | } |
212 | { |
213 | test_reference_extension(); |
214 | } |
215 | { |
216 | constexpr std::optional<int> o1{4}; |
217 | constexpr std::optional<int> o2 = std::move(o1); |
218 | static_assert( *o2 == 4, "" ); |
219 | } |
220 | |
221 | return 0; |
222 | } |
223 | |