diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -198,6 +198,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_ranges`` *unimplemented* ------------------------------------------------- ----------------- + ``__cpp_lib_span`` ``202002L`` + ------------------------------------------------- ----------------- ``__cpp_lib_three_way_comparison`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_to_array`` ``201907L`` 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 @@ -279,7 +295,9 @@ { 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()"); - return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; + + using _ReturnType = span; + return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } @@ -337,10 +355,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; @@ -418,7 +436,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 @@ -426,7 +444,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 @@ -449,7 +467,7 @@ { _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()"); - 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 @@ -98,6 +98,7 @@ __cpp_lib_shared_ptr_arrays 201611L __cpp_lib_shared_ptr_weak_type 201606L __cpp_lib_shared_timed_mutex 201402L +__cpp_lib_span 202002L __cpp_lib_string_udls 201304L __cpp_lib_string_view 201606L __cpp_lib_three_way_comparison 201711L @@ -234,8 +235,9 @@ # endif # 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 +# define __cpp_lib_to_array 201907L #endif #endif // _LIBCPP_VERSIONH 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; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_span 202002L [C++2a] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + +#elif TEST_STD_VER > 17 + +# ifndef __cpp_lib_span +# error "__cpp_lib_span should be defined in c++2a" +# endif +# if __cpp_lib_span != 202002L +# error "__cpp_lib_span should have the value 202002L in c++2a" +# endif + +#endif // TEST_STD_VER > 17 + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -85,6 +85,7 @@ __cpp_lib_shared_ptr_arrays 201611L [C++17] __cpp_lib_shared_ptr_weak_type 201606L [C++17] __cpp_lib_shared_timed_mutex 201402L [C++14] + __cpp_lib_span 202002L [C++2a] __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] __cpp_lib_three_way_comparison 201711L [C++2a] @@ -391,6 +392,10 @@ # error "__cpp_lib_shared_timed_mutex should not be defined before c++14" # endif +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + # ifdef __cpp_lib_string_udls # error "__cpp_lib_string_udls should not be defined before c++14" # endif @@ -784,6 +789,10 @@ # endif # endif +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++14" # endif @@ -1381,6 +1390,10 @@ # endif # endif +# ifdef __cpp_lib_span +# error "__cpp_lib_span should not be defined before c++2a" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++17" # endif @@ -2116,6 +2129,13 @@ # endif # endif +# ifndef __cpp_lib_span +# error "__cpp_lib_span should be defined in c++2a" +# endif +# if __cpp_lib_span != 202002L +# error "__cpp_lib_span should have the value 202002L in c++2a" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++2a" # endif diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -591,6 +591,12 @@ }, "headers": ["array"], }, + {"name": "__cpp_lib_span", + "values": { + "c++2a": int(202002), + }, + "headers": ["span"], + }, ]], key=lambda tc: tc["name"]) def get_std_dialects():