[libcxx-commits] [libcxx] [libc++][atomic] Applied `[[nodiscard]]` (PR #173962)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 30 03:08:07 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

`[[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/atomics

Towards #<!-- -->172124

N.B. Annotated  conservatively.

---
Full diff: https://github.com/llvm/llvm-project/pull/173962.diff


4 Files Affected:

- (modified) libcxx/include/__atomic/atomic.h (+11-11) 
- (modified) libcxx/include/__atomic/atomic_ref.h (+4-2) 
- (modified) libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp (+18-16) 
- (added) libcxx/test/libcxx/atomics/nodiscard.verify.cpp (+55) 


``````````diff
diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 554c111d695f2..788382c61740c 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -48,10 +48,10 @@ struct __atomic_base // false
   static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value;
 #endif
 
-  _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT {
     return __cxx_atomic_is_lock_free(sizeof(__cxx_atomic_impl<_Tp>));
   }
-  _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT {
     return static_cast<__atomic_base const volatile*>(this)->is_lock_free();
   }
   _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
@@ -62,11 +62,11 @@ struct __atomic_base // false
       _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
     std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
   }
-  _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
       _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
     return std::__cxx_atomic_load(std::addressof(__a_), __m);
   }
-  _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
       _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
     return std::__cxx_atomic_load(std::addressof(__a_), __m);
   }
@@ -435,12 +435,12 @@ struct atomic<_Tp> : __atomic_base<_Tp> {
 // atomic_is_lock_free
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT {
   return __o->is_lock_free();
 }
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT {
   return __o->is_lock_free();
 }
 
@@ -489,25 +489,25 @@ atomic_store_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, me
 // atomic_load
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT {
   return __o->load();
 }
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT {
   return __o->load();
 }
 
 // atomic_load_explicit
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
-    _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp
+atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
   return __o->load(__m);
 }
 
 template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
     _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
   return __o->load(__m);
 }
diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h
index 9a36aaa3b84fe..d5bd2afe33a21 100644
--- a/libcxx/include/__atomic/atomic_ref.h
+++ b/libcxx/include/__atomic/atomic_ref.h
@@ -122,7 +122,9 @@ struct __atomic_ref_base {
   static constexpr bool is_always_lock_free =
       __atomic_always_lock_free(sizeof(_Tp), std::addressof(__get_aligner_instance<required_alignment>::__instance));
 
-  _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept {
+    return __atomic_is_lock_free(sizeof(_Tp), __ptr_);
+  }
 
   _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept
       _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) {
@@ -137,7 +139,7 @@ struct __atomic_ref_base {
     return __desired;
   }
 
-  _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept
       _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__order) {
     _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
         __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire ||
diff --git a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
index 1b0b945f33700..5e88912c3fcd7 100644
--- a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
+++ b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
@@ -12,6 +12,8 @@
 
 // Test that invalid memory order arguments are diagnosed where possible.
 
+// clang-format off
+
 #include <atomic>
 
 void f() {
@@ -21,26 +23,26 @@ void f() {
     int val2 = 2; ((void)val2);
     // load operations
     {
-        x.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
-        x.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
-        vx.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
-        vx.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)x.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)x.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)vx.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)vx.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
         // valid memory orders
-        x.load(std::memory_order_relaxed);
-        x.load(std::memory_order_consume);
-        x.load(std::memory_order_acquire);
-        x.load(std::memory_order_seq_cst);
+        (void)x.load(std::memory_order_relaxed);
+        (void)x.load(std::memory_order_consume);
+        (void)x.load(std::memory_order_acquire);
+        (void)x.load(std::memory_order_seq_cst);
     }
     {
-        std::atomic_load_explicit(&x, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
-        std::atomic_load_explicit(&x, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
-        std::atomic_load_explicit(&vx, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
-        std::atomic_load_explicit(&vx, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)std::atomic_load_explicit(&x, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)std::atomic_load_explicit(&x, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)std::atomic_load_explicit(&vx, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
+        (void)std::atomic_load_explicit(&vx, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
         // valid memory orders
-        std::atomic_load_explicit(&x, std::memory_order_relaxed);
-        std::atomic_load_explicit(&x, std::memory_order_consume);
-        std::atomic_load_explicit(&x, std::memory_order_acquire);
-        std::atomic_load_explicit(&x, std::memory_order_seq_cst);
+        (void)std::atomic_load_explicit(&x, std::memory_order_relaxed);
+        (void)std::atomic_load_explicit(&x, std::memory_order_consume);
+        (void)std::atomic_load_explicit(&x, std::memory_order_acquire);
+        (void)std::atomic_load_explicit(&x, std::memory_order_seq_cst);
     }
     // store operations
     {
diff --git a/libcxx/test/libcxx/atomics/nodiscard.verify.cpp b/libcxx/test/libcxx/atomics/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..3e00a94d219ee
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/nodiscard.verify.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <atomic>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <atomic>
+
+#include "test_macros.h"
+
+void test() {
+#if TEST_STD_VER >= 20
+  {
+    int i = 49;
+    const std::atomic_ref<int> atRef{i};
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    atRef.is_lock_free();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    atRef.load();
+  }
+#endif
+
+  {
+    const volatile std::atomic<int> vat(82);
+    const std::atomic<int> at(94);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    vat.load();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    at.load();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_is_lock_free(&vat);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_is_lock_free(&at);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_load(&vat);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_load(&at);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_load_explicit(&vat, std::memory_order_seq_cst);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::atomic_load_explicit(&at, std::memory_order_seq_cst);
+  }
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/173962


More information about the libcxx-commits mailing list