[libcxx-commits] [libcxx] [libc++] Applied `[[nodiscard]]` to concurrency (partially) (PR #169463)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Wed Nov 26 06:35:51 PST 2025


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/169463

>From 059c7f0c33d30e03d815a6ab5947396bb585e506 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 23 Nov 2025 14:21:21 +0200
Subject: [PATCH 1/4] [libc++] `[[nodiscard]]` to concurrency

`[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue.

- https://libcxx.llvm.org/CodingGuidelines.html#apply-nodiscard-where-relevant

The following utilities have been anotated in this patch:

- [x] `<barrier>`
- [x] `<condition_variable>`
- [x] `<latch>`
- [x] `<mutex>`
- [x] `<semaphore>`
- [x] `<thread>`
---
 .../__condition_variable/condition_variable.h |  2 +-
 libcxx/include/__mutex/mutex.h                |  2 +-
 libcxx/include/__thread/thread.h              |  8 +-
 libcxx/include/barrier                        |  4 +-
 libcxx/include/latch                          |  4 +-
 libcxx/include/mutex                          |  2 +-
 libcxx/include/semaphore                      |  2 +-
 .../test/libcxx/thread/nodiscard.verify.cpp   | 94 +++++++++++++++++++
 .../thread.jthread/nodiscard.verify.cpp       | 29 ------
 9 files changed, 108 insertions(+), 39 deletions(-)
 create mode 100644 libcxx/test/libcxx/thread/nodiscard.verify.cpp
 delete mode 100644 libcxx/test/std/thread/thread.jthread/nodiscard.verify.cpp

diff --git a/libcxx/include/__condition_variable/condition_variable.h b/libcxx/include/__condition_variable/condition_variable.h
index 1e8edd5dcb009..b7151930e9226 100644
--- a/libcxx/include/__condition_variable/condition_variable.h
+++ b/libcxx/include/__condition_variable/condition_variable.h
@@ -170,7 +170,7 @@ class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
   wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
 
   typedef __libcpp_condvar_t* native_handle_type;
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
 
 private:
   void
diff --git a/libcxx/include/__mutex/mutex.h b/libcxx/include/__mutex/mutex.h
index 68c8842b35eda..1fbe09f266832 100644
--- a/libcxx/include/__mutex/mutex.h
+++ b/libcxx/include/__mutex/mutex.h
@@ -41,7 +41,7 @@ class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("mutex") mutex {
   _LIBCPP_RELEASE_CAPABILITY void unlock() _NOEXCEPT;
 
   typedef __libcpp_mutex_t* native_handle_type;
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
 };
 
 static_assert(is_nothrow_default_constructible<mutex>::value, "the default constructor for std::mutex must be nothrow");
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index a3b672bc0f0e7..561f092ddb7c0 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -242,13 +242,13 @@ class _LIBCPP_EXPORTED_FROM_ABI thread {
 
   _LIBCPP_HIDE_FROM_ABI void swap(thread& __t) _NOEXCEPT { std::swap(__t_, __t.__t_); }
 
-  _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); }
   void join();
   void detach();
-  _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); }
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; }
 
-  static unsigned hardware_concurrency() _NOEXCEPT;
+  [[__nodiscard__]] static unsigned hardware_concurrency() _NOEXCEPT;
 };
 
 inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); }
diff --git a/libcxx/include/barrier b/libcxx/include/barrier
index 41fbfb3e8fb7b..5f9b471f01741 100644
--- a/libcxx/include/barrier
+++ b/libcxx/include/barrier
@@ -158,7 +158,9 @@ class barrier {
 public:
   using arrival_token = typename __barrier_base<_CompletionF>::arrival_token;
 
-  static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return __barrier_base<_CompletionF>::max(); }
+  [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept {
+    return __barrier_base<_CompletionF>::max();
+  }
 
   _LIBCPP_HIDE_FROM_ABI explicit barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
       : __b_(__count, std::move(__completion)) {
diff --git a/libcxx/include/latch b/libcxx/include/latch
index c3b8f62e9b50e..de5f50c2229cc 100644
--- a/libcxx/include/latch
+++ b/libcxx/include/latch
@@ -70,7 +70,9 @@ class latch {
   atomic<ptrdiff_t> __a_;
 
 public:
-  static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
+  [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept {
+    return numeric_limits<ptrdiff_t>::max();
+  }
 
   inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {
     _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 0b81f1bb1c8a6..1c31bafc0da6b 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -234,7 +234,7 @@ public:
 
   typedef __libcpp_recursive_mutex_t* native_handle_type;
 
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
 };
 
 class _LIBCPP_EXPORTED_FROM_ABI timed_mutex {
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 99c4ad24b35ec..d490d4f4abfb3 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -133,7 +133,7 @@ class counting_semaphore {
 public:
   static_assert(__least_max_value >= 0, "The least maximum value must be a positive number");
 
-  static constexpr ptrdiff_t max() noexcept { return __least_max_value; }
+  [[nodiscard]] static constexpr ptrdiff_t max() noexcept { return __least_max_value; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr explicit counting_semaphore(ptrdiff_t __count) : __semaphore_(__count) {
     _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
diff --git a/libcxx/test/libcxx/thread/nodiscard.verify.cpp b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..179383f3b480e
--- /dev/null
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+// UNSUPPORTED: no-threads
+
+// Check that functions are marked [[nodiscard]]
+
+#include <barrier>
+#include <latch>
+#include <mutex>
+#include <semaphore>
+#include <thread>
+
+#include "test_macros.h"
+
+void test() {
+  // Threads
+  {
+    std::thread th;
+
+    th.joinable();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    th.get_id();        // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    th.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    th.hardware_concurrency(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#if TEST_STD_VER >= 20
+  {
+    std::jthread jt;
+
+    jt.joinable();        // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    jt.get_id();          // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    jt.native_handle();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    jt.get_stop_source(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    jt.get_stop_token();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    jt.hardware_concurrency(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+
+  // Mutual exclusion
+
+  { // <mutex>
+    std::mutex m;
+
+    m.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    std::recursive_mutex m;
+
+    m.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+
+  // Condition variables
+
+  { // <condition_variable>
+    std::condition_variable cv;
+
+    cv.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+
+#if TEST_STD_VER >= 20
+
+  // Semaphores
+
+  { // <semaphor>
+    std::counting_semaphore<> cs{0};
+
+    cs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::binary_semaphore bs{0};
+
+    bs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+
+  // Latches and barriers
+
+  { // <barrier>
+    std::barrier<> b{94};
+
+    b.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  { // <latch>
+    std::latch l{94};
+
+    l.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+
+#endif
+}
diff --git a/libcxx/test/std/thread/thread.jthread/nodiscard.verify.cpp b/libcxx/test/std/thread/thread.jthread/nodiscard.verify.cpp
deleted file mode 100644
index 2ef5cf874da90..0000000000000
--- a/libcxx/test/std/thread/thread.jthread/nodiscard.verify.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// [[nodiscard]] bool joinable() const noexcept;
-// [[nodiscard]] id get_id() const noexcept;
-// [[nodiscard]] native_handle_type native_handle();
-// [[nodiscard]] stop_source get_stop_source() noexcept;
-// [[nodiscard]] stop_token get_stop_token() const noexcept;
-// [[nodiscard]] static unsigned int hardware_concurrency() noexcept;
-
-#include <thread>
-
-void test() {
-  std::jthread jt;
-  jt.joinable();             // expected-warning {{ignoring return value of function}}
-  jt.get_id();               // expected-warning {{ignoring return value of function}}
-  jt.native_handle();        // expected-warning {{ignoring return value of function}}
-  jt.get_stop_source();      // expected-warning {{ignoring return value of function}}
-  jt.get_stop_token();       // expected-warning {{ignoring return value of function}}
-  jt.hardware_concurrency(); // expected-warning {{ignoring return value of function}}
-}

>From 4ad45f4b60156b960bd039f536e6aa7f97c34c32 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 26 Nov 2025 09:55:46 +0200
Subject: [PATCH 2/4] Addressed comments

---
 libcxx/include/__mutex/mutex.h                |  2 +-
 libcxx/include/latch                          |  2 +-
 libcxx/include/mutex                          | 18 +++---
 libcxx/include/semaphore                      |  6 +-
 .../test/libcxx/thread/nodiscard.verify.cpp   | 56 ++++++++++++++++++-
 5 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__mutex/mutex.h b/libcxx/include/__mutex/mutex.h
index 1fbe09f266832..e9cedf8db1cca 100644
--- a/libcxx/include/__mutex/mutex.h
+++ b/libcxx/include/__mutex/mutex.h
@@ -37,7 +37,7 @@ class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("mutex") mutex {
 #  endif
 
   _LIBCPP_ACQUIRE_CAPABILITY() void lock();
-  _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock() _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock() _NOEXCEPT;
   _LIBCPP_RELEASE_CAPABILITY void unlock() _NOEXCEPT;
 
   typedef __libcpp_mutex_t* native_handle_type;
diff --git a/libcxx/include/latch b/libcxx/include/latch
index de5f50c2229cc..33268d9655f25 100644
--- a/libcxx/include/latch
+++ b/libcxx/include/latch
@@ -99,7 +99,7 @@ public:
     if (__old == __update)
       __a_.notify_all();
   }
-  inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
+  [[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
     auto __value = __a_.load(memory_order_acquire);
     return try_wait_impl(__value);
   }
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 1c31bafc0da6b..3fc93fa3a5464 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -229,7 +229,7 @@ public:
   recursive_mutex& operator=(const recursive_mutex&) = delete;
 
   void lock();
-  bool try_lock() _NOEXCEPT;
+  [[__nodiscard__]] bool try_lock() _NOEXCEPT;
   void unlock() _NOEXCEPT;
 
   typedef __libcpp_recursive_mutex_t* native_handle_type;
@@ -251,14 +251,14 @@ public:
 
 public:
   void lock();
-  bool try_lock() _NOEXCEPT;
+  [[__nodiscard__]] bool try_lock() _NOEXCEPT;
   template <class _Rep, class _Period>
-  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
     return try_lock_until(chrono::steady_clock::now() + __d);
   }
 
   template <class _Clock, class _Duration>
-  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
     using namespace chrono;
     unique_lock<mutex> __lk(__m_);
     bool __no_timeout = _Clock::now() < __t;
@@ -288,14 +288,14 @@ public:
   recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
 
   void lock();
-  bool try_lock() _NOEXCEPT;
+  [[__nodiscard__]] bool try_lock() _NOEXCEPT;
   template <class _Rep, class _Period>
-  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
     return try_lock_until(chrono::steady_clock::now() + __d);
   }
 
   template <class _Clock, class _Duration>
-  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
     using namespace chrono;
     __thread_id __id = this_thread::get_id();
     unique_lock<mutex> __lk(__m_);
@@ -320,7 +320,7 @@ public:
 };
 
 template <class _L0, class _L1>
-_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
+[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
   unique_lock<_L0> __u0(__l0, try_to_lock_t());
   if (__u0.owns_lock()) {
     if (__l1.try_lock()) {
@@ -335,7 +335,7 @@ _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0,
 #    ifndef _LIBCPP_CXX03_LANG
 
 template <class _L0, class _L1, class _L2, class... _L3>
-_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
+[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
   int __r = 0;
   unique_lock<_L0> __u0(__l0, try_to_lock);
   if (__u0.owns_lock()) {
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index d490d4f4abfb3..1f19d50e32af7 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -156,12 +156,12 @@ public:
   }
   _LIBCPP_HIDE_FROM_ABI void acquire() { __semaphore_.acquire(); }
   template <class _Rep, class _Period>
-  _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
     return __semaphore_.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time));
   }
-  _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); }
   template <class _Clock, class _Duration>
-  _LIBCPP_HIDE_FROM_ABI bool try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) {
     auto const __current = _Clock::now();
     if (__current >= __abs_time)
       return try_acquire();
diff --git a/libcxx/test/libcxx/thread/nodiscard.verify.cpp b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
index 179383f3b480e..38d9528485da2 100644
--- a/libcxx/test/libcxx/thread/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -11,6 +11,7 @@
 
 // Check that functions are marked [[nodiscard]]
 
+#include <chrono>
 #include <barrier>
 #include <latch>
 #include <mutex>
@@ -19,6 +20,10 @@
 
 #include "test_macros.h"
 
+using namespace std::chrono_literals;
+
+const auto timePoint = std::chrono::steady_clock::now();
+
 void test() {
   // Threads
   {
@@ -47,13 +52,45 @@ void test() {
   { // <mutex>
     std::mutex m;
 
+    m.try_lock();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   }
   {
     std::recursive_mutex m;
 
+    m.try_lock();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   }
+  {
+    std::timed_mutex m;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock_for(82ms);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock_until(timePoint);
+  }
+  {
+    std::recursive_timed_mutex m;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock_for(82ms);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    m.try_lock_until(timePoint);
+  }
+  {
+    std::mutex m1;
+    std::mutex m2;
+    std::mutex m3;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::try_lock(m1, m2);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::try_lock(m1, m2, m3);
+  }
 
   // Condition variables
 
@@ -67,14 +104,28 @@ void test() {
 
   // Semaphores
 
-  { // <semaphor>
+  { // <semaphore>
     std::counting_semaphore<> cs{0};
 
     cs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    cs.try_acquire_for(92ms);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    cs.try_acquire();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    cs.try_acquire_until(timePoint);
+
     std::binary_semaphore bs{0};
 
     bs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    bs.try_acquire_for(82ms);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    bs.try_acquire();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    bs.try_acquire_until(timePoint);
   }
 
   // Latches and barriers
@@ -87,7 +138,8 @@ void test() {
   { // <latch>
     std::latch l{94};
 
-    l.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    l.max();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    l.try_wait(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   }
 
 #endif

>From 601f9e3ca269e8f9365cd3a468e4bbda6ba446c4 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 26 Nov 2025 16:26:39 +0200
Subject: [PATCH 3/4] Formatting

---
 libcxx/include/mutex | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 3fc93fa3a5464..bec0185ede21a 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -335,7 +335,8 @@ template <class _L0, class _L1>
 #    ifndef _LIBCPP_CXX03_LANG
 
 template <class _L0, class _L1, class _L2, class... _L3>
-[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
+[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
+    _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
   int __r = 0;
   unique_lock<_L0> __u0(__l0, try_to_lock);
   if (__u0.owns_lock()) {

>From 792178bedad5d0bfe25f3b0de3b5d94c5f55f871 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 26 Nov 2025 16:35:33 +0200
Subject: [PATCH 4/4] Fixed build

---
 libcxx/test/libcxx/thread/nodiscard.verify.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/libcxx/thread/nodiscard.verify.cpp b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
index 38d9528485da2..19e43f88db700 100644
--- a/libcxx/test/libcxx/thread/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/thread/nodiscard.verify.cpp
@@ -20,8 +20,6 @@
 
 #include "test_macros.h"
 
-using namespace std::chrono_literals;
-
 const auto timePoint = std::chrono::steady_clock::now();
 
 void test() {
@@ -67,7 +65,7 @@ void test() {
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.try_lock();
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-    m.try_lock_for(82ms);
+    m.try_lock_for(std::chrono::nanoseconds{82});
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.try_lock_until(timePoint);
   }
@@ -77,7 +75,7 @@ void test() {
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.try_lock();
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-    m.try_lock_for(82ms);
+    m.try_lock_for(std::chrono::nanoseconds{82});
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     m.try_lock_until(timePoint);
   }
@@ -110,7 +108,7 @@ void test() {
     cs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-    cs.try_acquire_for(92ms);
+    cs.try_acquire_for(std::chrono::nanoseconds{82});
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     cs.try_acquire();
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -121,7 +119,7 @@ void test() {
     bs.max(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-    bs.try_acquire_for(82ms);
+    bs.try_acquire_for(std::chrono::nanoseconds{82});
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     bs.try_acquire();
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}



More information about the libcxx-commits mailing list