[libcxx-commits] [libcxx] [libc++][ranges] Applied `[[nodiscard]]` to `zip_view` (PR #207667)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 6 00:14:24 PDT 2026
https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/207667
`[[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/ranges.zip
Towards #172124
>From 33e16582ed6dcc20864c817ae0e660052916ed65 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 21 Jan 2026 13:44:27 +0200
Subject: [PATCH] [libc++][ranges] Applied `[[nodiscard]]` to `zip_view`
`[[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/ranges.zip
Towards #172124
---
libcxx/include/__ranges/zip_view.h | 33 ++++---
.../range.zip/nodiscard.verify.cpp | 92 +++++++++++++++++++
2 files changed, 110 insertions(+), 15 deletions(-)
create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp
diff --git a/libcxx/include/__ranges/zip_view.h b/libcxx/include/__ranges/zip_view.h
index bea64c4997a9e..aa13bed5f428d 100644
--- a/libcxx/include/__ranges/zip_view.h
+++ b/libcxx/include/__ranges/zip_view.h
@@ -134,19 +134,19 @@ class zip_view : public view_interface<zip_view<_Views...>> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit zip_view(_Views... __views) : __views_(std::move(__views)...) {}
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
requires(!(__simple_view<_Views> && ...))
{
return __iterator<false>(std::__tuple_transform(ranges::begin, __views_));
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
requires(range<const _Views> && ...)
{
return __iterator<true>(std::__tuple_transform(ranges::begin, __views_));
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
requires(!(__simple_view<_Views> && ...))
{
if constexpr (!__zip_is_common<_Views...>) {
@@ -158,7 +158,7 @@ class zip_view : public view_interface<zip_view<_Views...>> {
}
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
requires(range<const _Views> && ...)
{
if constexpr (!__zip_is_common<const _Views...>) {
@@ -170,7 +170,7 @@ class zip_view : public view_interface<zip_view<_Views...>> {
}
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
requires(sized_range<_Views> && ...)
{
return std::apply(
@@ -181,7 +181,7 @@ class zip_view : public view_interface<zip_view<_Views...>> {
std::__tuple_transform(ranges::size, __views_));
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
requires(sized_range<const _Views> && ...)
{
return std::apply(
@@ -267,7 +267,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
requires _Const && (convertible_to<iterator_t<_Views>, iterator_t<__maybe_const<_Const, _Views>>> && ...)
: __current_(std::move(__i.__current_)) {}
- _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_);
}
@@ -315,7 +315,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
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 __zip_all_random_access<_Const, _Views...>
{
return std::__tuple_transform(
@@ -338,7 +338,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
return __x.__current_ <=> __y.__current_;
}
- _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 __zip_all_random_access<_Const, _Views...>
{
auto __r = __i;
@@ -346,13 +346,13 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
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 __zip_all_random_access<_Const, _Views...>
{
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 __zip_all_random_access<_Const, _Views...>
{
auto __r = __i;
@@ -360,7 +360,8 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
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<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
...)
{
@@ -374,7 +375,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
__diffs);
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept(
(noexcept(ranges::iter_move(std::declval<const iterator_t<__maybe_const<_Const, _Views>>&>())) && ...) &&
(is_nothrow_move_constructible_v<range_rvalue_reference_t<__maybe_const<_Const, _Views>>> && ...)) {
return std::__tuple_transform(ranges::iter_move, __i.__current_);
@@ -426,6 +427,7 @@ class zip_view<_Views...>::__sentinel {
requires(
sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_OtherConst, _Views>>> &&
...)
+ [[nodiscard]]
_LIBCPP_HIDE_FROM_ABI friend constexpr common_type_t<range_difference_t<__maybe_const<_OtherConst, _Views>>...>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
const auto __diffs = ranges::__tuple_zip_transform(minus<>(), __iter_current(__x), __y.__end_);
@@ -443,6 +445,7 @@ class zip_view<_Views...>::__sentinel {
requires(
sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_OtherConst, _Views>>> &&
...)
+ [[nodiscard]]
_LIBCPP_HIDE_FROM_ABI friend constexpr common_type_t<range_difference_t<__maybe_const<_OtherConst, _Views>>...>
operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) {
return -(__x - __y);
@@ -456,10 +459,10 @@ namespace views {
namespace __zip {
struct __fn {
- _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()() noexcept { return empty_view<tuple<>>{}; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()() noexcept { return empty_view<tuple<>>{}; }
template <class... _Ranges>
- _LIBCPP_HIDE_FROM_ABI static constexpr auto
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Ranges&&... __rs) noexcept(noexcept(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)))
-> decltype(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)) {
return zip_view<all_t<_Ranges>...>(std::forward<_Ranges>(__rs)...);
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..59a1518a006ef
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <ranges>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <ranges>
+#include <vector>
+#include <utility>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+void test() {
+ int arr[]{94, 82, 49};
+ std::vector<int> range;
+
+ std::ranges::zip_view view{range, arr};
+
+ // [range.zip.view]
+ {
+ // 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}}
+ std::as_const(view).begin();
+
+ // 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}}
+ std::as_const(view).end();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ view.size();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(view).size();
+ }
+
+ // [range.zip.iterator]
+
+ {
+ auto it = view.begin();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ *std::as_const(it);
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(it)[0];
+
+ // 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;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ iter_move(it);
+ }
+
+ // [range.zip.sentinel]
+
+ {
+ auto it = view.begin();
+ auto st = view.end();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(it) - st;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ st - std::as_const(it);
+ }
+
+ // [range.zip.overview]
+
+ {
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::zip();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::zip(arr, arr);
+ }
+}
More information about the libcxx-commits
mailing list