1a9e65961SEric Fiselier //===----------------------------------------------------------------------===//
2a9e65961SEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9e65961SEric Fiselier //
7a9e65961SEric Fiselier //===----------------------------------------------------------------------===//
8a9e65961SEric Fiselier 
931cbe0f2SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
10e9c66ad9SMehdi Amini 
112659663eSLouis Dionne // Throwing bad_optional_access is supported starting in macosx10.13
12*c360553cSLouis Dionne // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions
13e9c66ad9SMehdi Amini 
14a9e65961SEric Fiselier // <optional>
15a9e65961SEric Fiselier 
16c1bcd4c1SMarshall Clow // constexpr optional(optional<T>&& rhs);
17a9e65961SEric Fiselier 
18a9e65961SEric Fiselier #include <optional>
19a9e65961SEric Fiselier #include <type_traits>
20a9e65961SEric Fiselier #include <cassert>
21a9e65961SEric Fiselier 
22a9e65961SEric Fiselier #include "test_macros.h"
23cc89063bSNico Weber #include "archetypes.h"
24a9e65961SEric Fiselier 
25a9e65961SEric Fiselier using std::optional;
26a9e65961SEric Fiselier 
27a9e65961SEric Fiselier template <class T, class ...InitArgs>
test(InitArgs &&...args)28a9e65961SEric Fiselier void test(InitArgs&&... args)
29a9e65961SEric Fiselier {
30a9e65961SEric Fiselier     const optional<T> orig(std::forward<InitArgs>(args)...);
31a9e65961SEric Fiselier     optional<T> rhs(orig);
32a9e65961SEric Fiselier     bool rhs_engaged = static_cast<bool>(rhs);
33a9e65961SEric Fiselier     optional<T> lhs = std::move(rhs);
34a9e65961SEric Fiselier     assert(static_cast<bool>(lhs) == rhs_engaged);
35a9e65961SEric Fiselier     if (rhs_engaged)
36a9e65961SEric Fiselier         assert(*lhs == *orig);
37a9e65961SEric Fiselier }
38a9e65961SEric Fiselier 
3929b75d69SMarshall Clow template <class T, class ...InitArgs>
constexpr_test(InitArgs &&...args)4029b75d69SMarshall Clow constexpr bool constexpr_test(InitArgs&&... args)
4129b75d69SMarshall Clow {
4229b75d69SMarshall Clow     static_assert( std::is_trivially_copy_constructible_v<T>, ""); // requirement
4329b75d69SMarshall Clow     const optional<T> orig(std::forward<InitArgs>(args)...);
4429b75d69SMarshall Clow     optional<T> rhs(orig);
4529b75d69SMarshall Clow     optional<T> lhs = std::move(rhs);
4629b75d69SMarshall Clow     return (lhs.has_value() == orig.has_value()) &&
4729b75d69SMarshall Clow            (lhs.has_value() ? *lhs == *orig : true);
4829b75d69SMarshall Clow }
4929b75d69SMarshall Clow 
test_throwing_ctor()50a9e65961SEric Fiselier void test_throwing_ctor() {
51a9e65961SEric Fiselier #ifndef TEST_HAS_NO_EXCEPTIONS
52a9e65961SEric Fiselier     struct Z {
53a9e65961SEric Fiselier         Z() : count(0) {}
54a9e65961SEric Fiselier         Z(Z&& o) : count(o.count + 1)
55a9e65961SEric Fiselier         { if (count == 2) throw 6; }
56a9e65961SEric Fiselier         int count;
57a9e65961SEric Fiselier     };
58a9e65961SEric Fiselier     Z z;
59a9e65961SEric Fiselier     optional<Z> rhs(std::move(z));
60a9e65961SEric Fiselier     try
61a9e65961SEric Fiselier     {
62a9e65961SEric Fiselier         optional<Z> lhs(std::move(rhs));
63a9e65961SEric Fiselier         assert(false);
64a9e65961SEric Fiselier     }
65a9e65961SEric Fiselier     catch (int i)
66a9e65961SEric Fiselier     {
67a9e65961SEric Fiselier         assert(i == 6);
68a9e65961SEric Fiselier     }
69a9e65961SEric Fiselier #endif
70a9e65961SEric Fiselier }
71a9e65961SEric Fiselier 
72a9e65961SEric Fiselier 
73a9e65961SEric Fiselier template <class T, class ...InitArgs>
test_ref(InitArgs &&...args)74a9e65961SEric Fiselier void test_ref(InitArgs&&... args)
75a9e65961SEric Fiselier {
76a9e65961SEric Fiselier     optional<T> rhs(std::forward<InitArgs>(args)...);
77a9e65961SEric Fiselier     bool rhs_engaged = static_cast<bool>(rhs);
78a9e65961SEric Fiselier     optional<T> lhs = std::move(rhs);
79a9e65961SEric Fiselier     assert(static_cast<bool>(lhs) == rhs_engaged);
80a9e65961SEric Fiselier     if (rhs_engaged)
81a9e65961SEric Fiselier         assert(&(*lhs) == &(*rhs));
82a9e65961SEric Fiselier }
83a9e65961SEric Fiselier 
test_reference_extension()84a9e65961SEric Fiselier void test_reference_extension()
85a9e65961SEric Fiselier {
86a9e65961SEric Fiselier #if defined(_LIBCPP_VERSION) && 0 // FIXME these extensions are currently disabled.
87a9e65961SEric Fiselier     using T = TestTypes::TestType;
88a9e65961SEric Fiselier     T::reset();
89a9e65961SEric Fiselier     {
90a9e65961SEric Fiselier         T t;
91a9e65961SEric Fiselier         T::reset_constructors();
92a9e65961SEric Fiselier         test_ref<T&>();
93a9e65961SEric Fiselier         test_ref<T&>(t);
94a9e65961SEric Fiselier         assert(T::alive == 1);
95a9e65961SEric Fiselier         assert(T::constructed == 0);
96a9e65961SEric Fiselier         assert(T::assigned == 0);
97a9e65961SEric Fiselier         assert(T::destroyed == 0);
98a9e65961SEric Fiselier     }
99a9e65961SEric Fiselier     assert(T::destroyed == 1);
100a9e65961SEric Fiselier     assert(T::alive == 0);
101a9e65961SEric Fiselier     {
102a9e65961SEric Fiselier         T t;
103a9e65961SEric Fiselier         const T& ct = t;
104a9e65961SEric Fiselier         T::reset_constructors();
105a9e65961SEric Fiselier         test_ref<T const&>();
106a9e65961SEric Fiselier         test_ref<T const&>(t);
107a9e65961SEric Fiselier         test_ref<T const&>(ct);
108a9e65961SEric Fiselier         assert(T::alive == 1);
109a9e65961SEric Fiselier         assert(T::constructed == 0);
110a9e65961SEric Fiselier         assert(T::assigned == 0);
111a9e65961SEric Fiselier         assert(T::destroyed == 0);
112a9e65961SEric Fiselier     }
113a9e65961SEric Fiselier     assert(T::alive == 0);
114a9e65961SEric Fiselier     assert(T::destroyed == 1);
115a9e65961SEric Fiselier     {
116a9e65961SEric Fiselier         T t;
117a9e65961SEric Fiselier         T::reset_constructors();
118a9e65961SEric Fiselier         test_ref<T&&>();
119a9e65961SEric Fiselier         test_ref<T&&>(std::move(t));
120a9e65961SEric Fiselier         assert(T::alive == 1);
121a9e65961SEric Fiselier         assert(T::constructed == 0);
122a9e65961SEric Fiselier         assert(T::assigned == 0);
123a9e65961SEric Fiselier         assert(T::destroyed == 0);
124a9e65961SEric Fiselier     }
125a9e65961SEric Fiselier     assert(T::alive == 0);
126a9e65961SEric Fiselier     assert(T::destroyed == 1);
127a9e65961SEric Fiselier     {
128a9e65961SEric Fiselier         T t;
129a9e65961SEric Fiselier         const T& ct = t;
130a9e65961SEric Fiselier         T::reset_constructors();
131a9e65961SEric Fiselier         test_ref<T const&&>();
132a9e65961SEric Fiselier         test_ref<T const&&>(std::move(t));
133a9e65961SEric Fiselier         test_ref<T const&&>(std::move(ct));
134a9e65961SEric Fiselier         assert(T::alive == 1);
135a9e65961SEric Fiselier         assert(T::constructed == 0);
136a9e65961SEric Fiselier         assert(T::assigned == 0);
137a9e65961SEric Fiselier         assert(T::destroyed == 0);
138a9e65961SEric Fiselier     }
139a9e65961SEric Fiselier     assert(T::alive == 0);
140a9e65961SEric Fiselier     assert(T::destroyed == 1);
141a9e65961SEric Fiselier     {
142a9e65961SEric Fiselier         static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, "");
143a9e65961SEric Fiselier         static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, "");
144a9e65961SEric Fiselier     }
145a9e65961SEric Fiselier #endif
146a9e65961SEric Fiselier }
147a9e65961SEric Fiselier 
148a9e65961SEric Fiselier 
main(int,char **)1492df59c50SJF Bastien int main(int, char**)
150a9e65961SEric Fiselier {
151a9e65961SEric Fiselier     test<int>();
152a9e65961SEric Fiselier     test<int>(3);
15329b75d69SMarshall Clow     static_assert(constexpr_test<int>(), "" );
15429b75d69SMarshall Clow     static_assert(constexpr_test<int>(3), "" );
15529b75d69SMarshall Clow 
156a9e65961SEric Fiselier     {
15764428acfSEric Fiselier         optional<const int> o(42);
15864428acfSEric Fiselier         optional<const int> o2(std::move(o));
15964428acfSEric Fiselier         assert(*o2 == 42);
16064428acfSEric Fiselier     }
16164428acfSEric Fiselier     {
162a9e65961SEric Fiselier         using T = TestTypes::TestType;
163a9e65961SEric Fiselier         T::reset();
164a9e65961SEric Fiselier         optional<T> rhs;
165a9e65961SEric Fiselier         assert(T::alive == 0);
166a9e65961SEric Fiselier         const optional<T> lhs(std::move(rhs));
167a9e65961SEric Fiselier         assert(lhs.has_value() == false);
168a9e65961SEric Fiselier         assert(rhs.has_value() == false);
169a9e65961SEric Fiselier         assert(T::alive == 0);
170a9e65961SEric Fiselier     }
171a9e65961SEric Fiselier     TestTypes::TestType::reset();
172a9e65961SEric Fiselier     {
173a9e65961SEric Fiselier         using T = TestTypes::TestType;
174a9e65961SEric Fiselier         T::reset();
175a9e65961SEric Fiselier         optional<T> rhs(42);
176a9e65961SEric Fiselier         assert(T::alive == 1);
177a9e65961SEric Fiselier         assert(T::value_constructed == 1);
178a9e65961SEric Fiselier         assert(T::move_constructed == 0);
179a9e65961SEric Fiselier         const optional<T> lhs(std::move(rhs));
180a9e65961SEric Fiselier         assert(lhs.has_value());
181a9e65961SEric Fiselier         assert(rhs.has_value());
182a9e65961SEric Fiselier         assert(lhs.value().value == 42);
183a9e65961SEric Fiselier         assert(rhs.value().value == -1);
184a9e65961SEric Fiselier         assert(T::move_constructed == 1);
185a9e65961SEric Fiselier         assert(T::alive == 2);
186a9e65961SEric Fiselier     }
187a9e65961SEric Fiselier     TestTypes::TestType::reset();
188a9e65961SEric Fiselier     {
189a9e65961SEric Fiselier         using namespace ConstexprTestTypes;
190a9e65961SEric Fiselier         test<TestType>();
191a9e65961SEric Fiselier         test<TestType>(42);
192a9e65961SEric Fiselier     }
193a9e65961SEric Fiselier     {
194a9e65961SEric Fiselier         using namespace TrivialTestTypes;
195a9e65961SEric Fiselier         test<TestType>();
196a9e65961SEric Fiselier         test<TestType>(42);
197a9e65961SEric Fiselier     }
198a9e65961SEric Fiselier     {
199a9e65961SEric Fiselier         test_throwing_ctor();
200a9e65961SEric Fiselier     }
201a9e65961SEric Fiselier     {
202a9e65961SEric Fiselier         struct ThrowsMove {
203a9e65961SEric Fiselier           ThrowsMove() noexcept(false) {}
204a9e65961SEric Fiselier           ThrowsMove(ThrowsMove const&) noexcept(false) {}
205a9e65961SEric Fiselier           ThrowsMove(ThrowsMove &&) noexcept(false) {}
206a9e65961SEric Fiselier         };
207a9e65961SEric Fiselier         static_assert(!std::is_nothrow_move_constructible<optional<ThrowsMove>>::value, "");
208a9e65961SEric Fiselier         struct NoThrowMove {
209a9e65961SEric Fiselier           NoThrowMove() noexcept(false) {}
210a9e65961SEric Fiselier           NoThrowMove(NoThrowMove const&) noexcept(false) {}
211a9e65961SEric Fiselier           NoThrowMove(NoThrowMove &&) noexcept(true) {}
212a9e65961SEric Fiselier         };
213a9e65961SEric Fiselier         static_assert(std::is_nothrow_move_constructible<optional<NoThrowMove>>::value, "");
214a9e65961SEric Fiselier     }
215a9e65961SEric Fiselier     {
216a9e65961SEric Fiselier         test_reference_extension();
217a9e65961SEric Fiselier     }
218c1bcd4c1SMarshall Clow     {
219c1bcd4c1SMarshall Clow     constexpr std::optional<int> o1{4};
220c1bcd4c1SMarshall Clow     constexpr std::optional<int> o2 = std::move(o1);
221c1bcd4c1SMarshall Clow     static_assert( *o2 == 4, "" );
222c1bcd4c1SMarshall Clow     }
2232df59c50SJF Bastien 
2242df59c50SJF Bastien   return 0;
225a9e65961SEric Fiselier }
226