diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -94,8 +94,6 @@ # define _LIBCPP_ABI_OPTIMIZED_FUNCTION // All the regex constants must be distinct and nonzero. # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO -// Use raw pointers, not wrapped ones, for std::span's iterator type. -# define _LIBCPP_ABI_SPAN_POINTER_ITERATORS // Re-worked external template instantiations for std::string with a focus on // performance and fast-path inlining. # define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -197,10 +197,6 @@ is_convertible_v>(*)[], _ElementType(*)[]>; #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) -#if defined(_LIBCPP_ENABLE_DEBUG_MODE) || defined(_LIBCPP_ABI_SPAN_POINTER_ITERATORS) -# define _LIBCPP_SPAN_USE_POINTER_ITERATOR -#endif - template class _LIBCPP_TEMPLATE_VIS span { public: @@ -213,20 +209,26 @@ using const_pointer = const _Tp *; using reference = _Tp &; using const_reference = const _Tp &; -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - using iterator = pointer; -#else using iterator = __wrap_iter; -#endif using reverse_iterator = _VSTD::reverse_iterator; static constexpr size_type extent = _Extent; // [span.cons], span constructors, copy, assignment, and destructor template = nullptr> - _LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr} {} + _LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr} { + std::__debug_db_insert_c(this); + } - constexpr span (const span&) noexcept = default; +#ifndef _LIBCPP_ENABLE_DEBUG_MODE + constexpr span(const span&) noexcept = default; +#else + constexpr span(const span& __other) noexcept + : __data(__other.__data) + { + std::__debug_db_insert_c(this); + } +#endif constexpr span& operator=(const span&) noexcept = default; template = nullptr> _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_It __first, _End __last) : __data{_VSTD::to_address(__first)} { + std::__debug_db_insert_c(this); (void)__last; _LIBCPP_ASSERT((__last - __first >= 0), "invalid range in span's constructor (iterator, sentinel)"); _LIBCPP_ASSERT(__last - __first == _Extent, "invalid range in span's constructor (iterator, sentinel): last - first != extent"); } - _LIBCPP_INLINE_VISIBILITY constexpr span(type_identity_t (&__arr)[_Extent]) noexcept : __data{__arr} {} + _LIBCPP_INLINE_VISIBILITY constexpr span(type_identity_t (&__arr)[_Extent]) noexcept : __data{__arr} { + std::__debug_db_insert_c(this); + } template , nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} + constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} { + std::__debug_db_insert_c(this); + } template , nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} + constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} { + std::__debug_db_insert_c(this); + } #if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) template @@ -271,18 +281,21 @@ _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_Container& __c) : __data{std::data(__c)} { _LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)"); + std::__debug_db_insert_c(this); } template requires __span_compatible_range _LIBCPP_INLINE_VISIBILITY constexpr explicit span(const _Container& __c) : __data{std::data(__c)} { _LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)"); + std::__debug_db_insert_c(this); } #else template <__span_compatible_range _Range> _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_Range&& __r) : __data{ranges::data(__r)} { _LIBCPP_ASSERT(ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)"); + std::__debug_db_insert_c(this); } #endif @@ -292,7 +305,9 @@ enable_if_t< is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr) - : __data{__other.data()} {} + : __data{__other.data()} { + std::__debug_db_insert_c(this); + } template _LIBCPP_INLINE_VISIBILITY @@ -300,16 +315,22 @@ enable_if_t< is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr) noexcept - : __data{__other.data()} { _LIBCPP_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)"); } - + : __data{__other.data()} { + std::__debug_db_insert_c(this); + _LIBCPP_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)"); + } -// ~span() noexcept = default; +#ifdef _LIBCPP_ENABLE_DEBUG_MODE + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 ~span() noexcept { + std::__debug_db_erase_c(this); + } +#endif template _LIBCPP_INLINE_VISIBILITY constexpr span first() const noexcept { - static_assert(_Count <= _Extent, "Count out of range in span::first()"); + static_assert(_Count <= _Extent, "span::first(): Count out of range"); return span{data(), _Count}; } @@ -317,21 +338,21 @@ _LIBCPP_INLINE_VISIBILITY constexpr span last() const noexcept { - static_assert(_Count <= _Extent, "Count out of range in span::last()"); + static_assert(_Count <= _Extent, "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY constexpr span first(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "Count out of range in span::first(count)"); + _LIBCPP_ASSERT(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } _LIBCPP_INLINE_VISIBILITY constexpr span last(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "Count out of range in span::last(count)"); + _LIBCPP_ASSERT(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } @@ -340,8 +361,8 @@ constexpr auto subspan() const noexcept -> span { - static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()"); - static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "Offset + count out of range in span::subspan()"); + 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"); using _ReturnType = span; return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; @@ -352,11 +373,11 @@ constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { - _LIBCPP_ASSERT(__offset <= size(), "Offset out of range in span::subspan(offset, count)"); - _LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "Count out of range in span::subspan(offset, count)"); + _LIBCPP_ASSERT(__offset <= size(), "span::subspan(offset, count): offset out of range"); + _LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "span::subspan(offset, count): count out of range"); if (__count == dynamic_extent) return {data() + __offset, size() - __offset}; - _LIBCPP_ASSERT(__count <= size() - __offset, "Offset + count out of range in span::subspan(offset, count)"); + _LIBCPP_ASSERT(__count <= size() - __offset, "span::subspan(offset, count): offset + count out of range"); return {data() + __offset, __count}; } @@ -366,7 +387,7 @@ _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept { - _LIBCPP_ASSERT(__idx < size(), "span[] index out of bounds"); + _LIBCPP_ASSERT(__idx < size(), "span::operator[](index): index out of range"); return __data[__idx]; } @@ -386,18 +407,10 @@ // [span.iter], span iterator support _LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept { -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - return iterator(data()); -#else return iterator(this, data()); -#endif } _LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept { -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - return iterator(data() + size()); -#else return iterator(this, data() + size()); -#endif } _LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } _LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } @@ -408,6 +421,30 @@ _LIBCPP_INLINE_VISIBILITY span __as_writable_bytes() const noexcept { return span{reinterpret_cast(data()), size_bytes()}; } +#ifdef _LIBCPP_ENABLE_DEBUG_MODE + + using __debug_iterator = iterator; + + bool __dereferenceable(const iterator* __i) const { + return __data <= __i->base() && __i->base() < __data + extent; + } + + bool __decrementable(const iterator* __i) const { + return __data < __i->base() && __i->base() <= __data + extent; + } + + bool __addable(const iterator* __i, ptrdiff_t __n) const { + const_pointer __p = __i->base() + __n; + return __data <= __p && __p <= __data + extent; + } + + bool __subscriptable(const iterator* __i, ptrdiff_t __n) const { + const_pointer __p = __i->base() + __n; + return __data <= __p && __p < __data + extent; + } + +#endif // _LIBCPP_ENABLE_DEBUG_MODE + private: pointer __data; @@ -428,19 +465,24 @@ using const_pointer = const _Tp *; using reference = _Tp &; using const_reference = const _Tp &; -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - using iterator = pointer; -#else using iterator = __wrap_iter; -#endif using reverse_iterator = _VSTD::reverse_iterator; static constexpr size_type extent = dynamic_extent; // [span.cons], span constructors, copy, assignment, and destructor - _LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr}, __size{0} {} + _LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr}, __size{0} { + std::__debug_db_insert_c(this); + } + +#ifndef _LIBCPP_ENABLE_DEBUG_MODE + constexpr span(const span&) noexcept = default; +#else + constexpr span(const span& __other) noexcept : __data(__other.__data), __size(__other.__size) { + std::__debug_db_insert_c(this); + } - constexpr span (const span&) noexcept = default; +#endif constexpr span& operator=(const span&) noexcept = default; template = nullptr> _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, size_type __count) - : __data{_VSTD::to_address(__first)}, __size{__count} {} + : __data{_VSTD::to_address(__first)}, __size{__count} { + std::__debug_db_insert_c(this); + } template < class _It, class _End, @@ -458,35 +502,49 @@ nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, _End __last) - : __data(_VSTD::to_address(__first)), __size(__last - __first) {} + : __data(_VSTD::to_address(__first)), __size(__last - __first) { + std::__debug_db_insert_c(this); + } template _LIBCPP_INLINE_VISIBILITY - constexpr span(type_identity_t (&__arr)[_Sz]) noexcept : __data{__arr}, __size{_Sz} {} + constexpr span(type_identity_t (&__arr)[_Sz]) noexcept : __data{__arr}, __size{_Sz} { + std::__debug_db_insert_c(this); + } template , nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} + constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} { + std::__debug_db_insert_c(this); + } template , nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} + constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} { + std::__debug_db_insert_c(this); + } #if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) template requires __span_compatible_range<_Container, element_type> _LIBCPP_INLINE_VISIBILITY - constexpr span(_Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {} + constexpr span(_Container& __c) : __data(std::data(__c)), __size{std::size(__c)} { + std::__debug_db_insert_c(this); + } template requires __span_compatible_range _LIBCPP_INLINE_VISIBILITY - constexpr span(const _Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {} + constexpr span(const _Container& __c) : __data(std::data(__c)), __size{std::size(__c)} { + std::__debug_db_insert_c(this); + } #else template <__span_compatible_range _Range> _LIBCPP_INLINE_VISIBILITY - constexpr span(_Range&& __r) : __data(ranges::data(__r)), __size{ranges::size(__r)} {} + constexpr span(_Range&& __r) : __data(ranges::data(__r)), __size{ranges::size(__r)} { + std::__debug_db_insert_c(this); + } #endif template @@ -495,15 +553,21 @@ enable_if_t< is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr) noexcept - : __data{__other.data()}, __size{__other.size()} {} + : __data{__other.data()}, __size{__other.size()} { + std::__debug_db_insert_c(this); + } -// ~span() noexcept = default; +#ifdef _LIBCPP_ENABLE_DEBUG_MODE + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 ~span() noexcept { + std::__debug_db_erase_c(this); + } +#endif template _LIBCPP_INLINE_VISIBILITY constexpr span first() const noexcept { - _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::first()"); + _LIBCPP_ASSERT(_Count <= size(), "span::first(): Count out of range"); return span{data(), _Count}; } @@ -511,21 +575,21 @@ _LIBCPP_INLINE_VISIBILITY constexpr span last() const noexcept { - _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::last()"); + _LIBCPP_ASSERT(_Count <= size(), "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY constexpr span first(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "Count out of range in span::first(count)"); + _LIBCPP_ASSERT(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } _LIBCPP_INLINE_VISIBILITY constexpr span last (size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "Count out of range in span::last(count)"); + _LIBCPP_ASSERT(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } @@ -533,8 +597,8 @@ _LIBCPP_INLINE_VISIBILITY constexpr span subspan() const noexcept { - _LIBCPP_ASSERT(_Offset <= size(), "Offset out of range in span::subspan()"); - _LIBCPP_ASSERT(_Count == dynamic_extent || _Count <= size() - _Offset, "Offset + count out of range in span::subspan()"); + _LIBCPP_ASSERT(_Offset <= size(), "span::subspan(): Offset out of range"); + _LIBCPP_ASSERT(_Count == dynamic_extent || _Count <= size() - _Offset, "span::subspan(): Offset + Count out of range"); return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } @@ -542,11 +606,11 @@ _LIBCPP_INLINE_VISIBILITY subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { - _LIBCPP_ASSERT(__offset <= size(), "Offset out of range in span::subspan(offset, count)"); - _LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "count out of range in span::subspan(offset, count)"); + _LIBCPP_ASSERT(__offset <= size(), "span::subspan(offset, count): offset out of range"); + _LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "span::subspan(offset, count): count out of range"); if (__count == dynamic_extent) return {data() + __offset, size() - __offset}; - _LIBCPP_ASSERT(__count <= size() - __offset, "Offset + count out of range in span::subspan(offset, count)"); + _LIBCPP_ASSERT(__count <= size() - __offset, "span::subspan(offset, count): offset + count out of range"); return {data() + __offset, __count}; } @@ -556,19 +620,19 @@ _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept { - _LIBCPP_ASSERT(__idx < size(), "span[] index out of bounds"); + _LIBCPP_ASSERT(__idx < size(), "span::operator[](index): index out of range"); return __data[__idx]; } _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept { - _LIBCPP_ASSERT(!empty(), "span[].front() on empty span"); + _LIBCPP_ASSERT(!empty(), "span::front() on empty span"); return __data[0]; } _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept { - _LIBCPP_ASSERT(!empty(), "span[].back() on empty span"); + _LIBCPP_ASSERT(!empty(), "span::back() on empty span"); return __data[size()-1]; } @@ -577,18 +641,10 @@ // [span.iter], span iterator support _LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept { -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - return iterator(data()); -#else return iterator(this, data()); -#endif } _LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept { -#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR - return iterator(data() + size()); -#else return iterator(this, data() + size()); -#endif } _LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } _LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } @@ -599,6 +655,30 @@ _LIBCPP_INLINE_VISIBILITY span __as_writable_bytes() const noexcept { return {reinterpret_cast(data()), size_bytes()}; } +#ifdef _LIBCPP_ENABLE_DEBUG_MODE + + using __debug_iterator = iterator; + + bool __dereferenceable(const iterator* __i) const { + return __data <= __i->base() && __i->base() < __data + __size; + } + + bool __decrementable(const iterator* __i) const { + return __data < __i->base() && __i->base() <= __data + __size; + } + + bool __addable(const iterator* __i, ptrdiff_t __n) const { + const_pointer __p = __i->base() + __n; + return __data <= __p && __p <= __data + __size; + } + + bool __subscriptable(const iterator* __i, ptrdiff_t __n) const { + const_pointer __p = __i->base() + __n; + return __data <= __p && __p < __data + __size; + } + +#endif // _LIBCPP_ENABLE_DEBUG_MODE + private: pointer __data; size_type __size; diff --git a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Make sure that std::span's iterators check for OOB accesses when the debug mode is enabled. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: !libcpp-has-debug-mode, c++03 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + auto check = [](auto const& span) { + { + auto it = span.begin(); + TEST_LIBCPP_ASSERT_FAILURE(it + 4, "Attempted to add/subtract an iterator outside its valid range"); + } + { + auto it = span.begin(); + TEST_LIBCPP_ASSERT_FAILURE(it - 4, "Attempted to add/subtract an iterator outside its valid range"); + } + { + auto it = span.begin(); + TEST_LIBCPP_ASSERT_FAILURE(--it, "Attempted to decrement a non-decrementable iterator"); + } + { + auto it = span.begin(); + TEST_LIBCPP_ASSERT_FAILURE(it--, "Attempted to decrement a non-decrementable iterator"); + } + { + auto it = span.end(); + TEST_LIBCPP_ASSERT_FAILURE(++it, "Attempted to increment a non-incrementable iterator"); + } + { + auto it = span.end(); + TEST_LIBCPP_ASSERT_FAILURE(it++, "Attempted to increment a non-incrementable iterator"); + } + { + auto it = span.end(); + TEST_LIBCPP_ASSERT_FAILURE(*it, "Attempted to dereference a non-dereferenceable iterator"); + } + }; + { + int array[] = {0, 1, 2}; + std::span const span(array, 3); + check(span); + } + { + int array[] = {0, 1, 2}; + std::span const span(array, 3); + check(span); + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr reference back() const noexcept; + +// Make sure that accessing a span out-of-bounds triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 0); + TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span::back() on empty span"); + } + + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 0); + TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span::back() on empty span"); + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr reference front() const noexcept; + +// Make sure that accessing a span out-of-bounds triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 0); + TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span::front() on empty span"); + } + + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 0); + TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span::front() on empty span"); + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr reference operator[](size_type idx) const; + +// Make sure that accessing a span out-of-bounds triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(array, 3); + TEST_LIBCPP_ASSERT_FAILURE(s[3], "span::operator[](index): index out of range"); + } + + { + int array[] = {0, 1, 2}; + std::span const s(array, 3); + TEST_LIBCPP_ASSERT_FAILURE(s[3], "span::operator[](index): index out of range"); + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr span first(size_type count) const; + +// Make sure that creating a sub-span with an incorrect number of elements triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.first(4), "span::first(count): count out of range"); + TEST_LIBCPP_ASSERT_FAILURE(s.first<4>(), "span::first(): Count out of range"); + } + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.first(4), "span::first(count): count out of range"); + // s.first<4>() caught at compile-time (tested elsewhere) + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr span last(size_type count) const; + +// Make sure that creating a sub-span with an incorrect number of elements triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.last(4), "span::last(count): count out of range"); + TEST_LIBCPP_ASSERT_FAILURE(s.last<4>(), "span::last(): Count out of range"); + } + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.last(4), "span::last(count): count out of range"); + // s.last<4>() caught at compile-time (tested elsewhere) + } + + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// constexpr span subspan( +// size_type offset, size_type count = dynamic_extent) const; +// +// Requires: (0 <= Offset && Offset <= size()) +// && (Count == dynamic_extent || Count >= 0 && Offset + Count <= size()) + +// Make sure that creating a sub-span with an incorrect number of elements triggers an assertion. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(4), "span::subspan(offset, count): offset out of range"); + TEST_LIBCPP_ASSERT_FAILURE(s.subspan<4>(), "span::subspan(): Offset out of range"); + + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(0, 4), "span::subspan(offset, count): count out of range"); + TEST_LIBCPP_ASSERT_FAILURE((s.subspan<0, 4>()), "span::subspan(): Offset + Count out of range"); + + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(1, 3), "span::subspan(offset, count): offset + count out of range"); + TEST_LIBCPP_ASSERT_FAILURE((s.subspan<1, 3>()), "span::subspan(): Offset + Count out of range"); + } + { + int array[] = {0, 1, 2}; + std::span const s(&array[0], 3); + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(4), "span::subspan(offset, count): offset out of range"); + // s.subspan<4>() caught at compile-time (tested elsewhere) + + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(0, 4), "span::subspan(offset, count): count out of range"); + // s.subspan<0, 4>() caught at compile-time (tested elsewhere) + + TEST_LIBCPP_ASSERT_FAILURE(s.subspan(1, 3), "span::subspan(offset, count): offset + count out of range"); + // s.subspan<1, 3>() caught at compile-time (tested elsewhere) + } + + return 0; +} diff --git a/libcxx/test/std/containers/views/views.span/span.cons/span.dtor.compile.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/span.dtor.compile.pass.cpp --- a/libcxx/test/std/containers/views/views.span/span.cons/span.dtor.compile.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/span.dtor.compile.pass.cpp @@ -17,7 +17,11 @@ template constexpr void testDestructor() { static_assert(std::is_nothrow_destructible_v); +#ifdef _LIBCPP_ENABLE_DEBUG_MODE + static_assert(!std::is_trivially_destructible_v); +#else static_assert(std::is_trivially_destructible_v); +#endif } void test() { diff --git a/libcxx/test/std/containers/views/views.span/span.sub/first.fail.cpp b/libcxx/test/std/containers/views/views.span/span.sub/first.verify.cpp rename from libcxx/test/std/containers/views/views.span/span.sub/first.fail.cpp rename to libcxx/test/std/containers/views/views.span/span.sub/first.verify.cpp --- a/libcxx/test/std/containers/views/views.span/span.sub/first.fail.cpp +++ b/libcxx/test/std/containers/views/views.span/span.sub/first.verify.cpp @@ -12,30 +12,18 @@ // template // constexpr span first() const; // -// constexpr span first(size_type count) const; -// // Requires: Count <= size(). #include - #include -#include "test_macros.h" - -constexpr int carr[] = {1, 2, 3, 4}; - -int main(int, char**) { - std::span sp(carr); +void f() { + int array[] = {1, 2, 3, 4}; + std::span sp(array); // Count too large - { - [[maybe_unused]] auto s1 = sp.first<5>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Count out of range in span::first()"}} - } + [[maybe_unused]] auto s1 = sp.first<5>(); // expected-error@span:* {{span::first(): Count out of range}} // Count numeric_limits - { - [[maybe_unused]] auto s1 = sp.first(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Count out of range in span::first()"}} - } - - return 0; + [[maybe_unused]] auto s2 = sp.first(); // expected-error@span:* {{span::first(): Count out of range}} } diff --git a/libcxx/test/std/containers/views/views.span/span.sub/last.fail.cpp b/libcxx/test/std/containers/views/views.span/span.sub/last.verify.cpp rename from libcxx/test/std/containers/views/views.span/span.sub/last.fail.cpp rename to libcxx/test/std/containers/views/views.span/span.sub/last.verify.cpp --- a/libcxx/test/std/containers/views/views.span/span.sub/last.fail.cpp +++ b/libcxx/test/std/containers/views/views.span/span.sub/last.verify.cpp @@ -12,30 +12,18 @@ // template // constexpr span last() const; // -// constexpr span last(size_type count) const; -// // Requires: Count <= size(). #include - #include -#include "test_macros.h" - -constexpr int carr[] = {1, 2, 3, 4}; - -int main(int, char**) { - std::span sp(carr); +void f() { + int array[] = {1, 2, 3, 4}; + std::span sp(array); // Count too large - { - [[maybe_unused]] auto s1 = sp.last<5>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Count out of range in span::last()"}} - } + [[maybe_unused]] auto s1 = sp.last<5>(); // expected-error@span:* {{span::last(): Count out of range}} // Count numeric_limits - { - [[maybe_unused]] auto s1 = sp.last(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Count out of range in span::last()"}} - } - - return 0; + [[maybe_unused]] auto s2 = sp.last(); // expected-error@span:* {{span::last(): Count out of range}} } diff --git a/libcxx/test/std/containers/views/views.span/span.sub/subspan.fail.cpp b/libcxx/test/std/containers/views/views.span/span.sub/subspan.fail.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/views.span/span.sub/subspan.fail.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// - -// template -// constexpr span subspan() const; -// -// constexpr span subspan( -// size_type offset, size_type count = dynamic_extent) const; -// -// Requires: offset <= size() && -// (count == dynamic_extent || count <= size() - offset) - -#include - -#include - -#include "test_macros.h" - -constexpr int carr[] = {1, 2, 3, 4}; - -int main(int, char**) { - std::span sp(carr); - - // Offset too large templatized - { - [[maybe_unused]] auto s1 = sp.subspan<5>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Offset out of range in span::subspan()"}} - } - - // Count too large templatized - { - [[maybe_unused]] auto s1 = sp.subspan<0, 5>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Offset + count out of range in span::subspan()"}} - } - - // Offset + Count too large templatized - { - [[maybe_unused]] auto s1 = sp.subspan<2, 3>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Offset + count out of range in span::subspan()"}} - } - - // Offset + Count overflow templatized - { - [[maybe_unused]] auto s1 = sp.subspan<3, std::size_t(-2)>(); // expected-error-re@span:* {{static_assert failed{{( due to requirement '.*')?}} "Offset + count out of range in span::subspan()"}}, expected-error-re@span:* {{array is too large{{(.* elements)}}}} - } - - return 0; -} diff --git a/libcxx/test/std/containers/views/views.span/span.sub/subspan.verify.cpp b/libcxx/test/std/containers/views/views.span/span.sub/subspan.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.sub/subspan.verify.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// This test also generates spurious warnings when instantiating std::span +// with a very large extent (like size_t(-2)) -- silence those. +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=warning + +// + +// template +// constexpr span subspan() const; +// +// Requires: offset <= size() && +// (count == dynamic_extent || count <= size() - offset) + +#include +#include + +void f() { + int array[] = {1, 2, 3, 4}; + std::span sp(array); + + // Offset too large templatized + [[maybe_unused]] auto s1 = sp.subspan<5>(); // expected-error@span:* {{span::subspan(): Offset out of range"}} + + // Count too large templatized + [[maybe_unused]] auto s2 = sp.subspan<0, 5>(); // expected-error@span:* {{span::subspan(): Offset + Count out of range"}} + + // Offset + Count too large templatized + [[maybe_unused]] auto s3 = sp.subspan<2, 3>(); // expected-error@span:* {{span::subspan(): Offset + Count out of range"}} + + // Offset + Count overflow templatized + [[maybe_unused]] auto s4 = sp.subspan<3, std::size_t(-2)>(); // expected-error@span:* {{span::subspan(): Offset + Count out of range"}}, expected-error-re@span:* {{array is too large{{(.* elements)}}}} +} diff --git a/libcxx/test/std/containers/views/views.span/trivially_copyable.compile.pass.cpp b/libcxx/test/std/containers/views/views.span/trivially_copyable.compile.pass.cpp --- a/libcxx/test/std/containers/views/views.span/trivially_copyable.compile.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/trivially_copyable.compile.pass.cpp @@ -14,5 +14,10 @@ #include #include +#ifdef _LIBCPP_ENABLE_DEBUG_MODE +static_assert(!std::is_trivially_copyable_v>); +static_assert(!std::is_trivially_copyable_v>); +#else static_assert(std::is_trivially_copyable_v>); static_assert(std::is_trivially_copyable_v>); +#endif