[libcxx-commits] [libcxx] [libc++][ranges] Applied [[nodiscard]] to `join_view` (PR #206838)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jul 4 14:39:26 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Lucas Mellone (lknknm)

<details>
<summary>Changes</summary>

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

---
Full diff: https://github.com/llvm/llvm-project/pull/206838.diff


2 Files Affected:

- (modified) libcxx/include/__ranges/join_view.h (+8-8) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.join/nodiscard.verify.cpp (+73) 


``````````diff
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 364f056d8d2cf..c379b63975e4f 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>
@@ -340,7 +340,7 @@ struct join_view<_View>::__iterator final : public __join_view_iterator_category
   }
 
   _LIBCPP_HIDE_FROM_ABI friend constexpr decltype(auto)
-  iter_move(const __iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__inner_))) {
+  [[nodiscard]] 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);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/206838


More information about the libcxx-commits mailing list