Skip to content

Commit 7eaafda

Browse files
committed
[libc++][unordered_set] 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/unord.set
1 parent f5742c4 commit 7eaafda

File tree

3 files changed

+154
-47
lines changed

3 files changed

+154
-47
lines changed

libcxx/include/unordered_set

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -736,20 +736,20 @@ public:
736736
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(initializer_list<value_type> __il);
737737
# endif // _LIBCPP_CXX03_LANG
738738

739-
_LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
739+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
740740
return allocator_type(__table_.__node_alloc());
741741
}
742742

743743
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; }
744-
_LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); }
745-
_LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); }
744+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); }
745+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); }
746746

747-
_LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); }
748-
_LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); }
749-
_LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); }
750-
_LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); }
751-
_LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); }
752-
_LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); }
747+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); }
748+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); }
749+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); }
750+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); }
751+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); }
752+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); }
753753

754754
# ifndef _LIBCPP_CXX03_LANG
755755
template <class... _Args>
@@ -801,10 +801,10 @@ public:
801801
"node_type with incompatible allocator passed to unordered_set::insert()");
802802
return __table_.template __node_handle_insert_unique<node_type>(__h, std::move(__nh));
803803
}
804-
_LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
804+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
805805
return __table_.template __node_handle_extract<node_type>(__key);
806806
}
807-
_LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
807+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
808808
return __table_.template __node_handle_extract<node_type>(__it);
809809
}
810810

@@ -838,71 +838,81 @@ public:
838838
__table_.swap(__u.__table_);
839839
}
840840

841-
_LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); }
842-
_LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); }
841+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); }
842+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); }
843843

844-
_LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
845-
_LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
844+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
845+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
846846
# if _LIBCPP_STD_VER >= 20
847847
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
848-
_LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
848+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
849849
return __table_.find(__k);
850850
}
851851
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
852-
_LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
852+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
853853
return __table_.find(__k);
854854
}
855855
# endif // _LIBCPP_STD_VER >= 20
856856

857-
_LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_unique(__k); }
857+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const {
858+
return __table_.__count_unique(__k);
859+
}
858860
# if _LIBCPP_STD_VER >= 20
859861
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
860-
_LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
862+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
861863
return __table_.__count_unique(__k);
862864
}
863865
# endif // _LIBCPP_STD_VER >= 20
864866

865867
# if _LIBCPP_STD_VER >= 20
866-
_LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
868+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
867869

868870
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
869-
_LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
871+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
870872
return find(__k) != end();
871873
}
872874
# endif // _LIBCPP_STD_VER >= 20
873875

874-
_LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) {
876+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) {
875877
return __table_.__equal_range_unique(__k);
876878
}
877-
_LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const {
879+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const {
878880
return __table_.__equal_range_unique(__k);
879881
}
880882
# if _LIBCPP_STD_VER >= 20
881883
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
882-
_LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
884+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
883885
return __table_.__equal_range_unique(__k);
884886
}
885887
template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
886-
_LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
888+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
887889
return __table_.__equal_range_unique(__k);
888890
}
889891
# endif // _LIBCPP_STD_VER >= 20
890892

891-
_LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); }
892-
_LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); }
893+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); }
894+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT {
895+
return __table_.max_bucket_count();
896+
}
893897

894-
_LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); }
895-
_LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); }
898+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const {
899+
return __table_.bucket_size(__n);
900+
}
901+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); }
896902

897-
_LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); }
898-
_LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); }
899-
_LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); }
900-
_LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); }
901-
_LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); }
902-
_LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); }
903+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); }
904+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); }
905+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const {
906+
return __table_.cbegin(__n);
907+
}
908+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); }
909+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const {
910+
return __table_.cbegin(__n);
911+
}
912+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); }
903913

904-
_LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); }
905-
_LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); }
914+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); }
915+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); }
906916
_LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); }
907917
_LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_unique(__n); }
908918
_LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_unique(__n); }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03
10+
11+
// Check that functions are marked [[nodiscard]]
12+
13+
#include <unordered_set>
14+
15+
void test() {
16+
std::unordered_multiset<int> us;
17+
us.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
18+
}

libcxx/test/libcxx/diagnostics/unordered_set.nodiscard.verify.cpp

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,97 @@
88

99
// UNSUPPORTED: c++03
1010

11-
// check that <unordered_set> functions are marked [[nodiscard]]
12-
13-
// clang-format off
11+
// Check that functions are marked [[nodiscard]]
1412

1513
#include <unordered_set>
14+
#include <utility>
1615

17-
void unordered_set_test() {
18-
std::unordered_set<int> unordered_set;
19-
unordered_set.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
20-
}
16+
#include "test_macros.h"
17+
18+
struct TransparentKey {};
19+
20+
struct StoredKey {
21+
friend bool operator==(StoredKey const&, StoredKey const&) { return true; }
22+
friend bool operator==(StoredKey const&, TransparentKey const&) { return true; }
23+
};
24+
25+
struct TransparentKeyHash {
26+
using is_transparent = void;
27+
28+
constexpr std::size_t operator()(TransparentKey const&) const { return 0; }
29+
constexpr std::size_t operator()(StoredKey const&) const { return 0; }
30+
};
31+
32+
void test() {
33+
std::unordered_set<int> us;
34+
const std::unordered_set<int> cus;
35+
36+
us.get_allocator(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
37+
38+
us.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
39+
us.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
40+
us.max_size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
41+
42+
us.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
43+
us.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
44+
cus.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
45+
cus.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
46+
cus.cbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
47+
cus.cend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
48+
49+
int key = 0;
50+
51+
#if TEST_STD_VER >= 17
52+
us.extract(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
53+
us.extract(us.begin()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
54+
#endif
55+
56+
us.hash_function(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
57+
us.key_eq(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
58+
59+
us.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
60+
cus.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
61+
#if TEST_STD_VER >= 20
62+
std::unordered_set<StoredKey, TransparentKeyHash, std::equal_to<>> tus;
63+
const std::unordered_set<StoredKey, TransparentKeyHash, std::equal_to<>> ctus;
64+
TransparentKey tkey;
65+
66+
tus.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
67+
ctus.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
68+
#endif
69+
70+
us.count(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
71+
#if TEST_STD_VER >= 20
72+
tus.count(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
73+
#endif
74+
75+
#if TEST_STD_VER >= 20
76+
us.contains(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
77+
tus.contains(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
78+
#endif
79+
80+
us.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
81+
cus.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
82+
#if TEST_STD_VER >= 20
83+
tus.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
84+
ctus.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
85+
#endif
86+
87+
us.bucket_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
88+
us.max_bucket_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
89+
90+
int size = 0;
91+
92+
us.bucket_size(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
93+
us.bucket(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
94+
95+
us.begin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
96+
us.end(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
97+
cus.begin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
98+
cus.end(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
99+
cus.cbegin(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
100+
cus.cend(size); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
21101

22-
void unordered_multiset_test() {
23-
std::unordered_multiset<int> unordered_multiset;
24-
unordered_multiset.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
102+
us.load_factor(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
103+
us.max_load_factor(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
25104
}

0 commit comments

Comments
 (0)