diff --git a/libcxx/include/__ranges/adjacent_view.h b/libcxx/include/__ranges/adjacent_view.h index 40474b85c794f..ac1366adb4efc 100644 --- a/libcxx/include/__ranges/adjacent_view.h +++ b/libcxx/include/__ranges/adjacent_view.h @@ -81,26 +81,26 @@ class adjacent_view : public view_interface> { _LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_view(_View __base) : __base_(std::move(__base)) {} - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!__simple_view<_View>) { return __iterator(ranges::begin(__base_), ranges::end(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range // LWG4482 This is under-constrained. { return __iterator(ranges::begin(__base_), ranges::end(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!__simple_view<_View>) { if constexpr (common_range<_View>) { @@ -110,7 +110,7 @@ class adjacent_view : public view_interface> { } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range // LWG4482 This is under-constrained. { if constexpr (common_range) { @@ -120,7 +120,7 @@ class adjacent_view : public view_interface> { } } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { using _ST = decltype(ranges::size(__base_)); @@ -130,7 +130,7 @@ class adjacent_view : public view_interface> { return static_cast<_ST>(__sz); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range { using _ST = decltype(ranges::size(__base_)); @@ -205,7 +205,7 @@ class adjacent_view<_View, _Np>::__iterator { requires _Const && convertible_to, iterator_t> : __iterator(std::move(__i), make_index_sequence<_Np>{}) {} - _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return std::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_); } @@ -257,7 +257,7 @@ class adjacent_view<_View, _Np>::__iterator { return *this; } - _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const requires random_access_range<_Base> { return std::__tuple_transform([&](auto& __i) -> decltype(auto) { return __i[__n]; }, __current_); @@ -297,7 +297,7 @@ class adjacent_view<_View, _Np>::__iterator { return __x.__current_.back() <=> __y.__current_.back(); } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) requires random_access_range<_Base> { auto __r = __i; @@ -305,13 +305,13 @@ class adjacent_view<_View, _Np>::__iterator { return __r; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) requires random_access_range<_Base> { return __i + __n; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) requires random_access_range<_Base> { auto __r = __i; @@ -319,7 +319,8 @@ class adjacent_view<_View, _Np>::__iterator { return __r; } - _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 sized_sentinel_for, iterator_t<_Base>> { return __x.__current_.back() - __y.__current_.back(); @@ -366,14 +367,14 @@ class adjacent_view<_View, _Np>::__sentinel { template requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> - _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) { return __x.__current_.back() - __y.__end_; } template requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> - _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) { return __y.__end_ - __x.__current_.back(); } @@ -389,12 +390,12 @@ template struct __fn : __range_adaptor_closure<__fn<_Np>> { template requires(_Np == 0 && forward_range<_Range &&>) - _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&&) noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&&) noexcept { return empty_view>{}; } template - _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&& __range) noexcept( + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&& __range) noexcept( noexcept(adjacent_view, _Np>(std::forward<_Ranges>(__range)))) -> decltype(adjacent_view, _Np>(std::forward<_Ranges>(__range))) { return adjacent_view, _Np>(std::forward<_Ranges>(__range)); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adjacent/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adjacent/nodiscard.verify.cpp new file mode 100644 index 0000000000000..36b5ade3a4999 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adjacent/nodiscard.verify.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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++23 + +// Test the libc++ extension that std::ranges::adjacent_view and std::views::adjacent are marked as [[nodiscard]]. + +#include +#include + +struct View : std::ranges::view_interface { + int* begin(); + const int* begin() const; + volatile int* end(); + const volatile int* end() const; +}; +static_assert(!std::ranges::common_range); +static_assert(!std::same_as, std::ranges::iterator_t>); +static_assert(!std::same_as, std::ranges::sentinel_t>); + +void test() { + int range[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + auto v = View{} | std::views::adjacent<2>; + + // [range.adjacent.view] + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(v).base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(v).base(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.begin(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(v).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.end(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(v).end(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.size(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(v).size(); + + // [range.adjacent.iterator] + + auto it = v.begin(); + auto c_it = std::as_const(v).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *c_it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + c_it[0]; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it + 0; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + 0 + it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it - 0; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it - it; + + // [range.adjacent.sentinel] + + auto st = v.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; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + st - c_it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + c_it - st; + + // [range.adjacent.overview] + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::adjacent<0>(range); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::adjacent<2>(range); +}