Skip to content

Commit 823efd8

Browse files
authored
[libc++] Implement P3798R1: The unexpected in std::expected (#219236)
Closes llvm/llvm-project#204394 Re-application of llvm/llvm-project#204826 (45a65bb) Implements P3798R1 and related tests.
1 parent 7e1652b commit 823efd8

11 files changed

Lines changed: 109 additions & 7 deletions

File tree

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ Status
558558
---------------------------------------------------------- -----------------
559559
**C++29**
560560
----------------------------------------------------------------------------
561+
``__cpp_lib_expected`` ``202606L``
562+
---------------------------------------------------------- -----------------
561563
``__cpp_lib_map_lookup`` *unimplemented*
562564
---------------------------------------------------------- -----------------
563565
``__cpp_lib_mdspan_copy`` *unimplemented*

libcxx/docs/ReleaseNotes/24.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Implemented Papers
4747
- P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)
4848
- P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__)
4949
- P0528R3: The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange (`Github <https://llvm.org/PR76180>`__)
50+
- P3798R1: The unexpected in ``std::expected`` (`Github <https://llvm.org/PR204394>`__)
5051

5152
Improvements and New Features
5253
-----------------------------

libcxx/docs/Status/Cxx29Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"`P4101R1 <https://wg21.link/P4101R1>`__","Consteval-only Values for C++26","2026-06 (Brno)","","","`#204391 <https://github.com/llvm/llvm-project/issues/204391>`__","Voted as a Defect Report."
44
"`P2414R12 <https://wg21.link/P2414R12>`__","Pointer lifetime-end zap proposed solutions","2026-06 (Brno)","","","`#204392 <https://github.com/llvm/llvm-project/issues/204392>`__","Voted as a Defect Report."
55
"`P3319R6 <https://wg21.link/P3319R6>`__","Add an ``iota`` object for ``simd`` (and more)","2026-06 (Brno)","","","`#204393 <https://github.com/llvm/llvm-project/issues/204393>`__",""
6-
"`P3798R1 <https://wg21.link/P3798R1>`__","The unexpected in ``std::expected``","2026-06 (Brno)","","","`#204394 <https://github.com/llvm/llvm-project/issues/204394>`__",""
6+
"`P3798R1 <https://wg21.link/P3798R1>`__","The unexpected in ``std::expected``","2026-06 (Brno)","|Complete|","24","`#204394 <https://github.com/llvm/llvm-project/issues/204394>`__",""
77
"`P3052R2 <https://wg21.link/P3052R2>`__","``view_interface::at()``","2026-06 (Brno)","","","`#204395 <https://github.com/llvm/llvm-project/issues/204395>`__",""
88
"`P4206R0 <https://wg21.link/P4206R0>`__","Revert string support in ``std::constant_wrapper``","2026-06 (Brno)","|Complete|","23","`#203336 <https://github.com/llvm/llvm-project/issues/203336>`__","Applied as a Defect Report."
99
"`P3395R6 <https://wg21.link/P3395R6>`__","Fix encoding issues and add a formatter for ``std::error_code``","2026-06 (Brno)","","","`#204396 <https://github.com/llvm/llvm-project/issues/204396>`__",""

