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

source code of libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp