[libcxx-commits] [libcxx] [[nodiscard]] should be applied to functions where discarding the return value is most likely a correctness issue. (PR #174924)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 8 00:46:04 PST 2026
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/174924
>From 9a1908331ebc0d21344162c3e2d1b3081857bdb0 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 8 Jan 2026 10:16:34 +0200
Subject: [PATCH] [libc++][future] 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/futures
Towards #172124
---
libcxx/include/future | 46 ++++----
.../test/libcxx/thread/nodiscard.verify.cpp | 110 +++++++++++++++++-
2 files changed, 127 insertions(+), 29 deletions(-)
diff --git a/libcxx/include/future b/libcxx/include/future
index 4c0339f64de9c..4cd5e8ab2aec8 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -479,13 +479,13 @@ inline _LIBCPP_HIDE_FROM_ABI launch& operator^=(launch& __x, launch __y) {
_LIBCPP_DECLARE_STRONG_ENUM(future_status){ready, timeout, deferred};
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(future_status)
-_LIBCPP_EXPORTED_FROM_ABI const error_category& future_category() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& future_category() _NOEXCEPT;
-inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(future_errc __e) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(future_errc __e) _NOEXCEPT {
return error_code(static_cast<int>(__e), future_category());
}
-inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(future_errc __e) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(future_errc __e) _NOEXCEPT {
return error_condition(static_cast<int>(__e), future_category());
}
@@ -504,7 +504,7 @@ public:
_LIBCPP_HIDE_FROM_ABI explicit future_error(future_errc __ec) : future_error(std::make_error_code(__ec)) {}
# endif
- _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
_LIBCPP_HIDE_FROM_ABI future_error(const future_error&) _NOEXCEPT = default;
~future_error() _NOEXCEPT override;
@@ -942,15 +942,15 @@ public:
}
_LIBCPP_HIDE_FROM_ABI ~future();
- _LIBCPP_HIDE_FROM_ABI shared_future<_Rp> share() _NOEXCEPT;
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_future<_Rp> share() _NOEXCEPT;
// retrieving the value
- _LIBCPP_HIDE_FROM_ABI _Rp get();
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp get();
_LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
@@ -1013,15 +1013,15 @@ public:
}
_LIBCPP_HIDE_FROM_ABI ~future();
- _LIBCPP_HIDE_FROM_ABI shared_future<_Rp&> share() _NOEXCEPT;
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_future<_Rp&> share() _NOEXCEPT;
// retrieving the value
- _LIBCPP_HIDE_FROM_ABI _Rp& get();
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp& get();
_LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
@@ -1088,7 +1088,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
@@ -1138,7 +1138,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// retrieving the result
- _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future();
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future();
// setting the result
_LIBCPP_HIDE_FROM_ABI void set_value(const _Rp& __r);
@@ -1255,7 +1255,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// retrieving the result
- _LIBCPP_HIDE_FROM_ABI future<_Rp&> get_future();
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp&> get_future();
// setting the result
_LIBCPP_HIDE_FROM_ABI void set_value(_Rp& __r);
@@ -1365,7 +1365,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// retrieving the result
- future<void> get_future();
+ [[__nodiscard__]] future<void> get_future();
// setting the result
void set_value();
@@ -1638,10 +1638,10 @@ public:
__p_.swap(__other.__p_);
}
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; }
// result retrieval
- _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future() { return __p_.get_future(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future() { return __p_.get_future(); }
// execution
_LIBCPP_HIDE_FROM_ABI void operator()(_ArgTypes... __args);
@@ -1727,10 +1727,10 @@ public:
__p_.swap(__other.__p_);
}
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; }
// result retrieval
- _LIBCPP_HIDE_FROM_ABI future<void> get_future() { return __p_.get_future(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<void> get_future() { return __p_.get_future(); }
// execution
_LIBCPP_HIDE_FROM_ABI void operator()(_ArgTypes... __args);
@@ -1905,12 +1905,12 @@ public:
}
// retrieving the value
- _LIBCPP_HIDE_FROM_ABI const _Rp& get() const { return __state_->copy(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const _Rp& get() const { return __state_->copy(); }
_LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
@@ -1961,12 +1961,12 @@ public:
}
// retrieving the value
- _LIBCPP_HIDE_FROM_ABI _Rp& get() const { return __state_->copy(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp& get() const { return __state_->copy(); }
_LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
@@ -2022,7 +2022,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); }
// functions to check state
- _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); }
template <class _Rep, class _Period>
diff --git a/libcxx/test/libcxx/thread/nodiscard.verify.cpp b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
index c6c2ffb62d862..5dd65ae89b285 100644
--- a/libcxx/test/libcxx/thread/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -23,15 +23,113 @@
const auto timePoint = std::chrono::steady_clock::now();
void test() {
+ // [futures]
+ {
+ {
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::future_category();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::make_error_code(std::future_errc::no_state);
+
+ try {
+ } catch (std::future_error& err) {
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ err.code();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ err.what();
+ }
+ }
+
+ { // [futures.unique.future]
+ std::future<int> ftr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ftr.share();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ftr.get();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ftr.valid();
+
+ std::future<int&> refFtr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refFtr.share();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refFtr.get();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refFtr.valid();
+
+ std::future<void> voidFtr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ voidFtr.valid();
+ }
+
+ { // [futures.promise]
+ std::promise<int> pr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ pr.get_future();
+
+ std::promise<int&> refPr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refPr.get_future();
+
+ std::promise<void> voidPr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ voidPr.get_future();
+ }
+
+ { // [futures.shared.future]
+ std::shared_future<int> ftr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ftr.get();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ftr.valid();
+
+ std::shared_future<int&> refFtr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refFtr.get();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ refFtr.valid();
+
+ std::shared_future<void> voidFtr;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ voidFtr.valid();
+ }
+
#if TEST_STD_VER >= 11
- { // [futures.async]
- // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::async([]() {});
- // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::async(std::launch::any, []() {});
- }
+ { // [futures.async]
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::async([]() {});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::async(std::launch::any, []() {});
+ }
#endif
+ { // [futures.task]
+ std::packaged_task<int()> task;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ task.valid();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ task.get_future();
+
+ std::packaged_task<void()> voidTask;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ voidTask.valid();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ voidTask.get_future();
+ }
+ }
+
// std::scoped_lock
{
#if TEST_STD_VER >= 17
More information about the libcxx-commits
mailing list