Skip to content

Commit 8706d82

Browse files
H-G-HristovZingamfrederick-vs-ja
authored
[libc++] Applied [[nodiscard]] to Language Support (partially) (llvm#169611)
https://wg21.link/#support `[[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 was implemented in this patch: - [x] `<compare>` - [x] `<corotine>` - [x] `<initializer_list>` - [x] Integer comparisons --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: A. Jiang <[email protected]>
1 parent bbb8f7a commit 8706d82

File tree

7 files changed

+150
-35
lines changed

7 files changed

+150
-35
lines changed

libcxx/include/__compare/is_eq.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2020

2121
#if _LIBCPP_STD_VER >= 20
2222

23-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_eq(partial_ordering __c) noexcept { return __c == 0; }
24-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_neq(partial_ordering __c) noexcept { return __c != 0; }
25-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lt(partial_ordering __c) noexcept { return __c < 0; }
26-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lteq(partial_ordering __c) noexcept { return __c <= 0; }
27-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gt(partial_ordering __c) noexcept { return __c > 0; }
28-
_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gteq(partial_ordering __c) noexcept { return __c >= 0; }
23+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_eq(partial_ordering __c) noexcept { return __c == 0; }
24+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_neq(partial_ordering __c) noexcept { return __c != 0; }
25+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lt(partial_ordering __c) noexcept { return __c < 0; }
26+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lteq(partial_ordering __c) noexcept { return __c <= 0; }
27+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gt(partial_ordering __c) noexcept { return __c > 0; }
28+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gteq(partial_ordering __c) noexcept { return __c >= 0; }
2929

3030
#endif // _LIBCPP_STD_VER >= 20
3131

libcxx/include/__coroutine/coroutine_handle.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ struct coroutine_handle<void> {
4444
}
4545

4646
// [coroutine.handle.export.import], export/import
47-
_LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
47+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
4848

49-
_LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept {
49+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept {
5050
coroutine_handle __tmp;
5151
__tmp.__handle_ = __addr;
5252
return __tmp;
@@ -55,7 +55,7 @@ struct coroutine_handle<void> {
5555
// [coroutine.handle.observers], observers
5656
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; }
5757

58-
_LIBCPP_HIDE_FROM_ABI bool done() const {
58+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool done() const {
5959
_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines");
6060
return __builtin_coro_done(__handle_);
6161
}
@@ -100,7 +100,7 @@ struct coroutine_handle {
100100

101101
_LIBCPP_HIDE_FROM_ABI constexpr coroutine_handle(nullptr_t) noexcept {}
102102

103-
_LIBCPP_HIDE_FROM_ABI static coroutine_handle from_promise(_Promise& __promise) {
103+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static coroutine_handle from_promise(_Promise& __promise) {
104104
using _RawPromise = __remove_cv_t<_Promise>;
105105
coroutine_handle __tmp;
106106
__tmp.__handle_ =
@@ -114,9 +114,9 @@ struct coroutine_handle {
114114
}
115115

116116
// [coroutine.handle.export.import], export/import
117-
_LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
117+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
118118

119-
_LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept {
119+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept {
120120
coroutine_handle __tmp;
121121
__tmp.__handle_ = __addr;
122122
return __tmp;
@@ -130,7 +130,7 @@ struct coroutine_handle {
130130
// [coroutine.handle.observers], observers
131131
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; }
132132

133-
_LIBCPP_HIDE_FROM_ABI bool done() const {
133+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool done() const {
134134
_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines");
135135
return __builtin_coro_done(__handle_);
136136
}
@@ -150,7 +150,7 @@ struct coroutine_handle {
150150
}
151151

152152
// [coroutine.handle.promise], promise access
153-
_LIBCPP_HIDE_FROM_ABI _Promise& promise() const {
153+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Promise& promise() const {
154154
return *static_cast<_Promise*>(__builtin_coro_promise(this->__handle_, alignof(_Promise), false));
155155
}
156156

@@ -165,7 +165,7 @@ struct coroutine_handle {
165165
// [coroutine.handle.hash]
166166
template <class _Tp>
167167
struct hash<coroutine_handle<_Tp>> {
168-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept {
168+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept {
169169
return hash<void*>()(__v.address());
170170
}
171171
};

libcxx/include/__coroutine/noop_coroutine_handle.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ struct coroutine_handle<noop_coroutine_promise> {
3535

3636
// [coroutine.handle.noop.observers], observers
3737
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return true; }
38-
_LIBCPP_HIDE_FROM_ABI constexpr bool done() const noexcept { return false; }
38+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool done() const noexcept { return false; }
3939

4040
// [coroutine.handle.noop.resumption], resumption
4141
_LIBCPP_HIDE_FROM_ABI constexpr void operator()() const noexcept {}
4242
_LIBCPP_HIDE_FROM_ABI constexpr void resume() const noexcept {}
4343
_LIBCPP_HIDE_FROM_ABI constexpr void destroy() const noexcept {}
4444

4545
// [coroutine.handle.noop.promise], promise access
46-
_LIBCPP_HIDE_FROM_ABI noop_coroutine_promise& promise() const noexcept {
46+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI noop_coroutine_promise& promise() const noexcept {
4747
return *static_cast<noop_coroutine_promise*>(
4848
__builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false));
4949
}
5050

5151
// [coroutine.handle.noop.address], address
52-
_LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
52+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; }
5353

5454
private:
5555
_LIBCPP_HIDE_FROM_ABI friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
@@ -86,7 +86,9 @@ inline noop_coroutine_handle::__noop_coroutine_frame_ty_ noop_coroutine_handle::
8686
# endif
8787

8888
// [coroutine.noop.coroutine]
89-
inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); }
89+
[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept {
90+
return noop_coroutine_handle();
91+
}
9092

9193
_LIBCPP_END_NAMESPACE_STD
9294

libcxx/include/__utility/cmp.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ concept __comparison_can_promote_to =
3131
sizeof(_Tp) < sizeof(_Ip) || (sizeof(_Tp) == sizeof(_Ip) && __signed_integer<_Tp>);
3232

3333
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
34-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
34+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
3535
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
3636
return __t == __u;
3737
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
@@ -45,12 +45,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
4545
}
4646

4747
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
48-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept {
48+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept {
4949
return !std::cmp_equal(__t, __u);
5050
}
5151

5252
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
53-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
53+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
5454
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
5555
return __t < __u;
5656
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
@@ -64,22 +64,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
6464
}
6565

6666
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
67-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater(_Tp __t, _Up __u) noexcept {
67+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater(_Tp __t, _Up __u) noexcept {
6868
return std::cmp_less(__u, __t);
6969
}
7070

7171
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
72-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less_equal(_Tp __t, _Up __u) noexcept {
72+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less_equal(_Tp __t, _Up __u) noexcept {
7373
return !std::cmp_greater(__t, __u);
7474
}
7575

7676
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
77-
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater_equal(_Tp __t, _Up __u) noexcept {
77+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater_equal(_Tp __t, _Up __u) noexcept {
7878
return !std::cmp_less(__t, __u);
7979
}
8080

8181
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
82-
_LIBCPP_HIDE_FROM_ABI constexpr bool in_range(_Up __u) noexcept {
82+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool in_range(_Up __u) noexcept {
8383
return std::cmp_less_equal(__u, numeric_limits<_Tp>::max()) &&
8484
std::cmp_greater_equal(__u, numeric_limits<_Tp>::min());
8585
}

libcxx/include/initializer_list

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,17 @@ public:
7878

7979
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 initializer_list() _NOEXCEPT : __begin_(nullptr), __size_(0) {}
8080

81-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t size() const _NOEXCEPT { return __size_; }
81+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t size() const _NOEXCEPT {
82+
return __size_;
83+
}
8284

83-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* begin() const _NOEXCEPT { return __begin_; }
85+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* begin() const _NOEXCEPT {
86+
return __begin_;
87+
}
8488

85-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* end() const _NOEXCEPT { return __begin_ + __size_; }
89+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* end() const _NOEXCEPT {
90+
return __begin_ + __size_;
91+
}
8692
};
8793

8894
template <class _Ep>

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,40 @@
1010

1111
// check that <utility> functions are marked [[nodiscard]]
1212

13-
// clang-format off
14-
1513
#include <utility>
1614

1715
#include "test_macros.h"
1816

1917
void test() {
2018
int i = 0;
2119

22-
std::forward<int>(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
23-
std::forward<int>(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
24-
std::move(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
25-
std::move_if_noexcept(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
20+
std::forward<int>(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
21+
std::forward<int>(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
22+
std::move(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
23+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
24+
std::move_if_noexcept(i);
2625

2726
#if TEST_STD_VER >= 17
2827
std::as_const(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
2928
#endif
3029

30+
#if TEST_STD_VER >= 20
31+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
32+
std::cmp_equal(94, 82);
33+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
34+
std::cmp_not_equal(94, 82);
35+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
36+
std::cmp_less(94, 82);
37+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
38+
std::cmp_greater(94, 82);
39+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
40+
std::cmp_less_equal(94, 82);
41+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
42+
std::cmp_greater_equal(94, 82);
43+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
44+
std::in_range<long>(49);
45+
#endif
46+
3147
#if TEST_STD_VER >= 23
3248
enum E { Apple, Orange } e = Apple;
3349
std::to_underlying(e); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 <compare>
14+
#include <coroutine>
15+
#include <functional>
16+
#include <initializer_list>
17+
18+
#include "test_macros.h"
19+
20+
void test() {
21+
#if TEST_STD_VER >= 20
22+
{ // <compare>
23+
int x = 94;
24+
int y = 82;
25+
auto oRes = x <=> y;
26+
27+
std::is_eq(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
28+
std::is_neq(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
29+
std::is_lt(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
30+
std::is_lteq(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
31+
std::is_gt(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
32+
std::is_gteq(oRes); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
33+
}
34+
#endif
35+
36+
#if TEST_STD_VER >= 20
37+
{ // <coroutine>
38+
struct EmptyPromise {
39+
} promise;
40+
41+
{
42+
std::coroutine_handle<void> cr{};
43+
44+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
45+
cr.address();
46+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
47+
std::coroutine_handle<void>::from_address(&promise);
48+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
49+
cr.done();
50+
51+
std::hash<std::coroutine_handle<void>> hash;
52+
hash(cr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
53+
}
54+
{
55+
std::coroutine_handle<EmptyPromise> cr;
56+
57+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
58+
std::coroutine_handle<EmptyPromise>::from_promise(promise);
59+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
60+
cr.address();
61+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
62+
std::coroutine_handle<EmptyPromise>::from_address(&promise);
63+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
64+
cr.done();
65+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
66+
cr.promise();
67+
}
68+
{
69+
std::coroutine_handle<std::noop_coroutine_promise> cr = std::noop_coroutine();
70+
71+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
72+
cr.done();
73+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
74+
cr.promise();
75+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
76+
cr.address();
77+
78+
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
79+
std::noop_coroutine();
80+
}
81+
}
82+
#endif
83+
84+
{ // <initializer_list>
85+
std::initializer_list<int> il{94, 82, 49};
86+
87+
il.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
88+
il.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
89+
il.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
90+
}
91+
}

0 commit comments

Comments
 (0)