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<OtherType, OtherExtent>, as specified in the C++20 draft.


Tested x86_64-linux, committed to trunk.


commit cf9248752de63a49bde062eb00681ae1c6d1a546
Author: Jonathan Wakely <jwak...@redhat.com>
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<OtherType, OtherExtent>, 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<value_type, N>&)): Likewise.
            (span::span(const array<value_type, N>&)): 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 <concepts>
            and <iterator>.
            [_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<OType, OExtent>&)): 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 <typename _Container>
-    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<size_t>(-1);
 
+  template<typename _Type, size_t _Extent>
+    class span;
+
   namespace __detail
   {
-    template<typename _Element, typename _ToElement>
-      static constexpr inline bool __is_base_derived_safe_convertible_v
-	= is_convertible_v<_Element (*)[], _ToElement (*)[]>;
-
     template<typename _Tp>
-      inline constexpr bool __is_std_array_v = false;
+      struct __is_std_span : false_type { };
 
     template<typename _Tp, size_t _Num>
-      inline constexpr bool
-      __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true;
+      struct __is_std_span<span<_Tp, _Num>> : true_type { };
+
+    template<typename _Tp>
+      struct __is_std_array : false_type { };
+
+    template<typename _Tp, size_t _Num>
+      struct __is_std_array<_GLIBCXX_STD_C::array<_Tp, _Num>> : true_type { };
 
 #ifdef _GLIBCXX_DEBUG
     template<typename _Tp, size_t _Num>
-      inline constexpr bool
-      __is_std_array_v<std::__debug::array<_Tp, _Num>> = true;
-#endif // debug/array
+      struct __is_std_array<__debug::array<_Tp, _Num>> : true_type { };
+#endif
 
     template<size_t _Extent>
       class __extent_storage
@@ -119,6 +122,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    return dynamic_extent;
 	}
 
+      template<typename _Tp>
+	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<size_t _ArrayExtent,
-	enable_if_t<
-	  (_Extent == dynamic_extent || _ArrayExtent == _Extent)
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(::std::__adl_data(
-	      ::std::declval<element_type (&)[_ArrayExtent]>()))>,
-	    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<pointer>(__arr), _ArrayExtent)
 	{ }
 
       template<size_t _ArrayExtent,
-	enable_if_t<
-	  (_Extent == dynamic_extent || _ArrayExtent == _Extent)
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(::std::__adl_data(
-	      ::std::declval<const array<value_type, _ArrayExtent>&>()))>,
-	    element_type>>* = nullptr>
+	enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>*
+	  = nullptr>
 	constexpr
-	span(array<value_type, _ArrayExtent>& __arr)
-	noexcept(noexcept(::std::__adl_data(__arr)))
-	: span(::std::__adl_data(__arr), _ArrayExtent)
+	span(array<value_type, _ArrayExtent>& __arr) noexcept
+	: span(__arr.data(), _ArrayExtent)
 	{ }
 
       template<size_t _ArrayExtent,
-	enable_if_t<
-	  (_Extent == dynamic_extent || _ArrayExtent == _Extent)
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(::std::__adl_data(
-	      ::std::declval<const array<value_type, _ArrayExtent>&>()))>,
-	    element_type>>* = nullptr>
+	enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>*
+	  = nullptr>
 	constexpr
