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