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