Skip to content

Commit 7ded345

Browse files
authored
[libc++] Implement LWG3940: std::expected<void, E>::value() also needs E to be copy constructible (#71819)
This patch includes the fix for [LWG3940](https://cplusplus.github.io/LWG/issue3940) (`std::expected<void, E>::value()` also needs `E` to be copy constructible)
1 parent f670112 commit 7ded345

File tree

4 files changed

+53
-12
lines changed

4 files changed

+53
-12
lines changed

libcxx/docs/Status/Cxx2cIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"`3927 <https://wg21.link/LWG3927>`__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","",""
1616
"`3935 <https://wg21.link/LWG3935>`__","``template<class X> constexpr complex& operator=(const complex<X>&)`` has no specification","Varna June 2023","|Complete|","3.4",""
1717
"`3938 <https://wg21.link/LWG3938>`__","Cannot use ``std::expected`` monadic ops with move-only ``error_type``","Varna June 2023","|Complete|","18.0",""
18-
"`3940 <https://wg21.link/LWG3940>`__","``std::expected<void, E>::value()`` also needs ``E`` to be copy constructible","Varna June 2023","","",""
18+
"`3940 <https://wg21.link/LWG3940>`__","``std::expected<void, E>::value()`` also needs ``E`` to be copy constructible","Varna June 2023","|Complete|","18.0",""
1919
"","","","","",""
2020
"`2392 <https://wg21.link/LWG2392>`__","""character type"" is used but not defined","Kona November 2023","","",""
2121
"`3203 <https://wg21.link/LWG3203>`__","``span`` element access invalidation","Kona November 2023","","",""

libcxx/include/__expected/expected.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,12 +1150,14 @@ class expected<_Tp, _Err> {
11501150
}
11511151

11521152
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
1153+
static_assert(is_copy_constructible_v<_Err>);
11531154
if (!__has_val_) {
11541155
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
11551156
}
11561157
}
11571158

11581159
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
1160+
static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>);
11591161
if (!__has_val_) {
11601162
std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
11611163
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
// UNSUPPORTED: no-rtti
10+
// UNSUPPORTED: no-exceptions
11+
12+
// constexpr void value() const &;
13+
// Mandates: is_copy_constructible_v<E> is true.
14+
15+
// constexpr void value() &&;
16+
// Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
17+
18+
#include <expected>
19+
20+
#include "MoveOnly.h"
21+
22+
struct CopyOnly {
23+
CopyOnly() = default;
24+
CopyOnly(const CopyOnly&) = default;
25+
CopyOnly(CopyOnly&&) = delete;
26+
};
27+
28+
void test() {
29+
// MoveOnly type as error_type
30+
std::expected<void, MoveOnly> e(std::unexpect, 5);
31+
32+
e.value(); // expected-note {{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
33+
// expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>'}}
34+
// expected-error@*:* {{call to deleted constructor of 'MoveOnly'}}
35+
36+
std::move(e)
37+
.value(); // expected-note {{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
38+
// expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>'}}
39+
40+
// CopyOnly type as error_type
41+
std::expected<void, CopyOnly> e2(std::unexpect);
42+
// expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
43+
44+
e2.value();
45+
46+
std::move(e2)
47+
.value(); // expected-note {{in instantiation of member function 'std::expected<void, CopyOnly>::value' requested here}}
48+
// expected-error@*:* {{static assertion failed due to requirement 'is_move_constructible_v<CopyOnly>'}}
49+
// expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
50+
}

libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,6 @@ void testException() {
6565
}
6666
}
6767

68-
// MoveOnly
69-
{
70-
std::expected<void, MoveOnly> e(std::unexpect, 5);
71-
try {
72-
std::move(e).value();
73-
assert(false);
74-
} catch (const std::bad_expected_access<MoveOnly>& ex) {
75-
assert(ex.error() == 5);
76-
}
77-
}
78-
7968
#endif // TEST_HAS_NO_EXCEPTIONS
8069
}
8170

0 commit comments

Comments
 (0)