-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[libc++][optional] Applied [[nodiscard]]
#170045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++][optional] Applied [[nodiscard]]
#170045
Conversation
416db44 to
40cf697
Compare
|
@smallp-o-p Would you please review? |
`[[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
40cf697 to
ff99ffa
Compare
| // 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No change requested. I very wonder why we decided to expose bad_optional_access to old modes. @EricWF
Co-authored-by: William Tran-Viet <wtranviet@proton.me>
fcd651d to
6e305c1
Compare
|
@llvm/pr-subscribers-libcxx Author: Hristo Hristov (H-G-Hristov) Changes
Patch is 24.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170045.diff 5 Files Affected:
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..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@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.value_or(94);
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.value_or(94);
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).value_or(94);
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).value_or(94);
+
+#if TEST_STD_VER >= 23
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.and_then([](int&) { return std::optional<int>{82}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.and_then([](const int&) { return std::optional<int>{82}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).and_then([](int&&) { return std::optional<int>{82}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).and_then([](const int&&) { return std::optional<int>{82}; });
+
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.transform([](int&) { return std::optional<int>{94}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOpt.transform([](const int&) { return std::optional<int>{94}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(opt).transform([](int&&) { return std::optional<int>{94}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(cOpt).transform([](const int&&) { return std::optional<int>{94}; });
+
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ opt.or_else([] { return std::optional<int>{82}; });
+ // expected-warning@+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@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(optRef).value_or(z);
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOptRef.value_or(z);
+
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ optRef.and_then([](int&) { return std::optional<int>{94}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOptRef.and_then([](int&) { return std::optional<int>{94}; });
+
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ optRef.transform([](int&) { return std::optional<int>{82}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cOptRef.transform([](int&) { return std::optional<int>{82}; });
+
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ optRef.or_else([] { return std::optional<int&>{}; });
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::move(optRef).or_else([] {...
[truncated]
|
|
Thanks! This is finding stuff, including what looks like at least one bug: https://chromium-review.googlesource.com/c/chromium/src/+/7256034/2/third_party/blink/renderer/platform/fonts/font_metrics.cc |
`[[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@proton.me>
[[nodiscard]]should be applied to functions where discarding the return value is most likely a correctness issue.