[libcxx-commits] [libcxx] [libc++][ranges] Applied `[[nodiscard]]` to `reverse_view` (PR #205186)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 22 14:10:04 PDT 2026


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/205186

>From fed66125c6750e97fa37b319f4baec7a22e4a306 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 22 Jun 2026 23:26:39 +0300
Subject: [PATCH] [libc++][ranges] Applied `[[nodiscard]]` to `reverse_view`

Towards #172124

- https://wg21.link/range.reverse
- https://libcxx.llvm.org/CodingGuidelines.html#apply-nodiscard-where-relevant
---
 libcxx/include/__ranges/reverse_view.h        | 16 +--
 .../adaptor.nodiscard.verify.cpp              | 21 ----
 .../range.reverse/nodiscard.verify.cpp        | 99 +++++++++++++++++++
 3 files changed, 107 insertions(+), 29 deletions(-)
 delete mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.reverse/adaptor.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.reverse/nodiscard.verify.cpp

diff --git a/libcxx/include/__ranges/reverse_view.h b/libcxx/include/__ranges/reverse_view.h
index c36ba77dd8f6d..b016cc231f2b5 100644
--- a/libcxx/include/__ranges/reverse_view.h
+++ b/libcxx/include/__ranges/reverse_view.h
@@ -59,13 +59,13 @@ class reverse_view : public view_interface<reverse_view<_View>> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr explicit reverse_view(_View __view) : __base_(std::move(__view)) {}
 
-  _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_); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
 
   _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator<iterator_t<_View>> begin() {
     if constexpr (_UseCache)
@@ -78,35 +78,35 @@ class reverse_view : public view_interface<reverse_view<_View>> {
     return __tmp;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator<iterator_t<_View>> begin()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator<iterator_t<_View>> begin()
     requires common_range<_View>
   {
     return std::make_reverse_iterator(ranges::end(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
     requires common_range<const _View>
   {
     return std::make_reverse_iterator(ranges::end(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator<iterator_t<_View>> end() {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator<iterator_t<_View>> end() {
     return std::make_reverse_iterator(ranges::begin(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires common_range<const _View>
   {
     return std::make_reverse_iterator(ranges::begin(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
     return ranges::size(__base_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
     return ranges::size(__base_);
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/adaptor.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/adaptor.nodiscard.verify.cpp
deleted file mode 100644
index 2f7eb94611928..0000000000000
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/adaptor.nodiscard.verify.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// Test the libc++ extension that std::views::reverse is marked as [[nodiscard]].
-
-#include <ranges>
-
-void test() {
-  int range[] = {1, 2, 3};
-
-  std::views::reverse(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  range | std::views::reverse; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::all | std::views::reverse; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..6dfa2f5d17c60
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.reverse/nodiscard.verify.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <utility>
+
+#include "test_iterators.h"
+
+void test() {
+  int range[] = {19, 28, 29, 49, 82, 94};
+  auto v      = std::views::reverse(range);
+
+  // [range.reverse.view]
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.base();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(v).base();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.begin();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).begin();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.end();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).end();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.size();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).size();
+
+  // [range.reverse.overview]
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::reverse(std::views::reverse(range));
+
+  struct BidirRange : std::ranges::view_base {
+    int* begin_;
+    int* end_;
+
+    constexpr BidirRange(int* b, int* e) : begin_(b), end_(e) {}
+
+    constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
+    constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
+    constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{end_}; }
+    constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{end_}; }
+  };
+  static_assert(std::ranges::bidirectional_range<BidirRange>);
+  static_assert(std::ranges::common_range<BidirRange>);
+  static_assert(std::ranges::view<BidirRange>);
+  static_assert(std::copyable<BidirRange>);
+
+  { // views::reverse(x) is equivalent to subrange{end, begin, size} if x is a
+    // sized subrange over reverse iterators
+    using It       = bidirectional_iterator<int*>;
+    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::sized>;
+
+    using ReverseIt       = std::reverse_iterator<It>;
+    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::sized>;
+
+    BidirRange view(range, range + 6);
+    ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */ 6);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::reverse(subrange);
+  }
+  { // views::reverse(x) is equivalent to subrange{end, begin} if x is an
+    // unsized subrange over reverse iterators
+    using It       = bidirectional_iterator<int*>;
+    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::unsized>;
+
+    using ReverseIt       = std::reverse_iterator<It>;
+    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::unsized>;
+
+    BidirRange view(range, range + 6);
+    ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::reverse(subrange);
+  }
+  { // Otherwise, views::reverse(x) is equivalent to ranges::reverse_view{x}
+    BidirRange view(range, range + 6);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::reverse(view);
+  }
+}



More information about the libcxx-commits mailing list