[libcxx-commits] [libcxx] [libc++][optional] Applied `[[nodiscard]]` (PR #170045)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Nov 30 23:46:58 PST 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/170045
>From ff99ffae4044fe6ca69b0a14b3ddb20461f31a8d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 20 Nov 2025 05:10:21 +0200
Subject: [PATCH] [libc++][optional] 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/optional
---
libcxx/include/optional | 69 ++++----
.../utilities/optional/nodiscard.verify.cpp | 156 ++++++++++++++++++
.../optional.monadic/and_then.pass.cpp | 16 +-
.../optional.monadic/or_else.pass.cpp | 8 +-
.../optional.monadic/transform.pass.cpp | 20 +--
5 files changed, 213 insertions(+), 56 deletions(-)
create mode 100644 libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 23b21364b1a79..50ff0232b5c22 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -275,7 +275,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
@@ -378,7 +378,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_; }
@@ -440,7 +440,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_; }
@@ -634,7 +634,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>) {
@@ -653,7 +653,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>) {
@@ -672,10 +672,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
@@ -946,22 +946,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());
}
@@ -971,25 +971,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());
@@ -1000,7 +1000,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));
@@ -1010,7 +1010,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));
@@ -1020,7 +1020,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));
@@ -1029,7 +1029,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");
@@ -1039,7 +1039,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");
@@ -1049,7 +1049,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");
@@ -1059,7 +1059,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");
@@ -1069,7 +1069,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");
@@ -1081,7 +1081,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");
@@ -1093,7 +1093,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");
@@ -1105,7 +1105,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");
@@ -1117,7 +1117,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>,
@@ -1128,7 +1128,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>,
@@ -1426,8 +1426,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);
}
@@ -1440,17 +1440,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)...);
}
@@ -1461,7 +1462,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..8e3abb6e273de
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
@@ -0,0 +1,156 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+
+struct LVal {
+ constexpr std::optional<int> operator()(int&) { return 1; }
+ std::optional<int> operator()(const int&) = delete;
+ std::optional<int> operator()(int&&) = delete;
+ std::optional<int> operator()(const int&&) = delete;
+};
+
+struct CLVal {
+ std::optional<int> operator()(int&) = delete;
+ constexpr std::optional<int> operator()(const int&) { return 1; }
+ std::optional<int> operator()(int&&) = delete;
+ std::optional<int> operator()(const int&&) = delete;
+};
+
+struct RVal {
+ std::optional<int> operator()(int&) = delete;
+ std::optional<int> operator()(const int&) = delete;
+ constexpr std::optional<int> operator()(int&&) { return 1; }
+ std::optional<int> operator()(const int&&) = delete;
+};
+
+struct CRVal {
+ std::optional<int> operator()(int&) = delete;
+ std::optional<int> operator()(const int&) = delete;
+ std::optional<int> operator()(int&&) = delete;
+ constexpr std::optional<int> operator()(const int&&) { return 1; }
+};
+
+void test() {
+ std::bad_optional_access ex;
+
+ ex.what(); // expect-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ 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(82);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.value_or(82);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).value_or(82);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).value_or(82);
+
+#if TEST_STD_VER >= 23
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.and_then(LVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.and_then(CLVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).and_then(RVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).and_then(CRVal{});
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.transform(LVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.transform(CLVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).transform(RVal{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).transform(CRVal{});
+
+ // 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
+
+#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>{82}; });
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOptRef.and_then([](int&) { return std::optional<int>{82}; });
+
+ // 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
+
+ // 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'});
+
+ 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