[libcxx-commits] [libcxx] [libc++][expected] Applied `[[nodiscard]]` (PR #170245)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Dec 1 21:28:49 PST 2025


https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/170245

[[nodiscard]] should be applied to functions where discarding the return value is most likely a correctness issue.

- https://libcxx.llvm.org/CodingGuidelines.html
- https://wg21.link/expected.bad.void
- https://wg21.link/expected.bad
- https://wg21.link/expected.expected
- https://wg21.link/expected.void
- https://wg21.link/expected.unexpected

>From e7baa25507ff2dd43536988f83d0773f9c2c432c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 2 Dec 2025 07:28:24 +0200
Subject: [PATCH] [libc++][expected] Applied `[[nodiscard]]`

[[nodiscard]] should be applied to functions where discarding the return value is most likely a correctness issue.

- https://libcxx.llvm.org/CodingGuidelines.html
- https://wg21.link/expected.bad.void
- https://wg21.link/expected.bad
- https://wg21.link/expected.expected
- https://wg21.link/expected.void
- https://wg21.link/expected.unexpected
---
 .../include/__expected/bad_expected_access.h  |  14 +-
 libcxx/include/__expected/expected.h          | 124 +++++------
 libcxx/include/__expected/unexpected.h        |   8 +-
 .../utilities/expected/nodiscard.verify.cpp   | 203 ++++++++++++++++++
 4 files changed, 277 insertions(+), 72 deletions(-)
 create mode 100644 libcxx/test/libcxx/utilities/expected/nodiscard.verify.cpp

diff --git a/libcxx/include/__expected/bad_expected_access.h b/libcxx/include/__expected/bad_expected_access.h
index 1b734389e8311..b1958101d5178 100644
--- a/libcxx/include/__expected/bad_expected_access.h
+++ b/libcxx/include/__expected/bad_expected_access.h
@@ -43,9 +43,11 @@ class _LIBCPP_EXPORTED_FROM_ABI bad_expected_access<void> : public exception {
 
 public:
 #  if _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION
-  const char* what() const noexcept override;
+  [[nodiscard]] const char* what() const noexcept override;
 #  else
-  _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override { return "bad access to std::expected"; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override {
+    return "bad access to std::expected";
+  }
 #  endif
 };
 _LIBCPP_DIAGNOSTIC_POP
@@ -55,10 +57,10 @@ class bad_expected_access : public bad_expected_access<void> {
 public:
   _LIBCPP_HIDE_FROM_ABI explicit bad_expected_access(_Err __e) : __unex_(std::move(__e)) {}
 
-  _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; }
-  _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; }
-  _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); }
-  _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); }
 
 private:
   _Err __unex_;
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index be37e8ab66ac4..b6a9211ae3cdc 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -798,25 +798,25 @@ class expected : private __expected_base<_Tp, _Err> {
     return std::addressof(this->__val());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         this->__has_val(), "expected::operator* requires the expected to contain a value");
     return this->__val();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         this->__has_val(), "expected::operator* requires the expected to contain a value");
     return this->__val();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         this->__has_val(), "expected::operator* requires the expected to contain a value");
     return std::move(this->__val());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         this->__has_val(), "expected::operator* requires the expected to contain a value");
     return std::move(this->__val());
