[libcxx-commits] [libcxx] [libc++][bitset] Applied `[[nodiscard]]` (PR #170623)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 5 23:53:51 PST 2025


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

>From c47f4d55fa9065004f3ddd763bb3cdf54d42defa Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 4 Dec 2025 08:26:37 +0200
Subject: [PATCH 1/2] [libc++][bitset] 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/bitset
---
 libcxx/include/__bit_reference                |  2 +-
 libcxx/include/bitset                         | 45 +++++++++------
 .../template.bitset/nodiscard.verify.cpp      | 55 +++++++++++++++++++
 3 files changed, 83 insertions(+), 19 deletions(-)
 create mode 100644 libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp

diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference
index 20e5bc7d5695b..00bbc4100ddb9 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -139,7 +139,7 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator bool() const _NOEXCEPT {
     return static_cast<bool>(*__seg_ & __mask_);
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT {
     return !static_cast<bool>(*this);
   }
 
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 3453c2fcde71e..7b5ec901414d2 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -675,53 +675,62 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& set(size_t __pos, bool __val = true);
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& reset() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& reset(size_t __pos);
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator~() const _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator~() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& flip() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& flip(size_t __pos);
 
   // element access:
 #  ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
     return __base::__make_ref(__p);
   }
 #  else
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference operator[](size_t __p) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference operator[](size_t __p) const {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
     return __base::__make_ref(__p);
   }
 #  endif
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
     return __base::__make_ref(__p);
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return __base::to_ulong(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
+    return __base::to_ulong();
+  }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
     return __base::to_ullong();
   }
   template <class _CharT, class _Traits, class _Allocator>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
   to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const;
   template <class _CharT, class _Traits>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, allocator<_CharT> >
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, allocator<_CharT> >
   to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const;
   template <class _CharT>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, char_traits<_CharT>, allocator<_CharT> >
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, char_traits<_CharT>, allocator<_CharT> >
   to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<char, char_traits<char>, allocator<char> >
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<char, char_traits<char>, allocator<char> >
   to_string(char __zero = '0', char __one = '1') const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t count() const _NOEXCEPT;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_t size() const _NOEXCEPT { return _Size; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t count() const _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_t size() const _NOEXCEPT { return _Size; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const bitset& __rhs) const _NOEXCEPT;
 #  if _LIBCPP_STD_VER <= 17
   _LIBCPP_HIDE_FROM_ABI bool operator!=(const bitset& __rhs) const _NOEXCEPT;
 #  endif
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool test(size_t __pos) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return __base::all(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT { return __base::any(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool none() const _NOEXCEPT { return !any(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator<<(size_t __pos) const _NOEXCEPT;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator>>(size_t __pos) const _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool test(size_t __pos) const;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT {
+    return __base::all();
+  }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT {
+    return __base::any();
+  }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool none() const _NOEXCEPT { return !any(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator<<(size_t __pos) const _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator>>(size_t __pos) const _NOEXCEPT;
 
 private:
   template <class _CharT, class _Traits>
diff --git a/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..eff8cade03bcf
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/template.bitset/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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// <bitset>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <bitset>
+
+#include "test_macros.h"
+#include "test_allocator.h"
+
+void test() {
+  std::bitset<10> bs;
+  const std::bitset<10> cbs;
+
+  // std::bitset<>::reference operator~() const noexcept;
+  ~bs[0]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  ~bs; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  bs[0];          // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  cbs[0];         // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_ulong();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_ullong(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  struct CharTraits : public std::char_traits<char> {};
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_string<char, CharTraits, test_allocator<char>>();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_string<char, CharTraits>();
+#if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_string<wchar_t>();
+#endif
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.to_string();
+
+  bs.count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.size();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.test(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.all();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.any();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs.none();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs << 1;    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs >> 1;    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}

>From 2980120430989036197c1d3b31a8407326635b4b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 6 Dec 2025 09:53:38 +0200
Subject: [PATCH 2/2] Fix

---
 libcxx/include/bitset                            | 12 +++++++-----
 .../template.bitset/nodiscard.verify.cpp         | 16 +++++++++++-----
 2 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 7b5ec901414d2..f5e65e1f5c41a 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -791,7 +791,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>
 }
 
 template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::set() _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::set() _NOEXCEPT {
   std::fill_n(__base::__make_iter(0), _Size, true);
   return *this;
 }
@@ -928,7 +928,7 @@ bitset<_Size>::operator>>(size_t __pos) const _NOEXCEPT {
 }
 
 template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
 operator&(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
   bitset<_Size> __r = __x;
   __r &= __y;
@@ -936,7 +936,7 @@ operator&(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
 }
 
 template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
 operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
   bitset<_Size> __r = __x;
   __r |= __y;
@@ -944,7 +944,7 @@ operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
 }
 
 template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
 operator^(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
   bitset<_Size> __r = __x;
   __r ^= __y;
@@ -953,7 +953,9 @@ operator^(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT {
 
 template <size_t _Size>
 struct hash<bitset<_Size> > : public __unary_function<bitset<_Size>, size_t> {
-  _LIBCPP_HIDE_FROM_ABI size_t operator()(const bitset<_Size>& __bs) const _NOEXCEPT { return __bs.__hash_code(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const bitset<_Size>& __bs) const _NOEXCEPT {
+    return __bs.__hash_code();
+  }
 };
 
 template <class _CharT, class _Traits, size_t _Size>
diff --git a/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp
index eff8cade03bcf..b13fafe2edfc6 100644
--- a/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/template.bitset/nodiscard.verify.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
-
 // <bitset>
 
 // Check that functions are marked [[nodiscard]]
@@ -18,8 +16,8 @@
 #include "test_allocator.h"
 
 void test() {
-  std::bitset<10> bs;
-  const std::bitset<10> cbs;
+  std::bitset<11> bs;
+  const std::bitset<11> cbs;
 
   // std::bitset<>::reference operator~() const noexcept;
   ~bs[0]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -34,7 +32,7 @@ void test() {
   struct CharTraits : public std::char_traits<char> {};
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  bs.to_string<char, CharTraits, test_allocator<char>>();
+  bs.to_string<char, CharTraits, test_allocator<char> >();
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   bs.to_string<char, CharTraits>();
 #if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
@@ -52,4 +50,12 @@ void test() {
   bs.none();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   bs << 1;    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   bs >> 1;    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  bs & bs; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs | bs; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  bs ^ bs; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  std::hash<std::bitset<11> > hash;
+
+  hash(bs); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 }



More information about the libcxx-commits mailing list