[libcxx-commits] [libcxx] 1045d1e - [libc++][ranges] Applied `[[nodiscard]]` to `zip_view` (#207667)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 7 09:01:04 PDT 2026
Author: Hristo Hristov
Date: 2026-07-07T19:00:58+03:00
New Revision: 1045d1ebca559d7e6dee49b002142e52bb61b49e
URL: https://github.com/llvm/llvm-project/commit/1045d1ebca559d7e6dee49b002142e52bb61b49e
DIFF: https://github.com/llvm/llvm-project/commit/1045d1ebca559d7e6dee49b002142e52bb61b49e.diff
LOG: [libc++][ranges] Applied `[[nodiscard]]` to `zip_view` (#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/range.zip
Towards #172124
Added:
libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp
libcxx/test/libcxx/ranges/range.adaptors/range_adaptor_types.h
Modified:
libcxx/include/__ranges/zip_view.h
libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/nodiscard.verify.cpp
Removed:
################################################################################
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[](
diff erence_type __n) const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](
diff erence_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,
diff erence_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i,
diff erence_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+(
diff erence_type __n, const __iterator& __i)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(
diff erence_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,
diff erence_type __n)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i,
diff erence_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
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<__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
__
diff s);
}
- _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_
diff erence_t<__maybe_const<_OtherConst, _Views>>...>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
const auto __
diff s = 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_
diff erence_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.transform/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/nodiscard.verify.cpp
index e681d338dc786..0c4e60701e1eb 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.zip.transform/nodiscard.verify.cpp
@@ -14,6 +14,7 @@
#include <utility>
#include <vector>
+#include "../range_adaptor_types.h"
#include "test_iterators.h"
struct CommonView : std::ranges::view_interface<CommonView> {
@@ -28,26 +29,6 @@ static_assert(std::ranges::common_range<CommonView>);
static_assert(std::same_as<std::ranges::iterator_t<CommonView>, std::ranges::iterator_t<const CommonView>>);
static_assert(std::same_as<std::ranges::sentinel_t<CommonView>, std::ranges::sentinel_t<const CommonView>>);
-struct ForwardSizedNonCommon {
- int* buffer_ = nullptr;
- std::size_t size_ = 0;
-
- template <std::size_t N>
- constexpr ForwardSizedNonCommon(int (&b)[N]) : buffer_(b), size_(N) {}
-
- constexpr ForwardSizedNonCommon(int* b, std::size_t s) : buffer_(b), size_(s) {}
-
- using iterator = forward_sized_iterator<int*>;
- using sentinel = sized_sentinel<iterator>;
-
- constexpr iterator begin() const { return iterator(buffer_); }
- constexpr sentinel end() const { return sentinel(iterator(buffer_ + size_)); }
-};
-static_assert(std::ranges::forward_range<ForwardSizedNonCommon>);
-static_assert(std::ranges::sized_range<ForwardSizedNonCommon>);
-static_assert(!std::ranges::common_range<ForwardSizedNonCommon>);
-static_assert(!std::ranges::random_access_range<ForwardSizedNonCommon>);
-
template <class... Args>
struct Invocable {
int operator()(Args...) const { return 5; }
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..0667757b07658
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.zip/nodiscard.verify.cpp
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "../range_adaptor_types.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+void test() {
+ int arr[]{94, 82, 49};
+ std::vector<int> range;
+
+ std::ranges::zip_view zv{range, arr};
+
+ // [range.zip.view]
+ {
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zv.begin();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(zv).begin();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zv.end();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(zv).end();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ zv.size();
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(zv).size();
+ }
+
+ // [range.zip.iterator]
+
+ {
+ auto it = zv.begin();
+ auto cIt = std::as_const(zv).begin();
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ *cIt;
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cIt[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]
+
+ {
+ std::ranges::zip_view nonCommonZv{ForwardSizedNonCommon(arr)};
+ static_assert(!std::ranges::common_range<decltype(nonCommonZv)>);
+ static_assert(!std::same_as<decltype(nonCommonZv.end()), decltype(nonCommonZv.begin())>);
+ auto it = nonCommonZv.begin();
+ auto cIt = std::as_const(nonCommonZv).begin();
+ auto st = nonCommonZv.end();
+ auto cSt = std::as_const(nonCommonZv).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}}
+ it - cSt;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cSt - it;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ cIt - st;
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ st - cIt;
+ }
+
+ // [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);
+ }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range_adaptor_types.h b/libcxx/test/libcxx/ranges/range.adaptors/range_adaptor_types.h
new file mode 100644
index 0000000000000..cea4cb0dfddd5
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range_adaptor_types.h
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
+
+#include <cstdint>
+#include <ranges>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+#if TEST_STD_VER <= 20
+# error "range.adaptor/types.h" can only be included in builds supporting C++20
+#endif // TEST_STD_VER <= 20
+
+struct ForwardSizedNonCommon {
+ int* buffer_ = nullptr;
+ std::size_t size_ = 0;
+
+ template <std::size_t N>
+ constexpr ForwardSizedNonCommon(int (&b)[N]) : buffer_(b), size_(N) {}
+
+ constexpr ForwardSizedNonCommon(int* b, std::size_t s) : buffer_(b), size_(s) {}
+
+ using iterator = forward_sized_iterator<int*>;
+ using sentinel = sized_sentinel<iterator>;
+
+ constexpr iterator begin() const { return iterator(buffer_); }
+ constexpr sentinel end() const { return sentinel(iterator(buffer_ + size_)); }
+};
+static_assert(std::ranges::forward_range<ForwardSizedNonCommon>);
+static_assert(std::ranges::sized_range<ForwardSizedNonCommon>);
+static_assert(!std::ranges::common_range<ForwardSizedNonCommon>);
+static_assert(!std::ranges::random_access_range<ForwardSizedNonCommon>);
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADAPTOR_TYPES_H
More information about the libcxx-commits
mailing list