@@ -824,9 +824,9 @@ class expected : private __expected_base<_Tp, _Err> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
     static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
     if (!this->__has_val()) {
       std::__throw_bad_expected_access<_Err>(std::as_const(error()));
@@ -834,7 +834,7 @@ class expected : private __expected_base<_Tp, _Err> {
     return this->__val();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
     static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
     if (!this->__has_val()) {
       std::__throw_bad_expected_access<_Err>(std::as_const(error()));
@@ -842,7 +842,7 @@ class expected : private __expected_base<_Tp, _Err> {
     return this->__val();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
     static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
                   "error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
     if (!this->__has_val()) {
@@ -851,7 +851,7 @@ class expected : private __expected_base<_Tp, _Err> {
     return std::move(this->__val());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
     static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
                   "error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
     if (!this->__has_val()) {
@@ -860,46 +860,46 @@ class expected : private __expected_base<_Tp, _Err> {
     return std::move(this->__val());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return this->__unex();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return this->__unex();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return std::move(this->__unex());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return std::move(this->__unex());
   }
 
   template <class _Up = remove_cv_t<_Tp>>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
     static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
     static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
     return this->__has_val() ? this->__val() : static_cast<_Tp>(std::forward<_Up>(__v));
   }
 
   template <class _Up = remove_cv_t<_Tp>>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
     static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
     static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
     return this->__has_val() ? std::move(this->__val()) : static_cast<_Tp>(std::forward<_Up>(__v));
   }
 
   template <class _Up = _Err>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
     static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
     static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
     if (has_value())
@@ -908,7 +908,7 @@ class expected : private __expected_base<_Tp, _Err> {
   }
 
   template <class _Up = _Err>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
     static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible");
     static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
     if (has_value())
@@ -919,7 +919,7 @@ class expected : private __expected_base<_Tp, _Err> {
   // [expected.void.monadic], monadic
   template <class _Func>
     requires is_constructible_v<_Err, _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
     using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Up::error_type, _Err>,
@@ -932,7 +932,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
     using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Up::error_type, _Err>,
@@ -945,7 +945,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
     using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&&>>;
     static_assert(
         __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
@@ -959,7 +959,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
     using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
     static_assert(
         __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
@@ -973,7 +973,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, _Tp&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
     static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Gp::value_type, _Tp>,
@@ -986,7 +986,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, const _Tp&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
     static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Gp::value_type, _Tp>,
@@ -999,7 +999,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, _Tp&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
     static_assert(
         __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
@@ -1013,7 +1013,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, const _Tp&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
     static_assert(
         __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
@@ -1027,7 +1027,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
     using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, error());
@@ -1043,7 +1043,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
     using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, error());
@@ -1059,7 +1059,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
     using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, std::move(error()));
@@ -1075,7 +1075,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
     using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, std::move(error()));
@@ -1091,7 +1091,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, _Tp&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
     using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(error()) must be a valid template argument for unexpected");
@@ -1103,7 +1103,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, const _Tp&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
     using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(error()) must be a valid template argument for unexpected");
@@ -1115,7 +1115,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, _Tp&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
     using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(std::move(error())) must be a valid template argument for unexpected");
@@ -1128,7 +1128,7 @@ class expected : private __expected_base<_Tp, _Err> {
 
   template <class _Func>
     requires is_constructible_v<_Tp, const _Tp&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
     using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(std::move(error())) must be a valid template argument for unexpected");
@@ -1145,8 +1145,8 @@ class expected : private __expected_base<_Tp, _Err> {
     requires(!is_void_v<_T2>)
 #  if _LIBCPP_STD_VER >= 26
             && requires {
-                 { *__x == *__y } -> __core_convertible_to<bool>;
-                 { __x.error() == __y.error() } -> __core_convertible_to<bool>;
+                 { *__x == *__y }->__core_convertible_to<bool>;
+                 { __x.error() == __y.error() }->__core_convertible_to<bool>;
                }
 #  endif
   {
@@ -1165,7 +1165,7 @@ class expected : private __expected_base<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v)
 #  if _LIBCPP_STD_VER >= 26
     requires(!__is_std_expected<_T2>::value) && requires {
-      { *__x == __v } -> __core_convertible_to<bool>;
+      { *__x == __v }->__core_convertible_to<bool>;
     }
 #  endif
   {
@@ -1176,7 +1176,7 @@ class expected : private __expected_base<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e)
 #  if _LIBCPP_STD_VER >= 26
     requires requires {
-      { __x.error() == __e.error() } -> __core_convertible_to<bool>;
+      { __x.error() == __e.error() }->__core_convertible_to<bool>;
     }
 #  endif
   {
@@ -1595,7 +1595,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   // [expected.void.obs], observers
   _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
@@ -1616,32 +1616,32 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return this->__unex();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return this->__unex();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return std::move(this->__unex());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         !this->__has_val(), "expected::error requires the expected to contain an error");
     return std::move(this->__unex());
   }
 
   template <class _Up = _Err>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
     static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
     static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
     if (has_value()) {
@@ -1651,7 +1651,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Up = _Err>
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
     static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible");
     static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
     if (has_value()) {
@@ -1663,7 +1663,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   // [expected.void.monadic], monadic
   template <class _Func>
     requires is_constructible_v<_Err, _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
     using _Up = remove_cvref_t<invoke_result_t<_Func>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
     static_assert(
@@ -1676,7 +1676,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
     using _Up = remove_cvref_t<invoke_result_t<_Func>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
     static_assert(
@@ -1689,7 +1689,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
     using _Up = remove_cvref_t<invoke_result_t<_Func>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
     static_assert(
@@ -1702,7 +1702,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
     using _Up = remove_cvref_t<invoke_result_t<_Func>>;
     static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
     static_assert(
@@ -1714,7 +1714,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
     static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Gp::value_type, _Tp>,
@@ -1726,7 +1726,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
     static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
     static_assert(is_same_v<typename _Gp::value_type, _Tp>,
@@ -1738,7 +1738,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
     static_assert(
         __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
@@ -1751,7 +1751,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
     using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
     static_assert(
         __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
@@ -1765,7 +1765,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
     using _Up = remove_cv_t<invoke_result_t<_Func>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, error());
@@ -1780,7 +1780,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
     using _Up = remove_cv_t<invoke_result_t<_Func>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, error());
@@ -1795,7 +1795,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
     using _Up = remove_cv_t<invoke_result_t<_Func>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, std::move(error()));
@@ -1810,7 +1810,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   template <class _Func>
     requires is_constructible_v<_Err, const _Err&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
     using _Up = remove_cv_t<invoke_result_t<_Func>>;
     if (!has_value()) {
       return expected<_Up, _Err>(unexpect, std::move(error()));
@@ -1824,7 +1824,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
     using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(error()) must be a valid template argument for unexpected");
@@ -1835,7 +1835,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
     using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(error()) must be a valid template argument for unexpected");
@@ -1846,7 +1846,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
     using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(std::move(error())) must be a valid template argument for unexpected");
@@ -1858,7 +1858,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
     using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>;
     static_assert(__valid_std_unexpected<_Gp>::value,
                   "The result of f(std::move(error())) must be a valid template argument for unexpected");
@@ -1875,7 +1875,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y)
 #  if _LIBCPP_STD_VER >= 26
     requires requires {
-      { __x.error() == __y.error() } -> __core_convertible_to<bool>;
+      { __x.error() == __y.error() }->__core_convertible_to<bool>;
     }
 #  endif
   {
@@ -1890,7 +1890,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y)
 #  if _LIBCPP_STD_VER >= 26
     requires requires {
-      { __x.error() == __y.error() } -> __core_convertible_to<bool>;
+      { __x.error() == __y.error() }->__core_convertible_to<bool>;
     }
 #  endif
   {
diff --git a/libcxx/include/__expected/unexpected.h b/libcxx/include/__expected/unexpected.h
index 6904889b8c6b1..fc4f52ce14adc 100644
--- a/libcxx/include/__expected/unexpected.h
+++ b/libcxx/include/__expected/unexpected.h
@@ -89,10 +89,10 @@ class unexpected {
   _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(const unexpected&) = default;
   _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(unexpected&&)      = default;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; }
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; }
-  _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); }
-  _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Err>) {
     static_assert(is_swappable_v<_Err>, "unexpected::swap requires is_swappable_v<E> to be true");
diff --git a/libcxx/test/libcxx/utilities/expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..afaeb9f09642f
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/expected/nodiscard.verify.cpp
@@ -0,0 +1,203 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <expected>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <expected>
+#include <utility>
+
+struct LVal {
+  constexpr std::expected<int, int> operator()(int&) { return 1; }
+  std::expected<int, int> operator()(const int&)  = delete;
+  std::expected<int, int> operator()(int&&)       = delete;
+  std::expected<int, int> operator()(const int&&) = delete;
+};
+
+struct CLVal {
+  std::expected<int, int> operator()(int&) = delete;
+  constexpr std::expected<int, int> operator()(const int&) { return 1; }
+  std::expected<int, int> operator()(int&&)       = delete;
+  std::expected<int, int> operator()(const int&&) = delete;
+};
+
+struct RVal {
+  std::expected<int, int> operator()(int&)       = delete;
+  std::expected<int, int> operator()(const int&) = delete;
+  constexpr std::expected<int, int> operator()(int&&) { return 1; }
+  std::expected<int, int> operator()(const int&&) = delete;
+};
+
+struct CRVal {
+  std::expected<int, int> operator()(int&)       = delete;
+  std::expected<int, int> operator()(const int&) = delete;
+  std::expected<int, int> operator()(int&&)      = delete;
+  constexpr std::expected<int, int> operator()(const int&&) { return 1; }
+};
+
+void test() {
+  // [expected.bad.void]
+
+  class VoidBadExpectedAccess : public std::bad_expected_access<void> {};
+
+  VoidBadExpectedAccess voidEx;
+  const VoidBadExpectedAccess cVoidEx{};
+
+  voidEx.what();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVoidEx.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // [expected.bad]
+
+  std::bad_expected_access<char> ex('z');
+  const std::bad_expected_access<char> cEx('z');
+
+  ex.error();             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cEx.error();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(ex).error();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cEx).error(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // [expected.expected]
+
+  std::expected<int, int> exp;
+  const std::expected<int, int> cExp{};
+
+  *cExp;            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *exp;             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *std::move(cExp); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *std::move(exp);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  exp.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  cExp.value();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.value();             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).value();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  cExp.error();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.error();             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).error(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).error();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.value_or(94);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).value_or(94);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.error_or(82);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).error_or(82);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.and_then(LVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.and_then(CLVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).and_then(RVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).and_then(CRVal{});
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.or_else(LVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.or_else(CLVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).or_else(RVal{});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).or_else(CRVal{});
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.transform([](int) { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.transform([](const int) { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).transform([](int&&) { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).transform([](const int&&) { return 94; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  exp.transform_error([](int) { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cExp.transform_error([](const int) { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(exp).transform_error([](int&&) { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cExp).transform_error([](const int&&) { return 82; });
+
+  // [expected.void]
+
+  std::expected<void, int> vExp;
+  const std::expected<void, int> cVExp{};
+
+  vExp.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  vExp.error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cVExp).error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(vExp).error();
+
+  vExp.error_or(94);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.error_or(94); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  vExp.and_then([]() -> std::expected<int, int> { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.and_then([]() -> std::expected<int, int> { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(vExp).and_then([]() -> std::expected<int, int> { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cVExp).and_then([]() -> std::expected<int, int> { return 82; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  vExp.or_else([](auto) -> std::expected<void, long> { return {}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.or_else([](auto) -> std::expected<void, long> { return {}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(vExp).or_else([](auto) -> std::expected<void, long> { return {}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cVExp).or_else([](auto) -> std::expected<void, long> { return {}; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  vExp.transform([]() -> int { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.transform([]() -> int { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(vExp).transform([]() -> int { return 94; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cVExp).transform([]() -> int { return 94; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  vExp.transform_error([](auto) -> int { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cVExp.transform_error([](auto) -> int { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(vExp).transform_error([](auto) -> int { return 82; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cVExp).transform_error([](auto) -> int { return 82; });
+
+  // [expected.unexpected]
+
+  std::unexpected<char> unex('z');
+  const std::unexpected<char> cUnex('z');
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  unex.error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cUnex.error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(unex).error();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cUnex).error();
+}



More information about the libcxx-commits mailing list