xref: /llvm-project/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp (revision 5f2da9c80db99c302de9938d5785e43a3d71fa6f)
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& operator=(const expected& rhs);
11 //
12 // Effects:
13 // - If this->has_value() && rhs.has_value() is true, no effects.
14 // - Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false;
15 // - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
16 // - Otherwise, equivalent to unex = rhs.error().
17 //
18 // Returns: *this.
19 //
20 // Remarks: This operator is defined as deleted unless is_copy_assignable_v<E> is true and is_copy_constructible_v<E> is true.
21 
22 #include <cassert>
23 #include <concepts>
24 #include <expected>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "../../types.h"
29 #include "test_macros.h"
30 
31 struct NotCopyConstructible {
32   NotCopyConstructible(const NotCopyConstructible&)            = delete;
33   NotCopyConstructible& operator=(const NotCopyConstructible&) = default;
34 };
35 
36 struct NotCopyAssignable {
37   NotCopyAssignable(const NotCopyAssignable&)            = default;
38   NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
39 };
40 
41 // Test constraints
42 static_assert(std::is_copy_assignable_v<std::expected<void, int>>);
43 
44 // !is_copy_assignable_v<E>
45 static_assert(!std::is_copy_assignable_v<std::expected<void, NotCopyAssignable>>);
46 
47 // !is_copy_constructible_v<E>
48 static_assert(!std::is_copy_assignable_v<std::expected<void, NotCopyConstructible>>);
49 
50 constexpr bool test() {
51   // If this->has_value() && rhs.has_value() is true, no effects.
52   {
53     std::expected<void, int> e1;
54     std::expected<void, int> e2;
55     decltype(auto) x = (e1 = e2);
56     static_assert(std::same_as<decltype(x), std::expected<void, int>&>);
57     assert(&x == &e1);
58     assert(e1.has_value());
59   }
60 
61   // Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false;
62   {
63     Traced::state state{};
64     std::expected<void, Traced> e1;
65     std::expected<void, Traced> e2(std::unexpect, state, 5);
66     decltype(auto) x = (e1 = e2);
67     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
68     assert(&x == &e1);
69     assert(!e1.has_value());
70     assert(e1.error().data_ == 5);
71 
72     assert(state.copyCtorCalled);
73   }
74 
75   // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
76   {
77     Traced::state state{};
78     std::expected<void, Traced> e1(std::unexpect, state, 5);
79     std::expected<void, Traced> e2;
80     decltype(auto) x = (e1 = e2);
81     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
82     assert(&x == &e1);
83     assert(e1.has_value());
84 
85     assert(state.dtorCalled);
86   }
87 
88   // Otherwise, equivalent to unex = rhs.error().
89   {
90     Traced::state state{};
91     std::expected<void, Traced> e1(std::unexpect, state, 5);
92     std::expected<void, Traced> e2(std::unexpect, state, 10);
93     decltype(auto) x = (e1 = e2);
94     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
95     assert(&x == &e1);
96     assert(!e1.has_value());
97     assert(e1.error().data_ == 10);
98 
99     assert(state.copyAssignCalled);
100   }
101 
102   return true;
103 }
104 
105 void testException() {
106 #ifndef TEST_HAS_NO_EXCEPTIONS
107   std::expected<void, ThrowOnCopyConstruct> e1(std::in_place);
108   std::expected<void, ThrowOnCopyConstruct> e2(std::unexpect);
109   try {
110     e1 = e2;
111     assert(false);
112   } catch (Except) {
113     assert(e1.has_value());
114   }
115 #endif // TEST_HAS_NO_EXCEPTIONS
116 }
117 
118 int main(int, char**) {
119   test();
120   static_assert(test());
121   testException();
122   return 0;
123 }
124