[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