diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -53,8 +53,8 @@ // [span.cons], span constructors, copy, assignment, and destructor constexpr span() noexcept; - constexpr span(pointer ptr, size_type count); - constexpr span(pointer firstElem, pointer lastElem); + constexpr explicit(Extent != dynamic_extent) span(pointer ptr, size_type count); + constexpr explicit(Extent != dynamic_extent) span(pointer firstElem, pointer lastElem); template constexpr span(element_type (&arr)[N]) noexcept; template @@ -62,12 +62,12 @@ template constexpr span(const array& arr) noexcept; template - constexpr span(Container& cont); + constexpr explicit(Extent != dynamic_extent) span(Container& cont); template - constexpr span(const Container& cont); + constexpr explicit(Extent != dynamic_extent) span(const Container& cont); constexpr span(const span& other) noexcept = default; template - constexpr span(const span& s) noexcept; + constexpr explicit(Extent != dynamic_extent) span(const span& s) noexcept; ~span() noexcept = default; constexpr span& operator=(const span& other) noexcept = default; @@ -214,15 +214,31 @@ constexpr span (const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __ptr, size_type __count) : __data{__ptr} + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __ptr, size_type __count) : __data{__ptr} { (void)__count; _LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (ptr, len)"); } - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __f, pointer __l) : __data{__f} + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __f, pointer __l) : __data{__f} { (void)__l; _LIBCPP_ASSERT(_Extent == distance(__f, __l), "size mismatch in span's constructor (ptr, ptr)"); } _LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Extent]) noexcept : __data{__arr} {} _LIBCPP_INLINE_VISIBILITY constexpr span( array& __arr) noexcept : __data{__arr.data()} {} _LIBCPP_INLINE_VISIBILITY constexpr span(const array& __arr) noexcept : __data{__arr.data()} {} + template + _LIBCPP_INLINE_VISIBILITY + constexpr explicit span( _Container& __c, + enable_if_t<__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr) + : __data{_VSTD::data(__c)} { + _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); + } + + template + _LIBCPP_INLINE_VISIBILITY + constexpr explicit span(const _Container& __c, + enable_if_t<__is_span_compatible_container::value, nullptr_t> = nullptr) + : __data{_VSTD::data(__c)} { + _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); + } + template _LIBCPP_INLINE_VISIBILITY constexpr span(const span<_OtherElementType, _Extent>& __other, @@ -233,7 +249,7 @@ template _LIBCPP_INLINE_VISIBILITY - constexpr span(const span<_OtherElementType, dynamic_extent>& __other, + constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other, enable_if_t< is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr) noexcept @@ -247,7 +263,7 @@ constexpr span first() const noexcept { static_assert(_Count <= _Extent, "Count out of range in span::first()"); - return {data(), _Count}; + return span{data(), _Count}; } template @@ -255,7 +271,7 @@ constexpr span last() const noexcept { static_assert(_Count <= _Extent, "Count out of range in span::last()"); - return {data() + size() - _Count, _Count}; + return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY @@ -278,7 +294,8 @@ -> span { static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()"); - return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; + using _ReturnType = span; + return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } @@ -336,10 +353,10 @@ } _LIBCPP_INLINE_VISIBILITY span __as_bytes() const noexcept - { return {reinterpret_cast(data()), size_bytes()}; } + { return span{reinterpret_cast(data()), size_bytes()}; } _LIBCPP_INLINE_VISIBILITY span __as_writable_bytes() const noexcept - { return {reinterpret_cast(data()), size_bytes()}; } + { return span{reinterpret_cast(data()), size_bytes()}; } private: pointer __data; @@ -417,7 +434,7 @@ constexpr span first() const noexcept { _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::first()"); - return {data(), _Count}; + return span{data(), _Count}; } template @@ -425,7 +442,7 @@ constexpr span last() const noexcept { _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::last()"); - return {data() + size() - _Count, _Count}; + return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY @@ -448,7 +465,7 @@ { _LIBCPP_ASSERT(_Offset <= size(), "Offset out of range in span::subspan()"); _LIBCPP_ASSERT(_Count == dynamic_extent || _Offset + _Count <= size(), "Count out of range in span::subspan()"); - return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; + return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } constexpr span diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -235,6 +235,7 @@ // # define __cpp_lib_list_remove_return_type 201806L // # define __cpp_lib_ranges 201811L # define __cpp_lib_to_array 201907L +# define __cpp_lib_span 202002L // # define __cpp_lib_three_way_comparison 201711L #endif diff --git a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp @@ -185,13 +185,14 @@ // constexpr statically sized assignment { - constexpr std::span spans[] = { - {carr1, 2}, - {carr1 + 1, 2}, - {carr1 + 2, 2}, - {carr2, 2}, - {carr2 + 1, 2}, - {carr3, 2} + using spanType = std::span; + constexpr spanType spans[] = { + spanType{carr1, 2}, + spanType{carr1 + 1, 2}, + spanType{carr1 + 2, 2}, + spanType{carr2, 2}, + spanType{carr2 + 1, 2}, + spanType{carr3, 2} }; static_assert(std::size(spans) == 6, "" ); @@ -247,10 +248,11 @@ // statically sized assignment { - std::span spans[] = { - {arr, arr + 2}, - {arr + 1, arr + 3}, - {arr + 2, arr + 4} + using spanType = std::span; + spanType spans[] = { + spanType{arr, arr + 2}, + spanType{arr + 1, arr + 3}, + spanType{arr + 2, arr + 4} }; for (size_t i = 0; i < std::size(spans); ++i) @@ -279,10 +281,11 @@ } { - std::span spans[] = { - {strs, strs + 1}, - {strs + 1, strs + 2}, - {strs + 2, strs + 3} + using spanType = std::span; + spanType spans[] = { + spanType{strs, strs + 1}, + spanType{strs + 1, strs + 2}, + spanType{strs + 2, strs + 3} }; for (size_t i = 0; i < std::size(spans); ++i) diff --git a/libcxx/test/std/containers/views/span.cons/container.fail.cpp b/libcxx/test/std/containers/views/span.cons/container.fail.cpp --- a/libcxx/test/std/containers/views/span.cons/container.fail.cpp +++ b/libcxx/test/std/containers/views/span.cons/container.fail.cpp @@ -63,6 +63,10 @@ const T *data() const {return nullptr;} }; +template +std::span createImplicitSpan(container c) { + return {c}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} int main(int, char**) { @@ -106,12 +110,14 @@ std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} } -// statically sized +// explicit constructor necessary { - IsAContainer c; - std::span s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } + IsAContainer c; + const IsAContainer cc; + createImplicitSpan(c); + createImplicitSpan(cc); + } return 0; } diff --git a/libcxx/test/std/containers/views/span.cons/container.pass.cpp b/libcxx/test/std/containers/views/span.cons/container.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/container.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/container.pass.cpp @@ -84,14 +84,32 @@ return s1.data() == val.getV() && s1.size() == 1; } +template +constexpr bool testConstexprSpanStatic() +{ + constexpr IsAContainer val{}; + std::span s1{val}; + return s1.data() == val.getV() && s1.size() == 1; +} template void testRuntimeSpan() { IsAContainer val{}; const IsAContainer cVal; - std::span s1{val}; - std::span s2{cVal}; + std::span s1{val}; + std::span s2{cVal}; + assert(s1.data() == val.getV() && s1.size() == 1); + assert(s2.data() == cVal.getV() && s2.size() == 1); +} + +template +void testRuntimeSpanStatic() +{ + IsAContainer val{}; + const IsAContainer cVal; + std::span s1{val}; + std::span s2{cVal}; assert(s1.data() == val.getV() && s1.size() == 1); assert(s2.data() == cVal.getV() && s2.size() == 1); } @@ -105,12 +123,23 @@ static_assert(testConstexprSpan(), ""); static_assert(testConstexprSpan(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + checkCV(); return 0; diff --git a/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp --- a/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp +++ b/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp @@ -27,6 +27,11 @@ volatile int varr[] = {7,8,9}; const volatile int cvarr[] = {1,3,5}; +template +std::span createImplicitSpan(T* ptr, size_t len) { + return {ptr, len}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + int main(int, char**) { // We can't check that the size doesn't match - because that's a runtime property @@ -60,5 +65,10 @@ std::span< volatile int,3> s7{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} } +// explicit constructor necessary + { + createImplicitSpan(arr, 1); + } + return 0; } diff --git a/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp --- a/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp +++ b/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp @@ -27,6 +27,11 @@ volatile int varr[] = {7,8,9}; const volatile int cvarr[] = {1,3,5}; +template +std::span createImplicitSpan(T* first, T* last) { + return {first, last}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + int main(int, char**) { // We can't check that the size doesn't match - because that's a runtime property @@ -60,5 +65,10 @@ std::span< volatile int,3> s7{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} } + // explicit constructor necessary + { + createImplicitSpan(arr, arr + 1); + } + return 0; } diff --git a/libcxx/test/std/containers/views/span.cons/span.fail.cpp b/libcxx/test/std/containers/views/span.cons/span.fail.cpp --- a/libcxx/test/std/containers/views/span.cons/span.fail.cpp +++ b/libcxx/test/std/containers/views/span.cons/span.fail.cpp @@ -24,6 +24,11 @@ #include "test_macros.h" +template +std::span createImplicitSpan(std::span s) { + return {s}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + void checkCV () { // std::span< int> sp; @@ -101,5 +106,10 @@ checkCV(); + // explicit constructor necessary + { + createImplicitSpan(sp); + } + return 0; }