https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119197
Bug ID: 119197
Summary: [feat req] `std::expected` should be nodiscard
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: arthur.j.odwyer at gmail dot com
Target Milestone: ---
See https://quuxplusone.github.io/blog/2024/12/08/should-expected-be-nodiscard/
and
https://www.reddit.com/r/cpp/comments/1h9u4us/should_stdexpected_be_nodiscard/
(notice the top comment is by STL saying "no," and his next comment reverses
his position to "strongly yes") —
using Eint = std::expected<int, std::error_code>;
Eint f_or_error() noexcept;
It is invariably problematic to discard the result of a function that uses
`expected` for error handling. That's the equivalent of enclosing an
exception-throwing function call in `try { ... } catch(...){}`, discarding any
error condition; but the language allows it to happen without any ceremony. It
should of course still be possible to write the ceremony explicitly—
(void)f_or_error();
The way we make this happen is by marking `std::expected` as [[nodiscard]].
Microsoft STL has already marked it, in
https://github.com/microsoft/STL/pull/5174
martinmoene/expected-lite has already marked it.
libc++ has fixed their tests to keep working when `std::expected` is marked
nodiscard, although their own `std::expected` is not yet marked.
Microsoft STL's commit *also* marked all the exception types, which (if
libstdc++ did the same) would immediately fix #116866.
---
In fact, if you're ever asked "When should I use variant<T,U> and when should I
use expected<T,U>, given that they are physically equivalent?" — the answer is
"expected<T,U> is designed for error-handling and is (should be) nodiscard;
variant<T,U> is more general-purpose and is not nodiscard." The
error-handlingness (i.e. the should-be-nodiscardness) of `expected` is pretty
much its single defining characteristic.
---
jwakely was initially concerned that compiler bug #85973 might have rendered
such a marking completely moot, so it was a low priority in libstdc++; but my
understanding is that this concern has been resolved: #85973 is triggered only
in circumstances much more obscure than jwakely originally thought, and in fact
marking std::expected as [[nodiscard]] would have an immediate beneficial
effect in (1) ensuring error returns are handled correctly, and (2) aligning
libstdc++'s diagnostics with MS STL's in this specific area.