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
35struct NotCopyConstructible {
36 NotCopyConstructible(const NotCopyConstructible&) = delete;
37 NotCopyConstructible& operator=(const NotCopyConstructible&) = default;
38};
39
40struct NotCopyAssignable {
41 NotCopyAssignable(const NotCopyAssignable&) = default;
42 NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
43};
44
45struct 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
53static_assert(std::is_assignable_v<std::expected<void, int>&, const std::unexpected<int>&>);
54
55// !is_constructible_v<E, GF>
56static_assert(
57 !std::is_assignable_v<std::expected<void, NotCopyConstructible>&, const std::unexpected<NotCopyConstructible>&>);
58
59// !is_assignable_v<E&, GF>
60static_assert(
61 !std::is_assignable_v<std::expected<void, NotCopyAssignable>&, const std::unexpected<NotCopyAssignable>&>);
62
63constexpr 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
114void 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
127int main(int, char**) {
128 test();
129 static_assert(test());
130 testException();
131 return 0;
132}
133

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