[libcxx-commits] [libcxx] 8992cdf - [libc++][ranges] Applied [[nodiscard]] to `join_view` (#206838)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 6 22:48:11 PDT 2026
Author: Lucas Mellone
Date: 2026-07-07T13:48:07+08:00
New Revision: 8992cdf458f78c5ef9b018c92234658fc78cfd80
URL: https://github.com/llvm/llvm-project/commit/8992cdf458f78c5ef9b018c92234658fc78cfd80
DIFF: https://github.com/llvm/llvm-project/commit/8992cdf458f78c5ef9b018c92234658fc78cfd80.diff
LOG: [libc++][ranges] Applied [[nodiscard]] to `join_view` (#206838)
[[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.join
Towards https://github.com/llvm/llvm-project/issues/172124
Added:
libcxx/test/libcxx/ranges/range.adaptors/range.join/nodiscard.verify.cpp
Modified:
libcxx/include/__ranges/join_view.h
Removed:
################################################################################
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 364f056d8d2cf..f80b75c839d4a 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -100,15 +100,15 @@ class join_view : public view_interface<join_view<_View>> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit join_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_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin() {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() {
if constexpr (forward_range<_View>) {
constexpr bool __use_const = __simple_view<_View> && is_reference_v<range_reference_t<_View>>;
return __iterator<__use_const>{*this, ranges::begin(__base_)};
@@ -119,14 +119,14 @@ class join_view : public view_interface<join_view<_View>> {
}
template <class _V2 = _View>
- _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
requires forward_range<const _V2> && is_reference_v<range_reference_t<const _V2>> &&
input_range<range_reference_t<const _V2>>
{
return __iterator<true>{*this, ranges::begin(__base_)};
}
- _LIBCPP_HIDE_FROM_ABI constexpr auto end() {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() {
if constexpr (forward_range<_View> && is_reference_v<_InnerRange> && forward_range<_InnerRange> &&
common_range<_View> && common_range<_InnerRange>)
return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)};
@@ -135,7 +135,7 @@ class join_view : public view_interface<join_view<_View>> {
}
template <class _V2 = _View>
- _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
requires forward_range<const _V2> && is_reference_v<range_reference_t<const _V2>> &&
input_range<range_reference_t<const _V2>>
{
@@ -276,7 +276,7 @@ struct join_view<_View>::__iterator final : public __join_view_iterator_category
requires _Const && convertible_to<iterator_t<_View>, _Outer> && convertible_to<iterator_t<_InnerRange>, _Inner>
: __outer_(std::move(__i.__outer_)), __inner_(std::move(__i.__inner_)), __parent_(__i.__parent_) {}
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return **__inner_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return **__inner_; }
_LIBCPP_HIDE_FROM_ABI constexpr _Inner operator->() const
requires __has_arrow<_Inner> && copyable<_Inner>
@@ -339,7 +339,7 @@ struct join_view<_View>::__iterator final : public __join_view_iterator_category
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
}
- _LIBCPP_HIDE_FROM_ABI friend constexpr decltype(auto)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr decltype(auto)
iter_move(const __iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__inner_))) {
return ranges::iter_move(*__i.__inner_);
}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..6a7a93cbe5e81
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/nodiscard.verify.cpp
@@ -0,0 +1,73 @@
+
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// Test the libc++ extension that std::ranges::join_view and std::views::view are marked as [[nodiscard]].
+
+#include <functional>
+#include <ranges>
+#include <string>
+#include <utility>
+#include <vector>
+
+struct InnerView : std::ranges::view_interface<InnerView> {
+ int* begin();
+ const int* begin() const;
+ volatile int* end();
+ const volatile int* end() const;
+};
+
+struct View : std::ranges::view_interface<View> {
+ InnerView* begin();
+ const InnerView* begin() const;
+ volatile InnerView* end();
+ const volatile InnerView* 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() {
+ auto v = View{} | std::views::join;
+
+ // [range.join.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();
+
+ // [range.join.iterator]
+
+ 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}}
+ iter_move(c_it);
+
+ // [range.join.overview]
+
+ std::vector<std::string> ss{"hello", " ", "world", "!"};
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::views::join(ss);
+}
More information about the libcxx-commits
mailing list