-	span(const array<value_type, _ArrayExtent>& __arr)
-	noexcept(noexcept(::std::__adl_data(__arr)))
-	: span(::std::__adl_data(__arr), _ArrayExtent)
+	span(const array<value_type, _ArrayExtent>& __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<typename _Range,
-	enable_if_t<
-	  (_Extent == dynamic_extent)
-	  && !is_same_v<remove_cvref_t<_Range>, span>
-	  && !__detail::__is_std_array_v<remove_cvref_t<_Range>>
-	  && !is_array_v<remove_cvref_t<_Range>>
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(
-	      ::std::__adl_data(::std::declval<_Range&>())
-	      + ::std::__adl_size(::std::declval<_Range&>()))>,
-	    element_type>>* = nullptr>
+#ifdef _GLIBCXX_P1394
+    private:
+      // FIXME: use std::iter_reference_t
+      template<typename _Iterator>
+	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 _Rng,
+	       typename _Rng2 = remove_cvref_t<_Rng>,
+	       typename = enable_if_t<!__detail::__is_std_span<_Rng2>::value>>
+	using iterator_t = decltype(std::__adl_begin(std::declval<_Rng&>()));
+      // FIXME: use std::iter_value_t
+      template<typename _Iter>
+	using iter_value_t = typename iterator_traits<_Iter>::value_type;
+      // FIXME: use std::derived_from concept
+      template<typename _Derived, typename _Base>
+	using derived_from
+	  = __and_<is_base_of<_Base, _Derived>,
+	      is_convertible<const volatile _Derived*, const volatile _Base*>>;
+      // FIXME: require contiguous_iterator<_Iterator>
+      template<typename _Iter,
+	       typename _Ref = iter_reference_t<_Iter>,
+	       typename _Traits = iterator_traits<_Iter>,
+	       typename _Tag = typename _Traits::iterator_category>
+	using __is_compatible_iterator
+	  = __and_<derived_from<_Tag, random_access_iterator_tag>,
+		   is_lvalue_reference<_Ref>,
+		   is_same<iter_value_t<_Iter>, remove_cvref_t<_Ref>>,
+		   __is_compatible<remove_reference_t<_Ref>>>;
+
+      template<typename _Range>
+	using __is_compatible_range
+	  = __is_compatible_iterator<iterator_t<_Range>>;
+
+    public:
+      template<typename _Range, typename = _Require<
+	  bool_constant<_Extent == dynamic_extent>,
+	  __not_<__detail::__is_std_span<remove_cvref_t<_Range>>>,
+	  __not_<__detail::__is_std_array<remove_cvref_t<_Range>>>,
+	  __not_<is_array<remove_reference_t<_Range>>>,
+	  __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<typename _ContiguousIterator, typename _Sentinel,
-	enable_if_t<!is_convertible_v<_Sentinel, index_type>
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_reference_t<typename
-	      iterator_traits<_ContiguousIterator>::reference>,
-	  element_type>>* = nullptr>
+      template<typename _ContiguousIterator, typename _Sentinel, typename
+		= _Require<__not_<is_convertible<_Sentinel, index_type>>,
+			   __is_compatible_iterator<_ContiguousIterator>>>
 	constexpr
 	span(_ContiguousIterator __first, _Sentinel __last)
-	: span(::std::move(__first), static_cast<index_type>(__last - __first))
-	{ }
+	: _M_extent(static_cast<index_type>(__last - __first)),
+	  _M_ptr(std::to_address(__first))
+	{
+	  if (_Extent != dynamic_extent)
+	    __glibcxx_assert((__last - __first) == _Extent);
+	}
 
-      template<typename _ContiguousIterator>
+      template<typename _ContiguousIterator, typename
+		= _Require<__is_compatible_iterator<_ContiguousIterator>>>
 	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<typename _Container,
-	enable_if_t<
-	  (_Extent == dynamic_extent)
-	  && !is_same_v<remove_cvref_t<_Container>, span>
-	  && !__detail::__is_std_array_v<remove_cvref_t<_Container>>
-	  && !is_array_v<remove_cvref_t<_Container>>
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(
-	      ::std::__adl_data(::std::declval<_Container&>())
-	      + ::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<remove_pointer_t<_DataT>>;
+
+    public:
+      template<typename _Container, typename = _Require<
+		bool_constant<_Extent == dynamic_extent>,
+		__not_<__detail::__is_std_span<_Container>>,
+		__not_<__detail::__is_std_array<_Container>>,
+		__not_<is_array<_Container>>,
+		__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<typename _Container,
-	enable_if_t<
-	  (_Extent == dynamic_extent)
-	  && !is_same_v<remove_cvref_t<_Container>, span>
-	  && !__detail::__is_std_array_v<remove_cvref_t<_Container>>
-	  && !is_array_v<remove_cvref_t<_Container>>
-	  && __detail::__is_base_derived_safe_convertible_v<
-	    remove_pointer_t<decltype(
-	      ::std::__adl_data(::std::declval<_Container&>())
-	      + ::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<typename _Container, typename = _Require<
+		bool_constant<_Extent == dynamic_extent>,
+		__not_<__detail::__is_std_span<_Container>>,
+		__not_<__detail::__is_std_array<_Container>>,
+		__not_<is_array<_Container>>,
+		__is_compatible_container<const _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<pointer>(__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<index_type>(__last - __first))
+      : span(__first, static_cast<index_type>(__last - __first))
       { }
 #endif // P1394
 
+      template<typename _OType, size_t _OExtent, typename = _Require<
+	  __bool_constant<_Extent == dynamic_extent || _Extent == _OExtent>,
+	  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<const _Type, _ArrayExtent>;
 
-#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394
+#ifdef _GLIBCXX_P1394
 
   template<typename _ContiguousIterator, typename _Sentinel>
     span(_ContiguousIterator, _Sentinel)

Reply via email to