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