1 | //===----------------------------------------------------------------------===// |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | // |
6 | //===----------------------------------------------------------------------===// |
7 | |
8 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
9 | |
10 | // constexpr expected(const expected& rhs); |
11 | // |
12 | // Effects: If rhs.has_value() is true, direct-non-list-initializes val with *rhs. |
13 | // Otherwise, direct-non-list-initializes unex with rhs.error(). |
14 | // |
15 | // Postconditions: rhs.has_value() == this->has_value(). |
16 | // |
17 | // Throws: Any exception thrown by the initialization of val or unex. |
18 | // |
19 | // Remarks: This constructor is defined as deleted unless |
20 | // - is_copy_constructible_v<T> is true and |
21 | // - is_copy_constructible_v<E> is true. |
22 | // |
23 | // This constructor is trivial if |
24 | // - is_trivially_copy_constructible_v<T> is true and |
25 | // - is_trivially_copy_constructible_v<E> is true. |
26 | |
27 | #include <cassert> |
28 | #include <expected> |
29 | #include <type_traits> |
30 | #include <utility> |
31 | |
32 | #include "test_macros.h" |
33 | #include "../../types.h" |
34 | |
35 | struct NonCopyable { |
36 | NonCopyable(const NonCopyable&) = delete; |
37 | }; |
38 | |
39 | struct CopyableNonTrivial { |
40 | int i; |
41 | constexpr CopyableNonTrivial(int ii) : i(ii) {} |
42 | constexpr CopyableNonTrivial(const CopyableNonTrivial& o) { i = o.i; } |
43 | friend constexpr bool operator==(const CopyableNonTrivial&, const CopyableNonTrivial&) = default; |
44 | }; |
45 | |
46 | // Test: This constructor is defined as deleted unless |
47 | // - is_copy_constructible_v<T> is true and |
48 | // - is_copy_constructible_v<E> is true. |
49 | static_assert(std::is_copy_constructible_v<std::expected<int, int>>); |
50 | static_assert(std::is_copy_constructible_v<std::expected<CopyableNonTrivial, int>>); |
51 | static_assert(std::is_copy_constructible_v<std::expected<int, CopyableNonTrivial>>); |
52 | static_assert(std::is_copy_constructible_v<std::expected<CopyableNonTrivial, CopyableNonTrivial>>); |
53 | static_assert(!std::is_copy_constructible_v<std::expected<NonCopyable, int>>); |
54 | static_assert(!std::is_copy_constructible_v<std::expected<int, NonCopyable>>); |
55 | static_assert(!std::is_copy_constructible_v<std::expected<NonCopyable, NonCopyable>>); |
56 | |
57 | // Test: This constructor is trivial if |
58 | // - is_trivially_copy_constructible_v<T> is true and |
59 | // - is_trivially_copy_constructible_v<E> is true. |
60 | static_assert(std::is_trivially_copy_constructible_v<std::expected<int, int>>); |
61 | static_assert(!std::is_trivially_copy_constructible_v<std::expected<CopyableNonTrivial, int>>); |
62 | static_assert(!std::is_trivially_copy_constructible_v<std::expected<int, CopyableNonTrivial>>); |
63 | static_assert(!std::is_trivially_copy_constructible_v<std::expected<CopyableNonTrivial, CopyableNonTrivial>>); |
64 | |
65 | constexpr bool test() { |
66 | // copy the value non-trivial |
67 | { |
68 | const std::expected<CopyableNonTrivial, int> e1(5); |
69 | auto e2 = e1; |
70 | assert(e2.has_value()); |
71 | assert(e2.value().i == 5); |
72 | } |
73 | |
74 | // copy the error non-trivial |
75 | { |
76 | const std::expected<int, CopyableNonTrivial> e1(std::unexpect, 5); |
77 | auto e2 = e1; |
78 | assert(!e2.has_value()); |
79 | assert(e2.error().i == 5); |
80 | } |
81 | |
82 | // copy the value trivial |
83 | { |
84 | const std::expected<int, int> e1(5); |
85 | auto e2 = e1; |
86 | assert(e2.has_value()); |
87 | assert(e2.value() == 5); |
88 | } |
89 | |
90 | // copy the error trivial |
91 | { |
92 | const std::expected<int, int> e1(std::unexpect, 5); |
93 | auto e2 = e1; |
94 | assert(!e2.has_value()); |
95 | assert(e2.error() == 5); |
96 | } |
97 | |
98 | // copy TailClobberer as value |
99 | { |
100 | const std::expected<TailClobberer<0>, bool> e1; |
101 | auto e2 = e1; |
102 | assert(e2.has_value()); |
103 | } |
104 | |
105 | // copy TailClobberer as error |
106 | { |
107 | const std::expected<bool, TailClobberer<1>> e1(std::unexpect); |
108 | auto e2 = e1; |
109 | assert(!e2.has_value()); |
110 | } |
111 | |
112 | return true; |
113 | } |
114 | |
115 | void testException() { |
116 | #ifndef TEST_HAS_NO_EXCEPTIONS |
117 | struct Throwing { |
118 | Throwing() = default; |
119 | Throwing(const Throwing&) { throw Except{}; } |
120 | }; |
121 | |
122 | // throw on copying value |
123 | { |
124 | const std::expected<Throwing, int> e1; |
125 | try { |
126 | [[maybe_unused]] auto e2 = e1; |
127 | assert(false); |
128 | } catch (Except) { |
129 | } |
130 | } |
131 | |
132 | // throw on copying error |
133 | { |
134 | const std::expected<int, Throwing> e1(std::unexpect); |
135 | try { |
136 | [[maybe_unused]] auto e2 = e1; |
137 | assert(false); |
138 | } catch (Except) { |
139 | } |
140 | } |
141 | |
142 | #endif // TEST_HAS_NO_EXCEPTIONS |
143 | } |
144 | |
145 | int main(int, char**) { |
146 | test(); |
147 | static_assert(test()); |
148 | testException(); |
149 | return 0; |
150 | } |
151 | |