xref: /llvm-project/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
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, c++17, c++20
10 
11 // template<class U = T>
12 //   constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);
13 //
14 // Constraints:
15 // - is_same_v<remove_cvref_t<U>, in_place_t> is false; and
16 // - is_same_v<expected, remove_cvref_t<U>> is false; and
17 // - remove_cvref_t<U> is not a specialization of unexpected; and
18 // - is_constructible_v<T, U> is true.
19 //
20 // Effects: Direct-non-list-initializes val with std::forward<U>(v).
21 //
22 // Postconditions: has_value() is true.
23 //
24 // Throws: Any exception thrown by the initialization of val.
25 
26 #include <cassert>
27 #include <expected>
28 #include <type_traits>
29 #include <utility>
30 
31 #include "MoveOnly.h"
32 #include "test_macros.h"
33 #include "../../types.h"
34 
35 // Test Constraints:
36 static_assert(std::is_constructible_v<std::expected<int, int>, int>);
37 
38 // is_same_v<remove_cvref_t<U>, in_place_t>
39 struct FromJustInplace {
40   FromJustInplace(std::in_place_t);
41 };
42 static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t>);
43 static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t const&>);
44 
45 // is_same_v<expected, remove_cvref_t<U>>
46 // Note that result is true because it is covered by the constructors that take expected
47 static_assert(std::is_constructible_v<std::expected<int, int>, std::expected<int, int>&>);
48 
49 // remove_cvref_t<U> is a specialization of unexpected
50 // Note that result is true because it is covered by the constructors that take unexpected
51 static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpected<int>&>);
52 
53 // !is_constructible_v<T, U>
54 struct foo {};
55 static_assert(!std::is_constructible_v<std::expected<int, int>, foo>);
56 
57 // test explicit(!is_convertible_v<U, T>)
58 struct NotConvertible {
59   explicit NotConvertible(int);
60 };
61 static_assert(std::is_convertible_v<int, std::expected<int, int>>);
62 static_assert(!std::is_convertible_v<int, std::expected<NotConvertible, int>>);
63 
64 struct CopyOnly {
65   int i;
66   constexpr CopyOnly(int ii) : i(ii) {}
67   CopyOnly(const CopyOnly&) = default;
68   CopyOnly(CopyOnly&&)      = delete;
69   friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }
70 };
71 
72 struct BaseError {};
73 struct DerivedError : BaseError {};
74 
75 template <class T, class E = int>
76 constexpr void testInt() {
77   std::expected<T, E> e(5);
78   assert(e.has_value());
79   assert(e.value() == 5);
80 }
81 
82 template <class T, class E = int>
83 constexpr void testLValue() {
84   T t(5);
85   std::expected<T, E> e(t);
86   assert(e.has_value());
87   assert(e.value() == 5);
88 }
89 
90 template <class T, class E = int>
91 constexpr void testRValue() {
92   std::expected<T, E> e(T(5));
93   assert(e.has_value());
94   assert(e.value() == 5);
95 }
96 
97 constexpr bool test() {
98   testInt<int>();
99   testInt<CopyOnly>();
100   testInt<MoveOnly>();
101   testInt<TailClobberer<0>, bool>();
102   testLValue<int>();
103   testLValue<CopyOnly>();
104   testLValue<TailClobberer<0>, bool>();
105   testRValue<int>();
106   testRValue<MoveOnly>();
107   testRValue<TailClobberer<0>, bool>();
108 
109   // Test default template argument.
110   // Without it, the template parameter cannot be deduced from an initializer list
111   {
112     struct Bar {
113       int i;
114       int j;
115       constexpr Bar(int ii, int jj) : i(ii), j(jj) {}
116     };
117 
118     std::expected<Bar, int> e({5, 6});
119     assert(e.value().i == 5);
120     assert(e.value().j == 6);
121   }
122 
123   // https://cplusplus.github.io/LWG/issue3836
124 
125   // Test &
126   {
127     std::expected<bool, DerivedError> e1(false);
128     std::expected<bool, BaseError> e2(e1);
129     assert(e2.has_value());
130     assert(!e2.value()); // yes, e2 holds "false" since LWG3836
131   }
132 
133   // Test &&
134   {
135     std::expected<bool, DerivedError> e1(false);
136     std::expected<bool, BaseError> e2(std::move(e1));
137     assert(e2.has_value());
138     assert(!e2.value()); // yes, e2 holds "false" since LWG3836
139   }
140 
141   // Test const&
142   {
143     const std::expected<bool, DerivedError> e1(false);
144     std::expected<bool, BaseError> e2(e1);
145     assert(e2.has_value());
146     assert(!e2.value()); // yes, e2 holds "false" since LWG3836
147   }
148 
149   // Test const&&
150   {
151     const std::expected<bool, DerivedError> e1(false);
152     std::expected<bool, BaseError> e2(std::move(e1));
153     assert(e2.has_value());
154     assert(!e2.value()); // yes, e2 holds "false" since LWG3836
155   }
156   return true;
157 }
158 
159 void testException() {
160 #ifndef TEST_HAS_NO_EXCEPTIONS
161   struct Throwing {
162     Throwing(int) { throw Except{}; };
163   };
164 
165   try {
166     std::expected<Throwing, int> u(5);
167     assert(false);
168   } catch (Except) {
169   }
170 #endif // TEST_HAS_NO_EXCEPTIONS
171 }
172 
173 int main(int, char**) {
174   test();
175   static_assert(test());
176   testException();
177   return 0;
178 }
179