[libcxx-commits] [libcxx] 63ea393 - [libc++][optional] Applied `[[nodiscard]]` (#170045)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Dec 11 21:59:53 PST 2025


Author: Hristo Hristov
Date: 2025-12-12T07:59:48+02:00
New Revision: 63ea393f969b9fe8be3f80b38eb2b47063aa6d40

URL: https://github.com/llvm/llvm-project/commit/63ea393f969b9fe8be3f80b38eb2b47063aa6d40
DIFF: https://github.com/llvm/llvm-project/commit/63ea393f969b9fe8be3f80b38eb2b47063aa6d40.diff

LOG: [libc++][optional] Applied `[[nodiscard]]` (#170045)

`[[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/optional

---------

Co-authored-by: William Tran-Viet <wtranviet at proton.me>

Added: 
    libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp

Modified: 
    libcxx/include/optional
    libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp
    libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp
    libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/optional b/libcxx/include/optional
index 7b979d3d6d577..95b7d548f2560 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -340,7 +340,7 @@ public:
   _LIBCPP_HIDE_FROM_ABI bad_optional_access& operator=(const bad_optional_access&) _NOEXCEPT = default;
   // Get the key function ~bad_optional_access() into the dylib
   ~bad_optional_access() _NOEXCEPT override;
-  const char* what() const _NOEXCEPT override;
+  [[__nodiscard__]] const char* what() const _NOEXCEPT override;
 };
 
 } // namespace std
@@ -443,7 +443,7 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
   using value_type             = _Tp;
   using __base::__base;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() & noexcept { return this->__val_; }
   _LIBCPP_HIDE_FROM_ABI constexpr const value_type& __get() const& noexcept { return this->__val_; }
@@ -505,7 +505,7 @@ struct __optional_storage_base<_Tp, true> {
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const& noexcept { return *__value_; }
 
@@ -699,7 +699,7 @@ public:
 #      endif
 
   // [optional.iterators], iterator support
-  _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
     auto& __derived_self = static_cast<optional<_Tp>&>(*this);
     auto __ptr           = [&__derived_self]() {
       if constexpr (is_lvalue_reference_v<_Tp>) {
@@ -718,7 +718,7 @@ public:
 #      endif
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
     auto& __derived_self = static_cast<const optional<_Tp>&>(*this);
     auto* __ptr          = [&__derived_self]() {
       if constexpr (is_lvalue_reference_v<_Tp>) {
@@ -737,10 +737,10 @@ public:
 #      endif
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
     return begin() + (static_cast<optional<_Tp>&>(*this).has_value() ? 1 : 0);
   }
-  _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
     return begin() + (static_cast<const optional<_Tp>&>(*this).has_value() ? 1 : 0);
   }
 #    endif
@@ -1011,22 +1011,22 @@ public:
     return std::addressof(this->__get());
   }
 
-  _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_value(), "optional operator* called on a disengaged value");
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
     return std::move(this->__get());
   }
 
-  _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_value(), "optional operator* called on a disengaged value");
     return std::move(this->__get());
   }
@@ -1036,25 +1036,25 @@ public:
   using __base::__get;
   using __base::has_value;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
     if (!this->has_value())
       std::__throw_bad_optional_access();
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
     if (!this->has_value())
       std::__throw_bad_optional_access();
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
     if (!this->has_value())
       std::__throw_bad_optional_access();
     return std::move(this->__get());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
     if (!this->has_value())
       std::__throw_bad_optional_access();
     return std::move(this->__get());
@@ -1065,7 +1065,7 @@ public:
     requires(!(is_lvalue_reference_v<_Tp> && is_function_v<__libcpp_remove_reference_t<_Tp>>) &&
              !(is_lvalue_reference_v<_Tp> && is_array_v<__libcpp_remove_reference_t<_Tp>>))
 #    endif
-  _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>, "optional<T>::value_or: T must be copy constructible");
     static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T");
     return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v));
@@ -1075,7 +1075,7 @@ public:
 #    if _LIBCPP_STD_VER >= 26
     requires(!is_lvalue_reference_v<_Tp>)
 #    endif
-  _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>, "optional<T>::value_or: T must be move constructible");
     static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T");
     return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(std::forward<_Up>(__v));
@@ -1085,7 +1085,7 @@ public:
   template <class _Up = remove_cv_t<_Tp>>
     requires(is_lvalue_reference_v<_Tp> &&
              !(is_function_v<__libcpp_remove_reference_t<_Tp>> || is_array_v<__libcpp_remove_reference_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>, "optional<T>::value_or: T must be move constructible");
     static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T");
     return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v));
@@ -1094,7 +1094,7 @@ public:
 
 #    if _LIBCPP_STD_VER >= 23
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
     using _Up = invoke_result_t<_Func, _Tp&>;
     static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                   "Result of f(value()) must be a specialization of std::optional");
@@ -1104,7 +1104,7 @@ public:
   }
 
   template <class _Func>
-  _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 = invoke_result_t<_Func, const _Tp&>;
     static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                   "Result of f(value()) must be a specialization of std::optional");
@@ -1114,7 +1114,7 @@ public:
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
     using _Up = invoke_result_t<_Func, _Tp&&>;
     static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                   "Result of f(std::move(value())) must be a specialization of std::optional");
@@ -1124,7 +1124,7 @@ public:
   }
 
   template <class _Func>
-  _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 = invoke_result_t<_Func, const _Tp&&>;
     static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                   "Result of f(std::move(value())) must be a specialization of std::optional");
@@ -1134,7 +1134,7 @@ public:
   }
 
   template <class _Func>
-  _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&>>;
     static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
     static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
@@ -1146,7 +1146,7 @@ public:
   }
 
   template <class _Func>
-  _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&>>;
     static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
     static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
@@ -1158,7 +1158,7 @@ public:
   }
 
   template <class _Func>
-  _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&&>>;
     static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
     static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
@@ -1170,7 +1170,7 @@ public:
   }
 
   template <class _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
     using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
     static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
     static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
@@ -1182,7 +1182,7 @@ public:
   }
 
   template <invocable _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const&
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const&
     requires is_copy_constructible_v<_Tp>
   {
     static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
@@ -1193,7 +1193,7 @@ public:
   }
 
   template <invocable _Func>
-  _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) &&
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) &&
     requires is_move_constructible_v<_Tp>
   {
     static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
@@ -1491,8 +1491,8 @@ operator<=>(const optional<_Tp>& __x, const _Up& __v) {
 #    endif // _LIBCPP_STD_VER >= 20
 
 template <class _Tp, enable_if_t< is_move_constructible_v<_Tp> && is_swappable_v<_Tp>, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
-swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) {
+inline _LIBCPP_HIDE_FROM_ABI
+_LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) {
   __x.swap(__y);
 }
 
@@ -1505,17 +1505,18 @@ template <
     __make_optional_barrier_tag = __make_optional_barrier_tag{},
 #    endif
     class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) {
   return optional<decay_t<_Tp>>(std::forward<_Tp>(__v));
 }
 
 template <class _Tp, class... _Args>
-_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) {
   return optional<_Tp>(in_place, std::forward<_Args>(__args)...);
 }
 
 template <class _Tp, class _Up, class... _Args>
-_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp>
+make_optional(initializer_list<_Up> __il, _Args&&... __args) {
   return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...);
 }
 
@@ -1526,7 +1527,7 @@ struct hash< __enable_hash_helper<optional<_Tp>, remove_const_t<_Tp>> > {
   _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type;
 #    endif
 
-  _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const {
     return static_cast<bool>(__opt) ? hash<remove_const_t<_Tp>>()(*__opt) : 0;
   }
 };

diff  --git a/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..c49546cfdf4ad
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++17
+
+// <optional>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <string>
+#include <optional>
+#include <utility>
+
+#include "test_macros.h"
+
+void test() {
+  // [optional.bad.access]
+
+  std::bad_optional_access ex;
+
+  ex.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  // [optional.optional]
+
+  std::optional<int> opt;
+  const std::optional<int> cOpt;
+
+  opt.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+#if TEST_STD_VER >= 26
+  opt.begin();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  opt.end();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.end();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+  *opt;             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *cOpt;            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *std::move(opt);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *std::move(cOpt); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  opt.value();             // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.value();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(opt).value();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cOpt).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}}
+  opt.value_or(94);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.value_or(94);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(opt).value_or(94);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cOpt).value_or(94);
+
+#if TEST_STD_VER >= 23
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  opt.and_then([](int&) { return std::optional<int>{82}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.and_then([](const int&) { return std::optional<int>{82}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(opt).and_then([](int&&) { return std::optional<int>{82}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cOpt).and_then([](const int&&) { return std::optional<int>{82}; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  opt.transform([](int&) { return std::optional<int>{94}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOpt.transform([](const int&) { return std::optional<int>{94}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(opt).transform([](int&&) { return std::optional<int>{94}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(cOpt).transform([](const int&&) { return std::optional<int>{94}; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  opt.or_else([] { return std::optional<int>{82}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(opt).or_else([] { return std::optional<int>{82}; });
+#endif // TEST_STD_VER >= 23
+
+  // [optional.optional.ref]
+
+#if TEST_STD_VER >= 26
+  int z = 94;
+  std::optional<int&> optRef{z};
+  const std::optional<int&> cOptRef{z};
+
+  optRef.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  optRef.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  optRef.end();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  *optRef;  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *cOptRef; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  optRef.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}}
+  std::move(optRef).value_or(z);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOptRef.value_or(z);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  optRef.and_then([](int&) { return std::optional<int>{94}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOptRef.and_then([](int&) { return std::optional<int>{94}; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  optRef.transform([](int&) { return std::optional<int>{82}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cOptRef.transform([](int&) { return std::optional<int>{82}; });
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  optRef.or_else([] { return std::optional<int&>{}; });
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(optRef).or_else([] { return std::optional<int&>{}; });
+#endif // TEST_STD_VER >= 26
+
+  // [optional.specalg]
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::make_optional(82);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::make_optional<int>('h');
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::make_optional<std::string>({'z', 'm', 't'});
+
+  // [optional.hash]
+
+  std::hash<std::optional<int>> hash;
+
+  hash(opt); //expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}

diff  --git a/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp
index 133eed4a606bb..810283a4bc80e 100644
--- a/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp
@@ -231,8 +231,8 @@ constexpr void test_val_types() {
 constexpr void test_sfinae() {
   std::optional<NonConst> opt{};
   auto l = [](auto&& x) { return x.non_const(); };
-  opt.and_then(l);
-  std::move(opt).and_then(l);
+  (void)opt.and_then(l);
+  (void)std::move(opt).and_then(l);
 }
 
 constexpr bool test() {
@@ -245,15 +245,15 @@ constexpr bool test() {
     return std::optional<int>{};
   };
 
-  opt.and_then(never_called);
-  std::move(opt).and_then(never_called);
-  copt.and_then(never_called);
-  std::move(copt).and_then(never_called);
+  (void)opt.and_then(never_called);
+  (void)std::move(opt).and_then(never_called);
+  (void)copt.and_then(never_called);
+  (void)std::move(copt).and_then(never_called);
 
   std::optional<NoCopy> nc;
   const auto& cnc = nc;
-  std::move(cnc).and_then(NoCopy{});
-  std::move(nc).and_then(NoCopy{});
+  (void)std::move(cnc).and_then(NoCopy{});
+  (void)std::move(nc).and_then(NoCopy{});
 
   return true;
 }

diff  --git a/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp
index de0a67c1579ee..0c330e30055a2 100644
--- a/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp
@@ -49,7 +49,7 @@ constexpr bool test() {
     std::optional<int> opt;
     assert(opt.or_else([] { return std::optional<int>{0}; }) == 0);
     opt = 1;
-    opt.or_else([] {
+    (void)opt.or_else([] {
       assert(false);
       return std::optional<int>{};
     });
@@ -57,7 +57,7 @@ constexpr bool test() {
   {
     std::optional<MoveOnly> opt;
     opt = std::move(opt).or_else([] { return std::optional<MoveOnly>{MoveOnly{}}; });
-    std::move(opt).or_else([] {
+    (void)std::move(opt).or_else([] {
       assert(false);
       return std::optional<MoveOnly>{};
     });
@@ -69,7 +69,7 @@ constexpr bool test() {
     assert(opt.or_else([&] { return std::optional<int&>{i}; }) == i);
     int j = 3;
     opt   = j;
-    opt.or_else([] {
+    (void)opt.or_else([] {
       assert(false);
       return std::optional<int&>{};
     });
@@ -81,7 +81,7 @@ constexpr bool test() {
     assert(std::move(opt).or_else([&] { return std::optional<int&>{i}; }) == i);
     int j = 3;
     opt   = j;
-    std::move(opt).or_else([] {
+    (void)std::move(opt).or_else([] {
       assert(false);
       return std::optional<int&>{};
     });

diff  --git a/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp b/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
index ad2713f2ac5b8..36939f0b6b62e 100644
--- a/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp
@@ -171,8 +171,8 @@ struct NonConst {
 constexpr void test_sfinae() {
   std::optional<NonConst> opt{};
   auto l = [](auto&& x) { return x.non_const(); };
-  opt.transform(l);
-  std::move(opt).transform(l);
+  (void)opt.transform(l);
+  (void)std::move(opt).transform(l);
 }
 
 constexpr bool test() {
@@ -186,18 +186,18 @@ constexpr bool test() {
     return 0;
   };
 
-  opt.transform(never_called);
-  std::move(opt).transform(never_called);
-  copt.transform(never_called);
-  std::move(copt).transform(never_called);
+  (void)opt.transform(never_called);
+  (void)std::move(opt).transform(never_called);
+  (void)copt.transform(never_called);
+  (void)std::move(copt).transform(never_called);
 
   std::optional<NoCopy> nc;
   const auto& cnc = nc;
-  std::move(nc).transform(NoCopy{});
-  std::move(cnc).transform(NoCopy{});
+  (void)std::move(nc).transform(NoCopy{});
+  (void)std::move(cnc).transform(NoCopy{});
 
-  std::move(nc).transform(NoMove{});
-  std::move(cnc).transform(NoMove{});
+  (void)std::move(nc).transform(NoMove{});
+  (void)std::move(cnc).transform(NoMove{});
 
   return true;
 }


        


More information about the libcxx-commits mailing list