[PATCH] libstdc++: Add has_error and tests for std::expected
Alexander Kremer
akremer@ripple.com
Tue Jun 23 18:16:02 GMT 2026
Will move the function, thanks.
As for the DR situation, let's see what the discussion you started will lead to. I will adjust the patch accordingly once there is a conclusion - please loop me in.
My personal opinion is that this should have always been in std::expected and was simply missed by the committee back then, hence can be viewed as a defect. Having that said i also can't disagree that this technically is a new API.
Fwiw libc++ did merge it as a DR so we are in a bit of an awkward situation now. Nothing is set in stone so let's discuss and see.
Regards,
Alex
> On 23 Jun 2026, at 18:48, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Tue, 23 Jun 2026 at 17:54, Alex Kremer <akremer@ripple.com> wrote:
>>
>> This PR attempts to implement P3798 (The unexpected in std::expected).
>
> Thanks!
>
>> LEWG recommended this as DR for C++23
>> (https://github.com/cplusplus/papers/issues/2403, see poll).
>
> I'm unconvinced this should be a DR, I've started some discussions about it.
>
>> Implementation in libc++ is merged here: https://github.com/llvm/llvm-project/pull/204826
>>
>> Please advise on any documentation, tests and/or other changes that are needed to successfully land this change.
>>
>> Thanks,
>> Alex
>> ---
>> libstdc++-v3/include/bits/version.def | 5 +++--
>> libstdc++-v3/include/bits/version.h | 4 ++--
>> libstdc++-v3/include/std/expected | 6 ++++++
>> .../testsuite/20_util/expected/observers.cc | 18 ++++++++++++++++++
>> .../testsuite/20_util/expected/synopsis.cc | 2 +-
>> .../testsuite/20_util/expected/version.cc | 4 ++--
>> 6 files changed, 32 insertions(+), 7 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
>> index 40baefab4e4..d54f331d9f2 100644
>> --- a/libstdc++-v3/include/bits/version.def
>> +++ b/libstdc++-v3/include/bits/version.def
>> @@ -1594,9 +1594,10 @@ ftms = {
>>
>> ftms = {
>> name = expected;
>> + // 202606 P3798R1 The unexpected in std::expected
>> values = {
>> - v = 202211;
>> - cxxmin = 23;
>> + v = 202606;
>> + cxxmin = 23; // P3798R1 is C++29 but is accepted as DR for C++23
>> extra_cond = "__cpp_concepts >= 202002L";
>> };
>> };
>> diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
>> index de1d71fa935..fe79f448938 100644
>> --- a/libstdc++-v3/include/bits/version.h
>> +++ b/libstdc++-v3/include/bits/version.h
>> @@ -1743,9 +1743,9 @@
>>
>> #if !defined(__cpp_lib_expected)
>> # if (__cplusplus >= 202100L) && (__cpp_concepts >= 202002L)
>> -# define __glibcxx_expected 202211L
>> +# define __glibcxx_expected 202606L
>> # if defined(__glibcxx_want_all) || defined(__glibcxx_want_expected)
>> -# define __cpp_lib_expected 202211L
>> +# define __cpp_lib_expected 202606L
>> # endif
>> # endif
>> #endif /* !defined(__cpp_lib_expected) */
>> diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected
>> index fe4e1ecbf0e..7f8d0d37501 100644
>> --- a/libstdc++-v3/include/std/expected
>> +++ b/libstdc++-v3/include/std/expected
>> @@ -855,6 +855,9 @@ namespace __expected
>> _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
>> }
>>
>> + [[nodiscard]]
>> + constexpr bool has_error() const noexcept { return !has_value(); }
>> +
>
> I think I'd prefer to have this new function immediately after
> has_value(), as shown in the wording in P3798R1.
>
>> constexpr const _Er&
>> error() const & noexcept
>> {
>> @@ -1642,6 +1645,9 @@ namespace __expected
>> _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
>> }
>>
>> + [[nodiscard]]
>> + constexpr bool has_error() const noexcept { return !has_value(); }
>> +
>> constexpr const _Er&
>> error() const & noexcept
>> {
>> diff --git a/libstdc++-v3/testsuite/20_util/expected/observers.cc b/libstdc++-v3/testsuite/20_util/expected/observers.cc
>> index 31aaca352ae..84bce2eca52 100644
>> --- a/libstdc++-v3/testsuite/20_util/expected/observers.cc
>> +++ b/libstdc++-v3/testsuite/20_util/expected/observers.cc
>> @@ -59,6 +59,22 @@ test_has_value()
>> return true;
>> }
>>
>> +constexpr bool
>> +test_has_error()
>> +{
>> + std::expected<int, int> e;
>> + VERIFY( ! e.has_error() );
>> + e = std::unexpected(1);
>> + VERIFY( e.has_error() );
>> +
>> + std::expected<void, int> v;
>> + VERIFY( ! v.has_error() );
>> + v = std::unexpected(1);
>> + VERIFY( v.has_error() );
>> +
>> + return true;
>> +}
>> +
>> constexpr bool
>> test_value()
>> {
>> @@ -222,6 +238,8 @@ int main()
>> test_star();
>> static_assert( test_has_value() );
>> test_has_value();
>> + static_assert( test_has_error() );
>> + test_has_error();
>> static_assert( test_value() );
>> test_value();
>> #if __cpp_lib_constexpr_exceptions >= 202502L
>> diff --git a/libstdc++-v3/testsuite/20_util/expected/synopsis.cc b/libstdc++-v3/testsuite/20_util/expected/synopsis.cc
>> index a0d2d5bea22..8866af7887f 100644
>> --- a/libstdc++-v3/testsuite/20_util/expected/synopsis.cc
>> +++ b/libstdc++-v3/testsuite/20_util/expected/synopsis.cc
>> @@ -6,7 +6,7 @@
>>
>> #ifndef __cpp_lib_expected
>> # error "Feature-test macro for expected missing in <expected>"
>> -#elif __cpp_lib_expected != 202211L
>> +#elif __cpp_lib_expected != 202606L
>> # error "Feature-test macro for expected has wrong value in <expected>"
>> #endif
>>
>> diff --git a/libstdc++-v3/testsuite/20_util/expected/version.cc b/libstdc++-v3/testsuite/20_util/expected/version.cc
>> index 17c7fe4a5d6..f9b3011727f 100644
>> --- a/libstdc++-v3/testsuite/20_util/expected/version.cc
>> +++ b/libstdc++-v3/testsuite/20_util/expected/version.cc
>> @@ -5,7 +5,7 @@
>>
>> #ifndef __cpp_lib_expected
>> # error "Feature-test macro for expected missing in <version>"
>> -#elif __cpp_lib_expected != 202211L
>> +#elif __cpp_lib_expected != 202606L
>> # error "Feature-test macro for expected has wrong value in <version>"
>> #endif
>>
>> @@ -30,7 +30,7 @@
>>
>> #ifndef __cpp_lib_expected
>> # error "Feature-test macro for expected missing in <expected>"
>> -#elif __cpp_lib_expected != 202211L
>> +#elif __cpp_lib_expected != 202606L
>> # error "Feature-test macro for expected has wrong value in <expected>"
>> #endif
>>
>> --
>> 2.51.0
>>
>
More information about the Libstdc++
mailing list