[libc++][ranges] Applied [[nodiscard]] to iota_view (#173612)
`[[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/range.iota Towards #172124
This commit is contained in:
parent
fc30dc425b
commit
bb4c8806fb
@ -132,7 +132,8 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const noexcept(is_nothrow_copy_constructible_v<_Start>) {
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const
|
||||
noexcept(is_nothrow_copy_constructible_v<_Start>) {
|
||||
return __value_;
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Start operator[](difference_type __n) const
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator[](difference_type __n) const
|
||||
requires __advanceable<_Start>
|
||||
{
|
||||
return _Start(__value_ + __n);
|
||||
@ -238,27 +239,28 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
|
||||
return __x.__value_ <=> __y.__value_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n)
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n)
|
||||
requires __advanceable<_Start>
|
||||
{
|
||||
__i += __n;
|
||||
return __i;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i)
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i)
|
||||
requires __advanceable<_Start>
|
||||
{
|
||||
return __i + __n;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n)
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n)
|
||||
requires __advanceable<_Start>
|
||||
{
|
||||
__i -= __n;
|
||||
return __i;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
|
||||
operator-(const __iterator& __x, const __iterator& __y)
|
||||
requires __advanceable<_Start>
|
||||
{
|
||||
if constexpr (__integer_like<_Start>) {
|
||||
@ -289,14 +291,14 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
|
||||
return __x.__value_ == __y.__bound_sentinel_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start>
|
||||
operator-(const __iterator& __x, const __sentinel& __y)
|
||||
requires sized_sentinel_for<_BoundSentinel, _Start>
|
||||
{
|
||||
return __x.__value_ - __y.__bound_sentinel_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start>
|
||||
operator-(const __sentinel& __x, const __iterator& __y)
|
||||
requires sized_sentinel_for<_BoundSentinel, _Start>
|
||||
{
|
||||
@ -336,24 +338,24 @@ public:
|
||||
requires(!same_as<_Start, _BoundSentinel> && !same_as<_BoundSentinel, unreachable_sentinel_t>)
|
||||
: iota_view(std::move(__first.__value_), std::move(__last.__bound_sentinel_)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator{__value_}; }
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator{__value_}; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto end() const {
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const {
|
||||
if constexpr (same_as<_BoundSentinel, unreachable_sentinel_t>)
|
||||
return unreachable_sentinel;
|
||||
else
|
||||
return __sentinel{__bound_sentinel_};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const
|
||||
requires same_as<_Start, _BoundSentinel>
|
||||
{
|
||||
return __iterator{__bound_sentinel_};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __value_ == __bound_sentinel_; }
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __value_ == __bound_sentinel_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
|
||||
requires(same_as<_Start, _BoundSentinel> && __advanceable<_Start>) ||
|
||||
(integral<_Start> && integral<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start>
|
||||
{
|
||||
@ -382,13 +384,14 @@ namespace __iota {
|
||||
struct __fn {
|
||||
template <class _Start>
|
||||
requires(requires(_Start __s) { ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__s)); })
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const
|
||||
noexcept(noexcept(ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__start)))) {
|
||||
return ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__start));
|
||||
}
|
||||
|
||||
template <class _Start, class _BoundSentinel>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start, _BoundSentinel&& __bound_sentinel) const noexcept(
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto
|
||||
operator()(_Start&& __start, _BoundSentinel&& __bound_sentinel) const noexcept(
|
||||
noexcept(ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel))))
|
||||
-> decltype(ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel))) {
|
||||
return ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel));
|
||||
@ -402,7 +405,7 @@ inline constexpr auto iota = __iota::__fn{};
|
||||
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
|
||||
inline constexpr auto indices = [](__integer_like auto __size) static {
|
||||
inline constexpr auto indices = [] [[nodiscard]] (__integer_like auto __size) static {
|
||||
return ranges::views::iota(decltype(__size){}, __size);
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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++20
|
||||
|
||||
// Check that functions are marked [[nodiscard]]
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T>
|
||||
struct IntSentinelWith {
|
||||
using difference_type = std::iter_difference_t<T>;
|
||||
|
||||
T value_;
|
||||
constexpr explicit IntSentinelWith(T value = T()) : value_(value) {}
|
||||
|
||||
friend constexpr bool operator==(IntSentinelWith lhs, IntSentinelWith rhs) { return lhs.value_ == rhs.value_; }
|
||||
friend constexpr bool operator==(IntSentinelWith lhs, T rhs) { return lhs.value_ == rhs; }
|
||||
friend constexpr bool operator==(T lhs, IntSentinelWith rhs) { return lhs == rhs.value_; }
|
||||
|
||||
friend constexpr IntSentinelWith operator+(IntSentinelWith lhs, IntSentinelWith rhs) {
|
||||
return IntSentinelWith{lhs.value_ + rhs.value_};
|
||||
}
|
||||
friend constexpr difference_type operator-(IntSentinelWith lhs, IntSentinelWith rhs) {
|
||||
return lhs.value_ - rhs.value_;
|
||||
}
|
||||
friend constexpr difference_type operator-(IntSentinelWith lhs, T rhs) { return lhs.value_ - rhs; }
|
||||
friend constexpr difference_type operator-(T lhs, IntSentinelWith rhs) { return lhs - rhs.value_; }
|
||||
|
||||
constexpr IntSentinelWith& operator++() {
|
||||
++value_;
|
||||
return *this;
|
||||
}
|
||||
constexpr IntSentinelWith operator++(int) {
|
||||
auto tmp = *this;
|
||||
++value_;
|
||||
return tmp;
|
||||
}
|
||||
constexpr IntSentinelWith operator--() {
|
||||
--value_;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
template <class T>
|
||||
IntSentinelWith(T) -> IntSentinelWith<T>;
|
||||
static_assert(std::sized_sentinel_for<IntSentinelWith<random_access_iterator<int*>>, random_access_iterator<int*>>);
|
||||
|
||||
void test() {
|
||||
{
|
||||
// [range.iota.view]
|
||||
|
||||
auto view = std::views::iota(49, 94);
|
||||
auto unboundedView = std::views::iota(82);
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
view.begin();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
unboundedView.end();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
view.end();
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
view.empty();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
view.size();
|
||||
|
||||
// [range.iota.iterator]
|
||||
|
||||
auto it = view.begin();
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
*it;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it[82];
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it + 1;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
1 + it;
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it - 1;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it - it;
|
||||
}
|
||||
|
||||
{
|
||||
// [range.iota.sentinel]
|
||||
|
||||
int buffer[]{94, 82, 47};
|
||||
auto outIter = random_access_iterator<int*>(buffer);
|
||||
std::ranges::iota_view<random_access_iterator<int*>, IntSentinelWith<random_access_iterator<int*>>> view{
|
||||
outIter, IntSentinelWith<random_access_iterator<int*>>(std::ranges::next(outIter, 1))};
|
||||
|
||||
auto it = view.begin();
|
||||
auto st = view.end();
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it - st;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
st - it;
|
||||
}
|
||||
|
||||
{
|
||||
// [range.iota.overview]
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::iota(1);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::iota(1, 10);
|
||||
|
||||
#if _LIBCPP_STD_VER >= 26
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::indices(5);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user