libcxx/include/__expected/expected.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,10 @@ class expected : private __expected_base<_Tp, _Err> {
827827

828828
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
829829

830+
# if _LIBCPP_STD_VER >= 29
831+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_error() const noexcept { return !this->has_value(); }
832+
# endif
833+
830834
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
831835
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
832836
if (!this->__has_val()) {
@@ -1601,6 +1605,10 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
16011605

16021606
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
16031607

1608+
# if _LIBCPP_STD_VER >= 29
1609+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_error() const noexcept { return !this->has_value(); }
1610+
# endif
1611+
16041612
_LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
16051613
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
16061614
this->__has_val(), "expected::operator* requires the expected to contain a value");

libcxx/include/version

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ __cpp_lib_erase_if 202002L <deque> <forward
112112
__cpp_lib_exchange_function 201304L <utility>
113113
__cpp_lib_execution 201902L <execution>
114114
201603L // C++17
115-
__cpp_lib_expected 202211L <expected>
115+
__cpp_lib_expected 202606L <expected>
116+
202211L // C++23
116117
__cpp_lib_filesystem 201703L <filesystem>
117118
__cpp_lib_flat_map 202511L <flat_map>
118119
__cpp_lib_flat_set 202511L <flat_set>
@@ -661,6 +662,8 @@ __cpp_lib_void_t 201411L <type_traits>
661662
#endif
662663

663664
#if _LIBCPP_STD_VER >= 29
665+
# undef __cpp_lib_expected
666+
# define __cpp_lib_expected 202606L
664667
// # define __cpp_lib_map_lookup 202606L
665668
// # define __cpp_lib_mdspan_copy 202606L
666669
// # define __cpp_lib_pointer_tag_pair 202606L

libcxx/test/libcxx/utilities/expected/nodiscard.verify.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <expected>
1616
#include <utility>
1717

18+
#include "test_macros.h"
19+
1820
void test() {
1921
// [expected.bad.void]
2022

@@ -47,6 +49,9 @@ void test() {
4749
*std::move(exp); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
4850

4951
exp.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
52+
#if TEST_STD_VER >= 29
53+
exp.has_error(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
54+
#endif
5055

5156
cExp.value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
5257
exp.value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -110,6 +115,9 @@ void test() {
110115
const std::expected<void, int> cVExp{};
111116

112117
vExp.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
118+
#if TEST_STD_VER >= 29
119+
vExp.has_error(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
120+
#endif
113121

114122
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
115123
cVExp.error();

libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@
132132
# ifndef __cpp_lib_expected
133133
# error "__cpp_lib_expected should be defined in c++29"
134134
# endif
135-
# if __cpp_lib_expected != 202211L
136-
# error "__cpp_lib_expected should have the value 202211L in c++29"
135+
# if __cpp_lib_expected != 202606L
136+
# error "__cpp_lib_expected should have the value 202606L in c++29"
137137
# endif
138138

139139
# if !defined(_LIBCPP_VERSION)

libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9241,8 +9241,8 @@
92419241
# ifndef __cpp_lib_expected
92429242
# error "__cpp_lib_expected should be defined in c++29"
92439243
# endif
9244-
# if __cpp_lib_expected != 202211L
9245-
# error "__cpp_lib_expected should have the value 202211L in c++29"
9244+
# if __cpp_lib_expected != 202606L
9245+
# error "__cpp_lib_expected should have the value 202606L in c++29"
92469246
# endif
92479247

92489248
# if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
// REQUIRES: std-at-least-c++29
10+
11+
// constexpr bool has_error() const noexcept;
12+
13+
#include <cassert>
14+
#include <concepts>
15+
#include <expected>
16+
17+
#include "../../types.h"
18+
19+
constexpr bool test() {
20+
{
21+
const std::expected<int, int> e(std::unexpect, 5);
22+
static_assert(noexcept(e.has_error()));
23+
std::same_as<bool> decltype(auto) has_err = e.has_error();
24+
assert(has_err);
25+
}
26+
27+
{
28+
const std::expected<int, int> e(5);
29+
assert(!e.has_error());
30+
}
31+
32+
return true;
33+
}
34+
35+
int main(int, char**) {
36+
test();
37+
static_assert(test());
38+
39+
return 0;
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
// REQUIRES: std-at-least-c++29
10+
11+
// constexpr bool has_error() const noexcept;
12+
13+
#include <cassert>
14+
#include <concepts>
15+
#include <expected>
16+
17+
#include "../../types.h"
18+
19+
constexpr bool test() {
20+
{
21+
const std::expected<void, int> e(std::unexpect, 5);
22+
static_assert(noexcept(e.has_error()));
23+
std::same_as<bool> decltype(auto) has_err = e.has_error();
24+
assert(has_err);
25+
}
26+
27+
{
28+
const std::expected<void, int> e;
29+
assert(!e.has_error());
30+
}
31+
32+
return true;
33+
}
34+
35+
int main(int, char**) {
36+
test();
37+
static_assert(test());
38+
39+
return 0;
40+
}

0 commit comments

Comments
 (0)