diff --git a/libcxx/include/span b/libcxx/include/span index 896a3cd890186..097efbd50a00f 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -267,6 +267,8 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit span(_It __first, size_type __count) : __data_{std::to_address(__first)} { (void)__count; _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Extent == __count, "size mismatch in span's constructor (iterator, len)"); + _LIBCPP_ASSERT_VALID_INPUT_RANGE(__count == 0 || std::to_address(__first) != nullptr, + "passed nullptr with non-zero length in span's constructor (iterator, len)"); } template <__span_compatible_iterator _It, __span_compatible_sentinel_for<_It> _End> @@ -441,7 +443,10 @@ public: template <__span_compatible_iterator _It> _LIBCPP_HIDE_FROM_ABI constexpr span(_It __first, size_type __count) - : __data_{std::to_address(__first)}, __size_{__count} {} + : __data_{std::to_address(__first)}, __size_{__count} { + _LIBCPP_ASSERT_VALID_INPUT_RANGE(__count == 0 || std::to_address(__first) != nullptr, + "passed nullptr with non-zero length in span's constructor (iterator, len)"); + } template <__span_compatible_iterator _It, __span_compatible_sentinel_for<_It> _End> _LIBCPP_HIDE_FROM_ABI constexpr span(_It __first, _End __last) diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp index 4461bad8ff504..c8c6e3743bd21 100644 --- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp @@ -25,13 +25,48 @@ #include "check_assertion.h" int main(int, char**) { - std::array array{0, 1, 2}; + std::array array{0, 1, 2}; - auto too_large = [&] { std::span const s(array.data(), 4); (void)s; }; - TEST_LIBCPP_ASSERT_FAILURE(too_large(), "size mismatch in span's constructor (iterator, len)"); + // Input range too large (exceeds the span extent) + { + auto f = [&] { + std::span const s(array.data(), 4); + (void)s; + }; + TEST_LIBCPP_ASSERT_FAILURE(f(), "size mismatch in span's constructor (iterator, len)"); + } - auto too_small = [&] { std::span const s(array.data(), 2); (void)s; }; - TEST_LIBCPP_ASSERT_FAILURE(too_small(), "size mismatch in span's constructor (iterator, len)"); + // Input range too small (doesn't fill the span) + { + auto f = [&] { + std::span const s(array.data(), 2); + (void)s; + }; + TEST_LIBCPP_ASSERT_FAILURE(f(), "size mismatch in span's constructor (iterator, len)"); + } - return 0; + // Input range is non-empty but starts with a null pointer + { + // static extent + { + auto f = [&] { + int* p = nullptr; + std::span const s(p, 3); + (void)s; + }; + TEST_LIBCPP_ASSERT_FAILURE(f(), "passed nullptr with non-zero length in span's constructor (iterator, len)"); + } + + // dynamic extent + { + auto f = [&] { + int* p = nullptr; + std::span const s(p, 1); + (void)s; + }; + TEST_LIBCPP_ASSERT_FAILURE(f(), "passed nullptr with non-zero length in span's constructor (iterator, len)"); + } + } + + return 0; }