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