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

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jan 4 22:31:46 PST 2026


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/174360

>From 701e3332534e18f47518120474d1245bb008f748 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 25 Dec 2025 20:54:02 +0200
Subject: [PATCH] [libc++][ranges] Applied `[[nodiscard]]` to `view_interface`

`[[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/view.interface

Towards #172124
---
 libcxx/include/__ranges/view_interface.h      | 20 +++---
 .../view.interface/nodiscard.verify.cpp       | 71 +++++++++++++++++++
 2 files changed, 81 insertions(+), 10 deletions(-)
 create mode 100644 libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp

diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index 3bcfbaf3a2f9e..37b2c9e2c1a75 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -87,35 +87,35 @@ class view_interface {
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto data()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data()
     requires contiguous_iterator<iterator_t<_D2>>
   {
     return std::to_address(ranges::begin(__derived()));
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto data() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() const
     requires range<const _D2> && contiguous_iterator<iterator_t<const _D2>>
   {
     return std::to_address(ranges::begin(__derived()));
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires forward_range<_D2> && sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>>
   {
     return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived()));
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires forward_range<const _D2> && sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>>
   {
     return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived()));
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front()
     requires forward_range<_D2>
   {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
@@ -124,7 +124,7 @@ class view_interface {
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() const
     requires forward_range<const _D2>
   {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
@@ -133,7 +133,7 @@ class view_interface {
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back()
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back()
     requires bidirectional_range<_D2> && common_range<_D2>
   {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
@@ -142,7 +142,7 @@ class view_interface {
   }
 
   template <class _D2 = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() const
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() const
     requires bidirectional_range<const _D2> && common_range<const _D2>
   {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
@@ -151,12 +151,12 @@ class view_interface {
   }
 
   template <random_access_range _RARange = _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) {
     return ranges::begin(__derived())[__index];
   }
 
   template <random_access_range _RARange = const _Derived>
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const {
     return ranges::begin(__derived())[__index];
   }
 };
diff --git a/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..a79189b6e391d
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <cstddef>
+#include <ranges>
+#include <utility>
+
+struct View : std::ranges::view_interface<View> {
+  int* begin();
+  int* end();
+  const int* begin() const;
+  const int* end() const;
+};
+
+static_assert(std::ranges::sized_range<View>);
+static_assert(std::ranges::sized_range<const View>);
+static_assert(std::contiguous_iterator<std::ranges::iterator_t<View>>);
+static_assert(std::contiguous_iterator<std::ranges::iterator_t<const View>>);
+static_assert(std::ranges::forward_range<View>);
+static_assert(std::ranges::forward_range<const View>);
+static_assert(std::sized_sentinel_for<std::ranges::sentinel_t<View>, std::ranges::iterator_t<View>>);
+static_assert(std::sized_sentinel_for<std::ranges::sentinel_t<const View>, std::ranges::iterator_t<const View>>);
+static_assert(std::ranges::bidirectional_range<View>);
+static_assert(std::ranges::bidirectional_range<const View>);
+static_assert(std::ranges::common_range<View>);
+static_assert(std::ranges::common_range<const View>);
+
+void test() {
+  View v;
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.empty();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).empty();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.data();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).data();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.size();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).size();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.front();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).front();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.back();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).back();
+
+  using Diff = std::ranges::range_difference_t<View>;
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v[Diff{0}];
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v)[Diff{0}];
+}



More information about the libcxx-commits mailing list