[libcxx-commits] [libcxx] bb4c880 - [libc++][ranges] Applied `[[nodiscard]]` to `iota_view` (#173612)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 30 03:05:00 PST 2025


Author: Hristo Hristov
Date: 2025-12-30T13:04:57+02:00
New Revision: bb4c8806fb376bac7035a118791e2ef8aa3c339f

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

LOG: [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

Added: 
    libcxx/test/libcxx/ranges/range.factories/range.iota.view/nodiscard.verify.cpp

Modified: 
    libcxx/include/__ranges/iota_view.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h
index f66f3f9183fc7..6b2576ec6b23d 100644
--- a/libcxx/include/__ranges/iota_view.h
+++ b/libcxx/include/__ranges/iota_view.h
@@ -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[](
diff erence_type __n) const
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator[](
diff erence_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, 
diff erence_type __n)
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, 
diff erence_type __n)
       requires __advanceable<_Start>
     {
       __i += __n;
       return __i;
     }
 
-    _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(
diff erence_type __n, __iterator __i)
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(
diff erence_type __n, __iterator __i)
       requires __advanceable<_Start>
     {
       return __i + __n;
     }
 
-    _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, 
diff erence_type __n)
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, 
diff erence_type __n)
       requires __advanceable<_Start>
     {
       __i -= __n;
       return __i;
     }
 
-    _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 __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_
diff erence_t<_Start>
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_
diff erence_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_
diff erence_t<_Start>
+    [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_
diff erence_t<_Start>
     operator-(const __sentinel& __x, const __iterator& __y)
       requires sized_sentinel_for<_BoundSentinel, _Start>
     {
@@ -336,24 +338,24 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
     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);
 };
 

diff  --git a/libcxx/test/libcxx/ranges/range.factories/range.iota.view/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.factories/range.iota.view/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..b40204417274c
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.factories/range.iota.view/nodiscard.verify.cpp
@@ -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 
diff erence_type = std::iter_
diff erence_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 
diff erence_type operator-(IntSentinelWith lhs, IntSentinelWith rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+  friend constexpr 
diff erence_type operator-(IntSentinelWith lhs, T rhs) { return lhs.value_ - rhs; }
+  friend constexpr 
diff erence_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 at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    view.begin();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    unboundedView.end();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    view.end();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    view.empty();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    view.size();
+
+    // [range.iota.iterator]
+
+    auto it = view.begin();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    *it;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    it[82];
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    it + 1;
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    1 + it;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    it - 1;
+    // expected-warning at +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 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;
+  }
+
+  {
+    // [range.iota.overview]
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::iota(1);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::iota(1, 10);
+
+#if _LIBCPP_STD_VER >= 26
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::views::indices(5);
+#endif
+  }
+}


        


More information about the libcxx-commits mailing list