From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 47137 invoked by alias); 9 Sep 2019 11:12:42 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 47120 invoked by uid 89); 9 Sep 2019 11:12:42 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.4 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=UD:B, circuit, NB, N.B X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 09 Sep 2019 11:12:39 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C7DCA369CA; Mon, 9 Sep 2019 11:12:37 +0000 (UTC) Received: from localhost (unknown [10.33.36.99]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3AFD15D6A7; Mon, 9 Sep 2019 11:12:36 +0000 (UTC) Date: Mon, 09 Sep 2019 11:12:00 -0000 From: Jonathan Wakely To: JeanHeyd Meneide Cc: gcc-patches@gcc.gnu.org, libstdc++ Subject: Re: [ PATCH ] C++20 Message-ID: <20190909111235.GV9487@redhat.com> References: <20190830194119.GS9487@redhat.com> <20190903133122.GC9487@redhat.com> <20190905112747.GM9487@redhat.com> <20190905135234.GO9487@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="uX7BrQs69PbBafpd" Content-Disposition: inline In-Reply-To: <20190905135234.GO9487@redhat.com> X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.0 (2019-05-25) X-SW-Source: 2019-09/txt/msg00492.txt.bz2 --uX7BrQs69PbBafpd Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Content-length: 1054 And some further simplifications and improvements to the constructor constraints for std::span. This patch simplifies the constraints on the constructors from arrays by removing the redundant checks that element_type and value_type are convertible to element_type. The incorrect uses of __adl_data in those constructors are removed as well (they should use std::data not std::ranges::data, and the former doesn't use ADL). The range/container constructors are now constrained to exclude all specializations of std::span, not just the current instantiation. The range constructor now also checks s subset of the contiguous_range requirements. All relevant constructor constraints now use the _Require helper in order to short circuit and avoid unnecessary instantiations after the first failed constraint. A new constructor supports initialization from different specializations of std::span, as specified in the C++20 draft. Tested x86_64-linux, committed to trunk. --uX7BrQs69PbBafpd Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" Content-length: 15703 commit cf9248752de63a49bde062eb00681ae1c6d1a546 Author: Jonathan Wakely Date: Mon Sep 9 10:56:54 2019 +0100 Improve constraints for std::span constructors This patch simplifies the constraints on the constructors from arrays by removing the redundant checks that element_type and value_type are convertible to element_type. The incorrect uses of __adl_data in those constructors are removed as well (they should use std::data not std::ranges::data, and the former doesn't use ADL). The range/container constructors are now constrained to exclude all specializations of std::span, not just the current instantiation. The range constructor now also checks s subset of the contiguous_range requirements. All relevant constructor constraints now use the _Require helper in order to short circuit and avoid unnecessary instantiations after the first failed constraint. A new constructor supports initialization from different specializations of std::span, as specified in the C++20 draft. * include/bits/range_access.h (__adl_to_address): Remove. * include/std/span (__is_base_derived_safe_convertible_v): Replace with span::__is_compatible. (__is_std_array_v): Replace with __is_std_array class template and partial specializations. (__is_std_array, __is_std_span): New class templates and partial specializations. (span::__is_compatible): New alias template for SFINAE constraints. (span::span(element_type (&)[N])): Remove redundant constraints. Do not use __adl_data to obtain a pointer. (span::span(array&)): Likewise. (span::span(const array&)): Likewise. [_GLIBCXX_P1394] (span::iter_reference_t, span::iterator_t) (span::iter_value_t, span::derived_from): New alias templates for SFINAE constraints, until the equivalents are supported in and . [_GLIBCXX_P1394] (span::__is_compatible_iterator): New alias template for SFINAE constraints. [_GLIBCXX_P1394] (span::is_compatible_range): New class template for SFINAE constraints. [_GLIBCXX_P1394] (span::span(Range&&)): Improve constraints. [_GLIBCXX_P1394] (span::span(ContiguousIterator, Sentinel)): Likewise. Use std::to_address instead of __adl_to_address. [_GLIBCXX_P1394] (span::span(ContiguousIterator, size_type)): Likewise. [!_GLIBCXX_P1394] (span::__is_compatible_container): New alias template for SFINAE constraints. [!_GLIBCXX_P1394] (span::span(Container&)) (span::span(const Container&)): Improve constraints. [!_GLIBCXX_P1394] (span::span(pointer, size_type)) (span::span(pointer, pointer)): Remove redundant cast of pointer. (span(const span&)): New constructor. diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index c5744145590..bc137d7396e 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -396,13 +396,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto __adl_empty(_Container& __cont) noexcept(noexcept(empty(__cont))) { return empty(__cont); } - -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 - template - constexpr auto - __adl_to_address(_Container& __cont) noexcept(noexcept(to_address(__cont))) - { return to_address(__cont); } -#endif // P1394 and new contiguous_iterator requirements [iterator.concept.contiguous] #endif // C++20 _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 95d778b104b..1a0d61c1947 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -53,24 +53,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline constexpr size_t dynamic_extent = static_cast(-1); + template + class span; + namespace __detail { - template - static constexpr inline bool __is_base_derived_safe_convertible_v - = is_convertible_v<_Element (*)[], _ToElement (*)[]>; - template - inline constexpr bool __is_std_array_v = false; + struct __is_std_span : false_type { }; template - inline constexpr bool - __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true; + struct __is_std_span> : true_type { }; + + template + struct __is_std_array : false_type { }; + + template + struct __is_std_array<_GLIBCXX_STD_C::array<_Tp, _Num>> : true_type { }; #ifdef _GLIBCXX_DEBUG template - inline constexpr bool - __is_std_array_v> = true; -#endif // debug/array + struct __is_std_array<__debug::array<_Tp, _Num>> : true_type { }; +#endif template class __extent_storage @@ -119,6 +122,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return dynamic_extent; } + template + using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>; + public: // member types using value_type = remove_cv_t<_Type>; @@ -154,41 +160,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const span&) noexcept = default; template()))>, - element_type>>* = nullptr> - constexpr span(element_type (&__arr)[_ArrayExtent]) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> + constexpr + span(element_type (&__arr)[_ArrayExtent]) noexcept + : span(static_cast(__arr), _ArrayExtent) { } template&>()))>, - element_type>>* = nullptr> + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> constexpr - span(array& __arr) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + span(array& __arr) noexcept + : span(__arr.data(), _ArrayExtent) { } template&>()))>, - element_type>>* = nullptr> + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> constexpr - span(const array& __arr) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + span(const array& __arr) noexcept + : span(__arr.data(), _ArrayExtent) { } // NOTE: when the time comes, and P1394 - @@ -199,18 +191,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // and keep the crappy #else block // and then cry that NB comments failed C++20... // but maybe for C++23? -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 - template, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Range&>()))>, - element_type>>* = nullptr> +#ifdef _GLIBCXX_P1394 + private: + // FIXME: use std::iter_reference_t + template + using iter_reference_t = decltype(*std::declval<_Iterator&>()); + // FIXME: use std::ranges::iterator_t + // N.B. constraint is needed to prevent a cycle when __adl_begin finds + // begin(span) which does overload resolution on span(Range&&). + template, + typename = enable_if_t::value>> + using iterator_t = decltype(std::__adl_begin(std::declval<_Rng&>())); + // FIXME: use std::iter_value_t + template + using iter_value_t = typename iterator_traits<_Iter>::value_type; + // FIXME: use std::derived_from concept + template + using derived_from + = __and_, + is_convertible>; + // FIXME: require contiguous_iterator<_Iterator> + template, + typename _Traits = iterator_traits<_Iter>, + typename _Tag = typename _Traits::iterator_category> + using __is_compatible_iterator + = __and_, + is_lvalue_reference<_Ref>, + is_same, remove_cvref_t<_Ref>>, + __is_compatible>>; + + template + using __is_compatible_range + = __is_compatible_iterator>; + + public: + template, + __not_<__detail::__is_std_span>>, + __not_<__detail::__is_std_array>>, + __not_>>, + __is_compatible_range<_Range>>, + typename = decltype(std::__adl_data(std::declval<_Range&>()))> constexpr span(_Range&& __range) noexcept(noexcept(::std::__adl_data(__range)) @@ -218,72 +241,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : span(::std::__adl_data(__range), ::std::__adl_size(__range)) { } - template - && __detail::__is_base_derived_safe_convertible_v< - remove_reference_t::reference>, - element_type>>* = nullptr> + template>, + __is_compatible_iterator<_ContiguousIterator>>> constexpr span(_ContiguousIterator __first, _Sentinel __last) - : span(::std::move(__first), static_cast(__last - __first)) - { } + : _M_extent(static_cast(__last - __first)), + _M_ptr(std::to_address(__first)) + { + if (_Extent != dynamic_extent) + __glibcxx_assert((__last - __first) == _Extent); + } - template + template>> constexpr span(_ContiguousIterator __first, index_type __count) - noexcept(noexcept(::std::__adl_to_address(__first))) - : _M_extent(__count), _M_ptr(::std::__adl_to_address(__first)) + noexcept(noexcept(std::to_address(__first))) + : _M_extent(__count), _M_ptr(std::to_address(__first)) { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } - #else - + private: template, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Container&>()))>, - element_type>>* = nullptr> + typename _DataT = decltype(std::data(std::declval<_Container&>())), + typename _SizeT = decltype(std::size(std::declval<_Container&>()))> + using __is_compatible_container + = __is_compatible>; + + public: + template, + __not_<__detail::__is_std_span<_Container>>, + __not_<__detail::__is_std_array<_Container>>, + __not_>, + __is_compatible_container<_Container>>> constexpr - span(_Container& __range) - noexcept(noexcept(::std::__adl_data(__range)) - && noexcept(::std::__adl_size(__range))) - : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + span(_Container& __cont) + noexcept(noexcept(std::data(__cont)) && noexcept(std::size(__cont))) + : _M_extent(std::size(__cont)), _M_ptr(std::data(__cont)) { } - template, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Container&>()))>, - element_type>>* = nullptr> - constexpr span(const _Container& __range) - noexcept(noexcept(::std::__adl_data(__range)) - && noexcept(::std::__adl_size(__range))) - : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + template, + __not_<__detail::__is_std_span<_Container>>, + __not_<__detail::__is_std_array<_Container>>, + __not_>, + __is_compatible_container>> + constexpr + span(const _Container& __cont) + noexcept(noexcept(std::data(__cont)) && noexcept(std::size(__cont))) + : _M_extent(std::size(__cont)), _M_ptr(std::data(__cont)) { } constexpr span(pointer __first, index_type __count) noexcept - : _M_extent(__count), _M_ptr(static_cast(__first)) + : _M_extent(__count), _M_ptr(__first) { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } constexpr span(pointer __first, pointer __last) noexcept - : span(::std::move(__first), static_cast(__last - __first)) + : span(__first, static_cast(__last - __first)) { } #endif // P1394 + template, + is_convertible<_OType(*)[], _Type(*)[]>>> + constexpr + span(const span<_OType, _OExtent>& __s) noexcept + : _M_extent(__s.size()), _M_ptr(__s.data()) + { } + // assignment constexpr span& @@ -474,7 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const array<_Type, _ArrayExtent>&) -> span; -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 +#ifdef _GLIBCXX_P1394 template span(_ContiguousIterator, _Sentinel) --uX7BrQs69PbBafpd--