diff --git a/libcxx/include/span b/libcxx/include/span index 3d4f9e4ba7831..1911badd88cb1 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -310,30 +310,32 @@ public: } template - _LIBCPP_HIDE_FROM_ABI constexpr span first() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span first() const noexcept { static_assert(_Count <= _Extent, "span::first(): Count out of range"); return span{data(), _Count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr span last() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span last() const noexcept { static_assert(_Count <= _Extent, "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span first(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span last(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr auto - subspan() const noexcept -> span { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto subspan() const noexcept + -> span { static_assert(_Offset <= _Extent, "span::subspan(): Offset out of range"); static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "span::subspan(): 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 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -352,52 +354,58 @@ 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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span::operator[](index): index out of range"); return __data_[__idx]; } # 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::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::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 __as_bytes() const noexcept { return span{reinterpret_cast(data()), size_bytes()}; @@ -478,36 +486,38 @@ public: : __data_{__other.data()}, __size_{__other.size()} {} template - _LIBCPP_HIDE_FROM_ABI constexpr span first() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span first() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span::first(): Count out of range"); return span{data(), _Count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr span last() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span last() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span first(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span last(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr span subspan() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span subspan() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Offset <= size(), "span::subspan(): Offset out of range"); _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset, "span::subspan(): Offset + Count out of range"); return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } - constexpr span _LIBCPP_HIDE_FROM_ABI + [[nodiscard]] constexpr span _LIBCPP_HIDE_FROM_ABI subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -517,52 +527,58 @@ 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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span::operator[](index): index out of range"); return __data_[__idx]; } # 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::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::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 __as_bytes() const noexcept { return {reinterpret_cast(data()), size_bytes()}; @@ -585,13 +601,13 @@ inline constexpr bool ranges::enable_view> = true; // as_bytes & as_writable_bytes template -_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 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..666680597f147 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "test_macros.h" + +void test() { + { // Test with a static extent + std::span sp; + + sp.first<0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.last<0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.first(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.last(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.subspan<0, 0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.subspan(0, 0); // 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}} + sp[0]; // 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::span sp; + + sp.first<0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.last<0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.first(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.last(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.subspan<0, 0>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + sp.subspan(0, 0); // 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}} + sp[0]; // 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); + } +}