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