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