[libcxx-commits] [libcxx] [libc++][future] Applied `[[nodiscard]]` (PR #174924)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 8 01:57:41 PST 2026
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/174924
>From 1189c2c27512c6a4a4edf598c5d940a9b8028278 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 | 112 +++++++++++++++++-
.../futures.promise/set_exception.pass.cpp | 4 +-
.../set_exception_at_thread_exit.pass.cpp | 4 +-
.../futures.promise/set_value_void.pass.cpp | 2 +-
.../futures.shared_future/get.pass.cpp | 4 +-
.../make_ready_at_thread_exit.pass.cpp | 4 +-
.../futures.task.members/operator.pass.cpp | 4 +-
.../futures.unique_future/get.pass.cpp | 4 +-
9 files changed, 142 insertions(+), 42 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..b56f49fbada00 100644
--- a/libcxx/test/libcxx/thread/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -23,15 +23,115 @@
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);
+
+#if TEST_HAS_NO_EXCEPTIONS
+ try {
+ } catch (std::future_error& ex) {
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ex.code();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ex.what();
+ }
+#endif
+ }
+
+ { // [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
diff --git a/libcxx/test/std/thread/futures/futures.promise/set_exception.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/set_exception.pass.cpp
index bc6bc26dbbb01..b226b1b6f4511 100644
--- a/libcxx/test/std/thread/futures/futures.promise/set_exception.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/set_exception.pass.cpp
@@ -30,8 +30,8 @@ int main(int, char**)
p.set_exception(std::make_exception_ptr(3));
try
{
- f.get();
- assert(false);
+ (void)f.get();
+ assert(false);
}
catch (int i)
{
diff --git a/libcxx/test/std/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
index a1a351ec02b04..eb81c3c66fe54 100644
--- a/libcxx/test/std/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
@@ -36,8 +36,8 @@ int main(int, char**)
support::make_test_thread(func, std::move(p)).detach();
try
{
- f.get();
- assert(false);
+ (void)f.get();
+ assert(false);
}
catch (int i)
{
diff --git a/libcxx/test/std/thread/futures/futures.promise/set_value_void.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/set_value_void.pass.cpp
index 9f12e498b84ec..2aff04ba207f5 100644
--- a/libcxx/test/std/thread/futures/futures.promise/set_value_void.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/set_value_void.pass.cpp
@@ -28,7 +28,7 @@ int main(int, char**)
std::promise<T> p;
std::future<T> f = p.get_future();
p.set_value();
- f.get();
+ (void)f.get();
try
{
p.set_value();
diff --git a/libcxx/test/std/thread/futures/futures.shared_future/get.pass.cpp b/libcxx/test/std/thread/futures/futures.shared_future/get.pass.cpp
index 62da170a90c42..062d5b655dddb 100644
--- a/libcxx/test/std/thread/futures/futures.shared_future/get.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.shared_future/get.pass.cpp
@@ -129,7 +129,7 @@ int main(int, char**)
std::shared_future<T> f = p.get_future();
support::make_test_thread(func5, std::move(p)).detach();
assert(f.valid());
- f.get();
+ (void)f.get();
assert(f.valid());
}
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -140,7 +140,7 @@ int main(int, char**)
try
{
assert(f.valid());
- f.get();
+ (void)f.get();
assert(false);
}
catch (char i)
diff --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/make_ready_at_thread_exit.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/make_ready_at_thread_exit.pass.cpp
index 71c63b54358d7..3d40b418e2081 100644
--- a/libcxx/test/std/thread/futures/futures.task/futures.task.members/make_ready_at_thread_exit.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/make_ready_at_thread_exit.pass.cpp
@@ -95,8 +95,8 @@ int main(int, char**)
support::make_test_thread(func1, std::move(p)).detach();
try
{
- f.get();
- assert(false);
+ (void)f.get();
+ assert(false);
}
catch (const A& e)
{
diff --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/operator.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/operator.pass.cpp
index e6c833ef23a83..d8dc2659ba042 100644
--- a/libcxx/test/std/thread/futures/futures.task/futures.task.members/operator.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/operator.pass.cpp
@@ -95,8 +95,8 @@ int main(int, char**)
support::make_test_thread(func1, std::move(p)).detach();
try
{
- f.get();
- assert(false);
+ (void)f.get();
+ assert(false);
}
catch (const A& e)
{
diff --git a/libcxx/test/std/thread/futures/futures.unique_future/get.pass.cpp b/libcxx/test/std/thread/futures/futures.unique_future/get.pass.cpp
index 9c5b3340e997f..65f3d2199ccdd 100644
--- a/libcxx/test/std/thread/futures/futures.unique_future/get.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.unique_future/get.pass.cpp
@@ -129,7 +129,7 @@ int main(int, char**)
std::future<T> f = p.get_future();
support::make_test_thread(func5, std::move(p)).detach();
assert(f.valid());
- f.get();
+ (void)f.get();
assert(!f.valid());
}
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -140,7 +140,7 @@ int main(int, char**)
try
{
assert(f.valid());
- f.get();
+ (void)f.get();
assert(false);
}
catch (char i)
More information about the libcxx-commits
mailing list