[libcxx-commits] [libcxx] [libc++][unordered_multiset] Applied `[[nodiscard]]` (PR #171664)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Dec 14 08:49:40 PST 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/171664
>From e208f9812bc59bac2238c34a3850387d2e91cc4d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 10 Dec 2025 20:04:02 +0200
Subject: [PATCH 1/2] [libc++][unordered_multiset] Applied `[[nodiscard]]`
`[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue.
- https://libcxx.llvm.org/CodingGuidelines.htm
- https://wg21.link/unord.multiset
---
libcxx/include/unordered_set | 84 ++++++++------
.../unordered_multiset.nodiscard.verify.cpp | 105 ++++++++++++++++++
2 files changed, 152 insertions(+), 37 deletions(-)
create mode 100644 libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 9873f1ec70664..137b45ab9b251 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -1322,20 +1322,20 @@ public:
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(initializer_list<value_type> __il);
# endif // _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
return allocator_type(__table_.__node_alloc());
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; }
- _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); }
- _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); }
- _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); }
- _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); }
# ifndef _LIBCPP_CXX03_LANG
template <class... _Args>
@@ -1383,10 +1383,10 @@ public:
"node_type with incompatible allocator passed to unordered_multiset::insert()");
return __table_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh));
}
- _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __position) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __position) {
return __table_.template __node_handle_extract<node_type>(__position);
}
- _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
return __table_.template __node_handle_extract<node_type>(__key);
}
@@ -1427,71 +1427,81 @@ public:
__table_.swap(__u.__table_);
}
- _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); }
- _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); }
- _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
- _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
# endif // _LIBCPP_STD_VER >= 20
- _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_multi(__k); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const {
+ return __table_.__count_multi(__k);
+ }
# if _LIBCPP_STD_VER >= 20
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_multi(__k);
}
# endif // _LIBCPP_STD_VER >= 20
# if _LIBCPP_STD_VER >= 20
- _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
# endif // _LIBCPP_STD_VER >= 20
- _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) {
return __table_.__equal_range_multi(__k);
}
- _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const {
return __table_.__equal_range_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_multi(__k);
}
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
- _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_multi(__k);
}
# endif // _LIBCPP_STD_VER >= 20
- _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); }
- _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT {
+ return __table_.max_bucket_count();
+ }
- _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); }
- _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const {
+ return __table_.bucket_size(__n);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); }
- _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); }
- _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); }
- _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); }
- _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); }
- _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); }
- _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const {
+ return __table_.cbegin(__n);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const {
+ return __table_.cbegin(__n);
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); }
- _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); }
- _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); }
_LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); }
_LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_multi(__n); }
_LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_multi(__n); }
diff --git a/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..da1c1f99da4bf
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++11
+
+// Check that functions are marked [[nodiscard]]
+
+#include <unordered_set>
+#include <utility>
+
+#include "test_macros.h"
+
+struct TransparentKey {};
+
+struct StoredKey {
+ friend bool operator==(StoredKey const&, StoredKey const&) { return true; }
+ friend bool operator==(StoredKey const&, TransparentKey const&) { return true; }
+};
+
+struct TransparentKeyHash {
+ using is_transparent = void;
+
+ constexpr std::size_t operator()(TransparentKey const&) const { return 0; }
+ constexpr std::size_t operator()(StoredKey const&) const { return 0; }
+};
+
+void test() {
+ std::unordered_multiset<int> us;
+ const std::unordered_multiset<int> cus;
+
+ us.get_allocator(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ us.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.max_size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ us.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.cbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.cend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ int key = 0;
+
+#if TEST_STD_VER >= 17
+ us.extract(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.extract(us.begin()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+ us.hash_function(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.key_eq(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ us.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 20
+ std::unordered_multiset<StoredKey, TransparentKeyHash, std::equal_to<>> tus;
+ const std::unordered_multiset<StoredKey, TransparentKeyHash, std::equal_to<>> ctus;
+
+ TransparentKey tkey;
+
+ tus.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ctus.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+ us.count(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 20
+ tus.count(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+#if TEST_STD_VER >= 20
+ us.contains(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tus.contains(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+ us.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 20
+ tus.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ ctus.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+ us.bucket_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.max_bucket_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ int size = 0;
+
+ us.bucket_size(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.bucket(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ us.begin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.end(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.begin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.end(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.cbegin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cus.cend(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ us.load_factor(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ us.max_load_factor(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
>From 52dec4a14a4ec0de34753202dee2e654e9e43a5f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 14 Dec 2025 18:49:24 +0200
Subject: [PATCH 2/2] Enabled C++03
---
.../diagnostics/unordered_multiset.nodiscard.verify.cpp | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
index da1c1f99da4bf..ff62874caf01b 100644
--- a/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/unordered_multiset.nodiscard.verify.cpp
@@ -6,8 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// REQUIRES: std-at-least-c++11
-
// Check that functions are marked [[nodiscard]]
#include <unordered_set>
@@ -25,8 +23,8 @@ struct StoredKey {
struct TransparentKeyHash {
using is_transparent = void;
- constexpr std::size_t operator()(TransparentKey const&) const { return 0; }
- constexpr std::size_t operator()(StoredKey const&) const { return 0; }
+ std::size_t operator()(TransparentKey const&) const { return 0; }
+ std::size_t operator()(StoredKey const&) const { return 0; }
};
void test() {
More information about the libcxx-commits
mailing list