[libcxx-commits] [libcxx] cf1f0e9 - [libc++][ranges] Applied [[nodiscard]] to `adjacent_view` (#205206)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 29 04:46:54 PDT 2026


Author: Lucas Mellone
Date: 2026-06-29T19:46:49+08:00
New Revision: cf1f0e9d82abeb5b2283aee1614d98288403f4fe

URL: https://github.com/llvm/llvm-project/commit/cf1f0e9d82abeb5b2283aee1614d98288403f4fe
DIFF: https://github.com/llvm/llvm-project/commit/cf1f0e9d82abeb5b2283aee1614d98288403f4fe.diff

LOG: [libc++][ranges] Applied [[nodiscard]] to `adjacent_view` (#205206)

[[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.adjacent

Towards https://github.com/llvm/llvm-project/issues/172124

---------

Co-authored-by: A. Jiang <de34 at live.cn>
Co-authored-by: Hristo Hristov <zingam at outlook.com>

Added: 
    libcxx/test/libcxx/ranges/range.adaptors/range.adjacent/nodiscard.verify.cpp

Modified: 
    libcxx/include/__ranges/adjacent_view.h

Removed: 
    


################################################################################
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<adjacent_view<_View, _Np>> {
 
   _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<false>(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<const _View> // LWG4482 This is under-constrained.
   {
     return __iterator<true>(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<adjacent_view<_View, _Np>> {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires range<const _View> // LWG4482 This is under-constrained.
   {
     if constexpr (common_range<const _View>) {
@@ -120,7 +120,7 @@ class adjacent_view : public view_interface<adjacent_view<_View, _Np>> {
     }
   }
 
-  _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<adjacent_view<_View, _Np>> {
     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<const _View>
   {
     using _ST = decltype(ranges::size(__base_));
@@ -205,7 +205,7 @@ class adjacent_view<_View, _Np>::__iterator {
     requires _Const && convertible_to<iterator_t<_View>, iterator_t<const _View>>
       : __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[](
diff erence_type __n) const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](
diff erence_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, 
diff erence_type __n)
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, 
diff erence_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+(
diff erence_type __n, const __iterator& __i)
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(
diff erence_type __n, const __iterator& __i)
     requires random_access_range<_Base>
   {
     return __i + __n;
   }
 
-  _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, 
diff erence_type __n)
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, 
diff erence_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 
diff erence_type operator-(const __iterator& __x, const __iterator& __y)
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr 
diff erence_type
+  operator-(const __iterator& __x, const __iterator& __y)
     requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
   {
     return __x.__current_.back() - __y.__current_.back();
@@ -366,14 +367,14 @@ class adjacent_view<_View, _Np>::__sentinel {
 
   template <bool _OtherConst>
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
-  _LIBCPP_HIDE_FROM_ABI friend constexpr range_
diff erence_t<__maybe_const<_OtherConst, _View>>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_
diff erence_t<__maybe_const<_OtherConst, _View>>
   operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
     return __x.__current_.back() - __y.__end_;
   }
 
   template <bool _OtherConst>
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
-  _LIBCPP_HIDE_FROM_ABI friend constexpr range_
diff erence_t<__maybe_const<_OtherConst, _View>>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_
diff erence_t<__maybe_const<_OtherConst, _View>>
   operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) {
     return __y.__end_ - __x.__current_.back();
   }
@@ -389,12 +390,12 @@ template <size_t _Np>
 struct __fn : __range_adaptor_closure<__fn<_Np>> {
   template <class _Range>
     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<tuple<>>{};
   }
 
   template <class _Ranges>
-  _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<views::all_t<_Ranges&&>, _Np>(std::forward<_Ranges>(__range))))
       -> decltype(adjacent_view<views::all_t<_Ranges&&>, _Np>(std::forward<_Ranges>(__range))) {
     return adjacent_view<views::all_t<_Ranges&&>, _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 <ranges>
+#include <utility>
+
+struct View : std::ranges::view_interface<View> {
+  int* begin();
+  const int* begin() const;
+  volatile int* end();
+  const volatile int* end() const;
+};
+static_assert(!std::ranges::common_range<View>);
+static_assert(!std::same_as<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
+static_assert(!std::same_as<std::ranges::sentinel_t<View>, std::ranges::sentinel_t<const View>>);
+
+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 at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(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.adjacent.iterator]
+
+  auto it   = v.begin();
+  auto c_it = std::as_const(v).begin();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *c_it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  c_it[0];
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it + 0;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  0 + it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it - 0;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it - it;
+
+  // [range.adjacent.sentinel]
+
+  auto st = v.end();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it - st;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  st - it;
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  st - c_it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  c_it - st;
+
+  // [range.adjacent.overview]
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::adjacent<0>(range);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::adjacent<2>(range);
+}


        


More information about the libcxx-commits mailing list