diff --git a/libcxx/include/__ranges/join_with_view.h b/libcxx/include/__ranges/join_with_view.h index 8ed989a66468..3ce9011762e2 100644 --- a/libcxx/include/__ranges/join_with_view.h +++ b/libcxx/include/__ranges/join_with_view.h @@ -372,7 +372,7 @@ public: return __tmp; } - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) requires __ref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> { return __x.__outer_it_ == __y.__outer_it_ && __x.__inner_it_ == __y.__inner_it_; @@ -420,8 +420,7 @@ public: template requires sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool - operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { return __get_outer_of(__x) == __y.__end_; } }; diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h index 87e1991a1f3b..3d94b0a72b96 100644 --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -131,7 +131,7 @@ public: return _Pair(__begin_, __end_); } - _LIBCPP_HIDE_FROM_ABI constexpr _Iter begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter begin() const requires copyable<_Iter> { return __begin_; @@ -143,11 +143,11 @@ public: return std::move(__begin_); } - _LIBCPP_HIDE_FROM_ABI constexpr _Sent end() const { return __end_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Sent end() const { return __end_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __begin_ == __end_; } - _LIBCPP_HIDE_FROM_ABI constexpr make_unsigned_t> size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr make_unsigned_t> size() const requires(_Kind == subrange_kind::sized) { if constexpr (_StoreSize) @@ -214,7 +214,7 @@ subrange(_Range&&, make_unsigned_t>) template requires((_Index == 0 && copyable<_Iter>) || _Index == 1) -_LIBCPP_HIDE_FROM_ABI constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __subrange) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __subrange) { if constexpr (_Index == 0) return __subrange.begin(); else @@ -223,7 +223,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __ template requires(_Index < 2) -_LIBCPP_HIDE_FROM_ABI constexpr auto get(subrange<_Iter, _Sent, _Kind>&& __subrange) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto get(subrange<_Iter, _Sent, _Kind>&& __subrange) { if constexpr (_Index == 0) return __subrange.begin(); else diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join.with/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join.with/nodiscard.verify.cpp index dc2a9f5074ae..f94992c44326 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join.with/nodiscard.verify.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join.with/nodiscard.verify.cpp @@ -10,7 +10,6 @@ // Test that functions are marked [[nodiscard]]. -#include #include #include @@ -23,77 +22,37 @@ void test() { std::ranges::join_with_view view(range, pattern); - // clang-format off - view.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::as_const(view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::move(std::as_const(view)).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::move(view).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on + // [range.join.with.view] - // clang-format off - view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::as_const(view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(view).base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(view).base(); - // clang-format off - view.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::as_const(view).end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on -} - -void test_iterator() { - char range[3][2] = {{'x', 'x'}, {'y', 'y'}, {'z', 'z'}}; - char pattern[2] = {',', ' '}; - - std::ranges::join_with_view view(range, pattern); - - // clang-format off - *view.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - *std::as_const(view).begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on - - // clang-format off - (view.begin() == view.end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (std::as_const(view).begin() == view.end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (view.begin() == std::as_const(view).end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (std::as_const(view).begin() == std::as_const(view).end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on - - // clang-format off - iter_move(view.begin()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - iter_move(std::as_const(view).begin()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on -} - -void test_sentinel() { - std::array, 0> range; - std::array pattern; - - std::ranges::join_with_view view(range, pattern); - static_assert(!std::ranges::common_range); - - // clang-format off - (view.begin() == view.end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (std::as_const(view).begin() == view.end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (view.begin() == std::as_const(view).end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - (std::as_const(view).begin() == std::as_const(view).end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on -} - -void test_overview() { - int range[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - int pattern_base[2] = {-1, -1}; - auto pattern = std::views::all(pattern_base); - - // clang-format off - std::views::join_with(pattern); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::views::join_with(range, pattern); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - range | std::views::join_with(pattern); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::views::reverse | std::views::join_with(pattern); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - - std::views::join_with(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::views::join_with(range, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - range | std::views::join_with(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::views::reverse | std::views::join_with(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - // clang-format on + // 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}} + std::as_const(view).begin(); + + // 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}} + std::as_const(view).end(); + + // [range.join.with.iterator] + + auto cIt = std::as_const(view).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *cIt; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + iter_move(cIt); + + // [range.join.with.overview] + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::join_with(range, pattern); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::join_with(pattern); } diff --git a/libcxx/test/libcxx/ranges/range.utility/range.subrange/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.utility/range.subrange/nodiscard.verify.cpp new file mode 100644 index 000000000000..9ef94873b26e --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.utility/range.subrange/nodiscard.verify.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Test that functions are marked [[nodiscard]]. + +#include +#include +#include + +struct MoveOnlyIterator { + using iterator_concept = std::input_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = int; + + MoveOnlyIterator() = default; + + MoveOnlyIterator(MoveOnlyIterator&&) = default; + MoveOnlyIterator& operator=(MoveOnlyIterator&&) = default; + + MoveOnlyIterator(const MoveOnlyIterator&) = delete; + MoveOnlyIterator& operator=(const MoveOnlyIterator&) = delete; + + int operator*() const; + + MoveOnlyIterator& operator++(); + + void operator++(int); + + friend bool operator==(const MoveOnlyIterator&, std::default_sentinel_t); +}; +static_assert(std::input_iterator); +static_assert(!std::copyable); + +void test() { + std::vector range; + std::ranges::subrange subrange{range.begin(), range.end()}; + + MoveOnlyIterator it; + auto moveOnlySubrange = std::ranges::subrange(std::move(it), std::default_sentinel); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).begin(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(moveOnlySubrange).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).end(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).empty(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).size(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).next(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(subrange).next(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(subrange).prev(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(subrange).prev(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::as_const(subrange)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(subrange)); +}