-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[libc++][span] Mark functions as [[nodiscard]]
#168033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
+129
−37
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
|
@llvm/pr-subscribers-libcxx Author: Hristo Hristov (H-G-Hristov) ChangesFull diff: https://github.com/llvm/llvm-project/pull/168033.diff 2 Files Affected:
diff --git a/libcxx/include/span b/libcxx/include/span
index 3d4f9e4ba7831..c24c31282e2cb 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -310,30 +310,32 @@ public:
}
template <size_t _Count>
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept {
static_assert(_Count <= _Extent, "span<T, N>::first<Count>(): Count out of range");
return span<element_type, _Count>{data(), _Count};
}
template <size_t _Count>
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept {
static_assert(_Count <= _Extent, "span<T, N>::last<Count>(): Count out of range");
return span<element_type, _Count>{data() + size() - _Count, _Count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
+ first(size_type __count) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::first(count): count out of range");
return {data(), __count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
+ last(size_type __count) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::last(count): count out of range");
return {data() + size() - __count, __count};
}
template <size_t _Offset, size_t _Count = dynamic_extent>
- _LIBCPP_HIDE_FROM_ABI constexpr auto
- subspan() const noexcept -> span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset> {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto subspan() const noexcept
+ -> span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset> {
static_assert(_Offset <= _Extent, "span<T, N>::subspan<Offset, Count>(): Offset out of range");
static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset,
"span<T, N>::subspan<Offset, Count>(): Offset + Count out of range");
@@ -342,7 +344,7 @@ public:
return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span<T, N>::subspan(offset, count): offset out of range");
if (__count == dynamic_extent)
@@ -352,8 +354,10 @@ public:
return {data() + __offset, __count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return _Extent; }
- _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return _Extent * sizeof(element_type); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return _Extent; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept {
+ return _Extent * sizeof(element_type);
+ }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return _Extent == 0; }
_LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept {
@@ -362,42 +366,46 @@ public:
}
# if _LIBCPP_STD_VER >= 26
- _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
if (__index >= size())
std::__throw_out_of_range("span");
return __data_[__index];
}
# endif
- _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::front() on empty span");
return __data_[0];
}
- _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::back() on empty span");
return __data_[size() - 1];
}
- _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; }
// [span.iter], span iterator support
- _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept {
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data(), data(), data() + size());
# else
return iterator(data());
# endif
}
- _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept {
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data() + size(), data(), data() + size());
# else
return iterator(data() + size());
# endif
}
- _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
- _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept {
+ return reverse_iterator(end());
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept {
+ return reverse_iterator(begin());
+ }
_LIBCPP_HIDE_FROM_ABI span<const byte, _Extent * sizeof(element_type)> __as_bytes() const noexcept {
return span<const byte, _Extent * sizeof(element_type)>{reinterpret_cast<const byte*>(data()), size_bytes()};
@@ -478,36 +486,38 @@ public:
: __data_{__other.data()}, __size_{__other.size()} {}
template <size_t _Count>
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::first<Count>(): Count out of range");
return span<element_type, _Count>{data(), _Count};
}
template <size_t _Count>
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::last<Count>(): Count out of range");
return span<element_type, _Count>{data() + size() - _Count, _Count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
+ first(size_type __count) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::first(count): count out of range");
return {data(), __count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent>
+ last(size_type __count) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::last(count): count out of range");
return {data() + size() - __count, __count};
}
template <size_t _Offset, size_t _Count = dynamic_extent>
- _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> subspan() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> subspan() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Offset <= size(), "span<T>::subspan<Offset, Count>(): Offset out of range");
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset,
"span<T>::subspan<Offset, Count>(): Offset + Count out of range");
return span<element_type, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
}
- constexpr span<element_type, dynamic_extent> _LIBCPP_HIDE_FROM_ABI
+ [[nodiscard]] constexpr span<element_type, dynamic_extent> _LIBCPP_HIDE_FROM_ABI
subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span<T>::subspan(offset, count): offset out of range");
if (__count == dynamic_extent)
@@ -517,8 +527,10 @@ public:
return {data() + __offset, __count};
}
- _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return __size_; }
- _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return __size_ * sizeof(element_type); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return __size_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept {
+ return __size_ * sizeof(element_type);
+ }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return __size_ == 0; }
_LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept {
@@ -527,42 +539,46 @@ public:
}
# if _LIBCPP_STD_VER >= 26
- _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
if (__index >= size())
std::__throw_out_of_range("span");
return __data_[__index];
}
# endif
- _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::front() on empty span");
return __data_[0];
}
- _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::back() on empty span");
return __data_[size() - 1];
}
- _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; }
// [span.iter], span iterator support
- _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept {
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data(), data(), data() + size());
# else
return iterator(data());
# endif
}
- _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept {
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data() + size(), data(), data() + size());
# else
return iterator(data() + size());
# endif
}
- _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
- _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept {
+ return reverse_iterator(end());
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept {
+ return reverse_iterator(begin());
+ }
_LIBCPP_HIDE_FROM_ABI span<const byte, dynamic_extent> __as_bytes() const noexcept {
return {reinterpret_cast<const byte*>(data()), size_bytes()};
@@ -585,13 +601,13 @@ inline constexpr bool ranges::enable_view<span<_ElementType, _Extent>> = true;
// as_bytes & as_writable_bytes
template <class _Tp, size_t _Extent>
-_LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept {
return __s.__as_bytes();
}
template <class _Tp, size_t _Extent>
requires(!is_const_v<_Tp>)
-_LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept {
return __s.__as_writable_bytes();
}
diff --git a/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp b/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..16602715d280c
--- /dev/null
+++ b/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <span>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <array>
+#include <span>
+#include <vector>
+
+#include "test_macros.h"
+
+void test() {
+ { // Test with a static extent
+ std::array arr{94, 92};
+ std::span sp{arr};
+
+ sp.first<1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.last<1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.first(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.last(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.subspan<0, 1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.subspan(0, 1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.size_bytes(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 26
+ sp.at(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+ sp.front(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.back(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.data(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.rbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.rend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ std::as_bytes(sp); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_writable_bytes(sp);
+ }
+ { // Test with a dynamic extent
+ std::vector vec{94, 92};
+ std::span sp{vec};
+
+ sp.first<1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.last<1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.first(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.last(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.subspan<0, 1>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.subspan(0, 1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.size_bytes(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 26
+ sp.at(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+ sp.front(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.back(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.data(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.rbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sp.rend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ std::as_bytes(sp); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_writable_bytes(sp);
+ }
+}
|
9512c4a to
334f144
Compare
philnik777
approved these changes
Nov 14, 2025
Contributor
philnik777
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % nits.
libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
Outdated
Show resolved
Hide resolved
…y.cpp Co-authored-by: Nikolas Klauser <nikolasklauser@berlin.de>
…y.cpp Co-authored-by: Nikolas Klauser <nikolasklauser@berlin.de>
Zingam
reviewed
Nov 14, 2025
libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
Outdated
Show resolved
Hide resolved
Zingam
reviewed
Nov 14, 2025
libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
Outdated
Show resolved
Hide resolved
philnik777
approved these changes
Nov 17, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
https://libcxx.llvm.org/CodingGuidelines.html#apply-nodiscard-where-relevant