commit f7686704e7edb8b38b4d4726726b97b78ae2da8d Author: Jonathan Wakely Date: Mon Sep 30 11:48:14 2019 +0100 Implement LWG 3255 for std::span constructors Also fix the constraints on span(Container&) and span(const Container&) constructors so that they aren't used for const spans or const arrays. * include/std/span (span(element_type(&)[N])) (span(array&), span(const array&)): Deduce array element type to allow safe const conversions (LWG 3255). [!_GLIBCXX_P1394] (span(Container&), span(const Container&)): Use remove_cv_t on arguments to __is_std_span and __is_std_array. * testsuite/23_containers/span/lwg3255.cc: New test. diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 1a0d61c1947..fcec22a6c57 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -125,6 +125,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3255. span's array constructor is too strict + template> + using __is_compatible_array = __is_compatible<_Tp>; + public: // member types using value_type = remove_cv_t<_Type>; @@ -149,9 +156,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // constructors - template - && (_Extent == dynamic_extent || _Extent == 0)>* = nullptr> + template* = nullptr> constexpr span() noexcept : _M_extent(0), _M_ptr(nullptr) { } @@ -159,28 +165,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr span(const span&) noexcept = default; - template* - = nullptr> + template>> constexpr - span(element_type (&__arr)[_ArrayExtent]) noexcept + span(_Tp (&__arr)[_ArrayExtent]) noexcept : span(static_cast(__arr), _ArrayExtent) { } - template* - = nullptr> + template>> constexpr - span(array& __arr) noexcept - : span(__arr.data(), _ArrayExtent) + span(array<_Tp, _ArrayExtent>& __arr) noexcept + : span(static_cast(__arr.data()), _ArrayExtent) { } - template* - = nullptr> + template>> constexpr - span(const array& __arr) noexcept - : span(__arr.data(), _ArrayExtent) + span(const array<_Tp, _ArrayExtent>& __arr) noexcept + : span(static_cast(__arr.data()), _ArrayExtent) { } // NOTE: when the time comes, and P1394 - @@ -271,8 +274,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: template, - __not_<__detail::__is_std_span<_Container>>, - __not_<__detail::__is_std_array<_Container>>, + __not_<__detail::__is_std_span>>, + __not_<__detail::__is_std_array>>, __not_>, __is_compatible_container<_Container>>> constexpr @@ -283,8 +286,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template, - __not_<__detail::__is_std_span<_Container>>, - __not_<__detail::__is_std_array<_Container>>, + __not_<__detail::__is_std_span>>, + __not_<__detail::__is_std_array>>, __not_>, __is_compatible_container>> constexpr diff --git a/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc new file mode 100644 index 00000000000..638c88101f9 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc @@ -0,0 +1,69 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +using std::span; +using std::dynamic_extent; +using std::array; +using std::is_constructible_v; + +// LWG 3255 span's array constructor is too strict + +// FIXME: remove '!' from next line when P0388R4 is implemented: +static_assert( ! is_constructible_v, array> ); +static_assert( is_constructible_v, array> ); + +static_assert( is_constructible_v, int(&)[1]> ); +static_assert( is_constructible_v, int(&)[1]> ); +static_assert( is_constructible_v, const int(&)[1]> ); + +static_assert( is_constructible_v, array&> ); +static_assert( is_constructible_v, array&> ); +static_assert( is_constructible_v, array&> ); + +static_assert( is_constructible_v, const array&> ); +static_assert( is_constructible_v, const array&> ); +static_assert( is_constructible_v, const array&> ); + +static_assert( !is_constructible_v, int(&)[2]> ); +static_assert( !is_constructible_v, int(&)[2]> ); +static_assert( !is_constructible_v, const int(&)[2]> ); + +static_assert( !is_constructible_v, array&> ); +static_assert( !is_constructible_v, array&> ); +static_assert( !is_constructible_v, array&> ); + +static_assert( !is_constructible_v, const array&> ); +static_assert( !is_constructible_v, const array&> ); +static_assert( !is_constructible_v, const array&> ); + +static_assert( is_constructible_v, int(&)[2]> ); +static_assert( is_constructible_v, int(&)[2]> ); +static_assert( is_constructible_v, const int(&)[2]> ); + +static_assert( is_constructible_v, array&> ); +static_assert( is_constructible_v, array&> ); +static_assert( is_constructible_v, array&> ); + +static_assert( is_constructible_v, const array&> ); +static_assert( is_constructible_v, const array&> ); +static_assert( is_constructible_v, const array&> );