[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:16:57 PST 2026


https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/174924

- https://libcxx.llvm.org/CodingGuidelines.html
- https://wg21.link/futures

Towards #172124

>From 779fbdd61b4db1df7a118d7e1f2e8fc2942d2c68 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] [[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                         |  42 +++----
 .../test/libcxx/thread/nodiscard.verify.cpp   | 104 +++++++++++++++++-
 2 files changed, 119 insertions(+), 27 deletions(-)

diff --git a/libcxx/include/future b/libcxx/include/future
index 4c0339f64de9c..e16bf88372dad 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();
@@ -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..bb7a1eeebae8b 100644
--- a/libcxx/test/libcxx/thread/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -23,15 +23,107 @@
 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();
+
+      std::future_errc ec;
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::make_error_code(ec);
+
+      std::future_error err(ec);
+
+      // 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::scoped_lock
   {
 #if TEST_STD_VER >= 17



More information about the libcxx-commits mailing list