[ PATCH ] C++20 <span>

JeanHeyd Meneide phdofthehouse@gmail.com
Wed Sep 4 22:47:00 GMT 2019


     Thank you for the thorough review!

On Tue, Sep 3, 2019 at 9:31 AM Jonathan Wakely <jwakely@redhat.com> wrote:
> It looks like__adl_begin and __adl_end should be guarded by #ifdef
> _GLIBCXX_P1394 because they're not needed otherwise.

     I'm absolutely going to need it for the bit data structures (and
in tuning up other parts of the library). It will also be important
for things that need to behave nicely when working with things needing
[range.access] internally in libstdc++,
while we wait for the cmcstl2 implementation. I did gate
__adl_to_address behind p1394, though, because that is definitely
specific to that paper (and its friend, p1474).

     Let me know if I missed anything!

     Tested on x64_86 Linux with 23_containers/* tests.
-------------- next part --------------
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 3fe80f32cc4..b8b786d9260 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -68,6 +68,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
 	${std_srcdir}/stdexcept \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index b675d356cd4..cd1e9df5482 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -412,6 +412,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
 	${std_srcdir}/stdexcept \
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index d1e74711433..a80ec48248f 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -318,6 +318,78 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #endif // C++17
 
+#if __cplusplus > 201703L
+  // "why are these in namespace std:: and not __gnu_cxx:: ?"
+  // because if we don't put them here it's impossible to 
+  // have implicit ADL with "using std::begin/end/size/data;".
+  template <typename _Container>
+    constexpr auto
+    __adl_begin(_Container& __cont) noexcept(noexcept(begin(__cont)))
+    { return begin(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_end(_Container& __cont) noexcept(noexcept(end(__cont)))
+    { return end(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_cbegin(_Container& __cont) noexcept(noexcept(cbegin(__cont)))
+    { return cbegin(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_cend(_Container& __cont) noexcept(noexcept(cend(__cont)))
+    { return cend(__cont); }
+
+  template <typename _Container>
+    constexpr auto
+    __adl_rbegin(_Container& __cont) noexcept(noexcept(rbegin(__cont)))
+    { return rbegin(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_rend(_Container& __cont) noexcept(noexcept(rend(__cont)))
+    { return rend(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_crbegin(_Container& __cont) noexcept(noexcept(crbegin(__cont)))
+    { return crbegin(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_crend(_Container& __cont) noexcept(noexcept(crend(__cont)))
+    { return crend(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_data(_Container& __cont) noexcept(noexcept(data(__cont)))
+    { return data(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_cdata(_Container& __cont) noexcept(noexcept(cdata(__cont)))
+    { return cdata(__cont); }
+  
+  template <typename _Container>
+    constexpr auto
+    __adl_size(_Container& __cont) noexcept(noexcept(size(__cont)))
+    { return size(__cont); }
+  
+  template <typename _Container>
+    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
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index 8ab0d72b0c2..e29775a42c5 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -446,7 +446,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201103L
   template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR auto
+    _GLIBCXX20_CONSTEXPR
+    auto
     __niter_base(reverse_iterator<_Iterator> __it)
     -> decltype(__make_reverse_iterator(__niter_base(__it.base())))
     { return __make_reverse_iterator(__niter_base(__it.base())); }
@@ -457,7 +458,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR auto
+    _GLIBCXX20_CONSTEXPR
+    auto
     __miter_base(reverse_iterator<_Iterator> __it)
     -> decltype(__make_reverse_iterator(__miter_base(__it.base())))
     { return __make_reverse_iterator(__miter_base(__it.base())); }
@@ -802,12 +804,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _GLIBCXX_CONSTEXPR __normal_iterator() _GLIBCXX_NOEXCEPT
       : _M_current(_Iterator()) { }
 
-      explicit
+      explicit _GLIBCXX20_CONSTEXPR
       __normal_iterator(const _Iterator& __i) _GLIBCXX_NOEXCEPT
       : _M_current(__i) { }
 
       // Allow iterator to const_iterator conversion
       template<typename _Iter>
+        _GLIBCXX20_CONSTEXPR
         __normal_iterator(const __normal_iterator<_Iter,
 			  typename __enable_if<
       	       (std::__are_same<_Iter, typename _Container::pointer>::__value),
@@ -815,14 +818,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         : _M_current(__i.base()) { }
 
       // Forward iterator requirements
+      _GLIBCXX20_CONSTEXPR
       reference
       operator*() const _GLIBCXX_NOEXCEPT
       { return *_M_current; }
 
+      _GLIBCXX20_CONSTEXPR
       pointer
       operator->() const _GLIBCXX_NOEXCEPT
       { return _M_current; }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator&
       operator++() _GLIBCXX_NOEXCEPT
       {
@@ -830,11 +836,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator
       operator++(int) _GLIBCXX_NOEXCEPT
       { return __normal_iterator(_M_current++); }
 
       // Bidirectional iterator requirements
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator&
       operator--() _GLIBCXX_NOEXCEPT
       {
@@ -842,31 +850,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator
       operator--(int) _GLIBCXX_NOEXCEPT
       { return __normal_iterator(_M_current--); }
 
       // Random access iterator requirements
+      _GLIBCXX20_CONSTEXPR
       reference
       operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
       { return _M_current[__n]; }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator&
       operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
       { _M_current += __n; return *this; }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator
       operator+(difference_type __n) const _GLIBCXX_NOEXCEPT
       { return __normal_iterator(_M_current + __n); }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator&
       operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
       { _M_current -= __n; return *this; }
 
+      _GLIBCXX20_CONSTEXPR
       __normal_iterator
       operator-(difference_type __n) const _GLIBCXX_NOEXCEPT
       { return __normal_iterator(_M_current - __n); }
 
+      _GLIBCXX20_CONSTEXPR
       const _Iterator&
       base() const _GLIBCXX_NOEXCEPT
       { return _M_current; }
@@ -882,6 +897,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Forward iterator requirements
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -889,6 +905,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() == __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
 	       const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -896,6 +913,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() == __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -903,6 +921,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() != __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator!=(const __normal_iterator<_Iterator, _Container>& __lhs,
 	       const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -911,6 +930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Random access iterator requirements
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -918,6 +938,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() < __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator<(const __normal_iterator<_Iterator, _Container>& __lhs,
 	      const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -925,6 +946,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() < __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -932,6 +954,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() > __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator>(const __normal_iterator<_Iterator, _Container>& __lhs,
 	      const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -939,6 +962,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() > __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -946,6 +970,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() <= __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator<=(const __normal_iterator<_Iterator, _Container>& __lhs,
 	       const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -953,6 +978,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() <= __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
@@ -960,6 +986,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() >= __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     operator>=(const __normal_iterator<_Iterator, _Container>& __lhs,
 	       const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -973,6 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _IteratorL, typename _IteratorR, typename _Container>
 #if __cplusplus >= 201103L
     // DR 685.
+    _GLIBCXX20_CONSTEXPR
     inline auto
     operator-(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept
@@ -985,6 +1013,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() - __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline typename __normal_iterator<_Iterator, _Container>::difference_type
     operator-(const __normal_iterator<_Iterator, _Container>& __lhs,
 	      const __normal_iterator<_Iterator, _Container>& __rhs)
@@ -992,6 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() - __rhs.base(); }
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline __normal_iterator<_Iterator, _Container>
     operator+(typename __normal_iterator<_Iterator, _Container>::difference_type
 	      __n, const __normal_iterator<_Iterator, _Container>& __i)
@@ -1006,6 +1036,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
     _Iterator
     __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it)
     _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
new file mode 100644
index 00000000000..6bb373f1bcd
--- /dev/null
+++ b/libstdc++-v3/include/std/span
@@ -0,0 +1,515 @@
+// Components for manipulating non-owning sequences of objects -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file span
+ *  This is a Standard C++ Library header.
+ */
+
+//
+// P0122 span library
+// Contributed by ThePhD
+//
+
+#ifndef _GLIBCXX_SPAN
+#define _GLIBCXX_SPAN 1
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+
+#include <cstddef>
+#include <type_traits>
+#include <tuple>
+#include <utility>
+#include <array>
+#include <bits/stl_iterator.h>
+#include <bits/range_access.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+  _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+// FIXME: they forgot this feature test macro
+// get on someone's back about it in Belfast!!!
+#define __cpp_lib_span 201911
+
+  inline constexpr size_t dynamic_extent =
+    static_cast<size_t>(-1);
+
+  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;
+
+    template<typename _Tp, size_t _Num>
+      inline constexpr bool
+      __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true;
+
+#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
+
+    template<size_t _Extent>
+      class __extent_storage
+      {
+      public:
+
+        constexpr 
+        __extent_storage() noexcept = default;
+        
+        constexpr 
+        __extent_storage(size_t) noexcept
+        {}
+
+        static constexpr size_t
+        _M_extent() noexcept
+        { return _Extent; }
+      };
+
+    template<>
+      class __extent_storage<static_cast<size_t>(-1)>
+      {
+      public:
+      
+        constexpr 
+        __extent_storage() noexcept : _M_extent_value(0){};
+
+        constexpr 
+        __extent_storage(size_t __extent) noexcept
+        : _M_extent_value(__extent)
+        {}
+
+        constexpr size_t
+        _M_extent() const noexcept
+        { return this->_M_extent_value; }
+
+      private:
+        size_t _M_extent_value;
+      };
+
+  } // namespace __detail
+
+  template<typename _Type, size_t _Extent = dynamic_extent>
+    class span : private __detail::__extent_storage<_Extent>
+    {
+    public:
+      // member types
+      using value_type             = remove_cv_t<_Type>;
+      using element_type           = _Type;
+      using index_type             = size_t;
+      using reference              = element_type&;
+      using const_reference        = const element_type&;
+      using pointer                = _Type*;
+      using const_pointer          = const _Type*;
+      using iterator               = __gnu_cxx::__normal_iterator<pointer, span>;
+      using const_iterator         = __gnu_cxx::__normal_iterator<const_pointer, span>;
+      using reverse_iterator       = ::std::reverse_iterator<iterator>;
+      using const_reverse_iterator = ::std::reverse_iterator<const_iterator>;
+      using difference_type        = ptrdiff_t;
+      // Official wording has no size_type -- why??
+      // using size_type = size_t;
+
+      // member constants
+      static inline constexpr size_t extent = _Extent;
+
+    private:
+      using __base_t = __detail::__extent_storage<extent>;
+
+    public:
+      // constructors
+      template <typename _Dummy = _Type, enable_if_t<is_same_v<_Dummy, _Type> && (_Extent == dynamic_extent || _Extent == 0)>* = nullptr>
+        constexpr span() noexcept : __base_t(0), _M_ptr(nullptr)
+        {}
+
+      constexpr 
+      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)
+        {}
+
+      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>
+        constexpr span(array<value_type, _ArrayExtent>& __arr) noexcept(
+          noexcept(::std::__adl_data(__arr)))
+        : span(::std::__adl_data(__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>
+        constexpr span(const array<value_type, _ArrayExtent>& __arr) 
+          noexcept(noexcept(::std::__adl_data(__arr)))
+        : span(::std::__adl_data(__arr), _ArrayExtent)
+        {}
+
+      // NOTE: when the time comes, and P1394 -
+      // range constructors for std::span - ships in
+      // the standard, delete the #else block and remove
+      // the conditional
+      // if the paper fails, delete #if block
+      // 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>
+        constexpr span(_Range&& __range) noexcept(
+          noexcept(::std::__adl_data(__range)) &&
+          noexcept(::std::__adl_size(__range)))
+        : 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>
+        constexpr span(_ContiguousIterator __first, _Sentinel __last)
+        : span(::std::move(__first), static_cast<index_type>(__last - __first))
+        {}
+
+      template<typename _ContiguousIterator>
+        constexpr span(_ContiguousIterator __first, index_type __count) noexcept(
+          noexcept(::std::__adl_to_address(__first)))
+        : __base_t(__count), _M_ptr(::std::__adl_to_address(__first))
+        { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); }
+
+  #else
+
+      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(_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,
+        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))
+        {}
+      
+      constexpr span(pointer __first, index_type __count) noexcept
+      : __base_t(__count), _M_ptr(static_cast<pointer>(__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))
+      {}
+  #endif // P1394
+
+      // assignment
+      constexpr span&
+      operator=(const span&) noexcept = default;
+
+      // observers: element access
+      constexpr reference
+      front() const noexcept
+      { return *this->begin(); }
+
+      constexpr reference
+      back() const noexcept
+      {
+        iterator __it = this->end();
+        --__it;
+        return *__it;
+      }
+
+      constexpr reference 
+      operator[](index_type __idx) const noexcept
+      { return *(this->_M_ptr + __idx); }
+
+      constexpr pointer
+      data() const noexcept
+      { return this->_M_ptr; }
+
+      constexpr index_type
+      size() const noexcept
+      { return this->__base_t::_M_extent(); }
+
+      constexpr index_type
+      size_bytes() const noexcept
+      { return this->__base_t::_M_extent() * sizeof(element_type); }
+
+      constexpr bool
+      empty() const noexcept
+      { return size() == 0; }
+
+      // observers: iterator support
+      constexpr iterator
+      begin() const noexcept
+      { return iterator(this->_M_ptr); }
+
+      constexpr const_iterator
+      cbegin() const noexcept
+      { return const_iterator(this->_M_ptr); }
+
+      constexpr iterator
+      end() const noexcept
+      { return iterator(this->_M_ptr + this->size()); }
+
+      constexpr const_iterator
+      cend() const noexcept
+      { return const_iterator(this->_M_ptr + this->size()); }
+
+      constexpr reverse_iterator
+      rbegin() const noexcept
+      { return reverse_iterator(this->end()); }
+
+      constexpr const_reverse_iterator
+      crbegin() const noexcept
+      { return const_reverse_iterator(this->cend()); }
+
+      constexpr reverse_iterator
+      rend() const noexcept
+      { return reverse_iterator(this->begin()); }
+
+      constexpr const_reverse_iterator
+      crend() const noexcept
+      { return const_reverse_iterator(this->cbegin()); }
+
+      // observers: subranges
+      template<size_t _Count>
+        constexpr span<element_type, _Count>
+        first() const
+        {
+          __glibcxx_assert(_Count < size());
+          return { this->data(), _Count };
+        }
+
+      constexpr span<element_type, dynamic_extent>
+      first(index_type __count) const
+      {
+        __glibcxx_assert(__count < size());
+        return { this->data(), __count }; 
+      }
+
+      template<size_t _Count>
+        constexpr span<element_type, _Count>
+        last() const
+        {
+          static_assert(_Count == dynamic_extent ||
+                          _Extent == dynamic_extent || _Count <= _Extent,
+            "Count or Extent are dynamic, "
+            "or the Count is less than the static extent");
+          __glibcxx_assert(_Count <= size());
+          return { this->data() + (this->size() - _Count), _Count };
+        }
+
+      constexpr span<element_type, dynamic_extent>
+      last(index_type __count) const
+      {
+        __glibcxx_assert(__count < size());
+        index_type __offset = (this->size() - __count);
+        return { this->data() + __offset, __count };
+      }
+
+      template<size_t _Offset, size_t _Count = dynamic_extent>
+        constexpr auto
+        subspan() const
+        {
+          static_assert(_Count == dynamic_extent ||
+                          _Extent == dynamic_extent ||
+                          (_Offset + _Count) <= _Extent,
+            "Count or Extent are dynamic, "
+            "or the Count + Offset is less than the static extent");
+          constexpr size_t __span_extent =
+            (_Count != dynamic_extent
+                ? _Count
+                : (_Extent != dynamic_extent ? _Extent - _Offset
+                                                    : dynamic_extent));
+          using __span_t = span<element_type, __span_extent>;
+          if constexpr(_Count != dynamic_extent) 
+            {
+              __glibcxx_assert((_Offset + _Count) < size());
+            }
+          return __span_t(this->data() + _Offset,
+            (_Count == dynamic_extent ? this->size() - _Offset : _Count));
+        }
+
+      constexpr span<element_type, dynamic_extent>
+      subspan(
+        index_type __offset, index_type __count = dynamic_extent) const
+      {
+        return {this->data() + __offset,
+          __count == dynamic_extent ? this->size() - __offset : __count};
+      }
+
+      // observers: range helpers
+      friend constexpr iterator
+      begin(span __sp) noexcept
+      {
+        return __sp.begin();
+      }
+
+      friend constexpr iterator
+      end(span __sp) noexcept
+      {
+        return __sp.end();
+      }
+
+    private:
+      pointer _M_ptr;
+    };
+
+  // deduction guides
+  template<typename _Type, size_t _ArrayExtent>
+    span(_Type(&)[_ArrayExtent])->span<_Type, _ArrayExtent>;
+
+  template<typename _Type, size_t _ArrayExtent>
+    span(array<_Type, _ArrayExtent>&)->span<_Type, _ArrayExtent>;
+
+  template<typename _Type, size_t _ArrayExtent>
+    span(const array<_Type, _ArrayExtent>&)
+      ->span<const _Type, _ArrayExtent>;
+
+#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394
+
+  template<typename _ContiguousIterator, typename _Sentinel>
+    span(_ContiguousIterator, _Sentinel)
+      ->span<remove_reference_t<
+        typename iterator_traits<_ContiguousIterator>::reference>>;
+
+  template<typename _Range>
+    span(_Range &&)
+      ->span<remove_reference_t<typename iterator_traits<decltype(
+        ::std::__adl_begin(::std::declval<_Range&>()))>::reference>>;
+
+#else
+
+  template<typename _Container>
+    span(_Container&)->span<typename _Container::value_type>;
+
+  template<typename _Container>
+    span(const _Container&)->span<const typename _Container::value_type>;
+
+#endif // P1394
+
+  template<typename _Type, size_t _Extent>
+    span<const byte, _Extent == dynamic_extent
+        ? dynamic_extent : _Extent * sizeof(_Type)>
+    inline as_bytes(span<_Type, _Extent> __sp) noexcept
+    {
+      return {reinterpret_cast<const byte*>(__sp.data()), __sp.size_bytes()};
+    }
+
+  template<typename _Type, size_t _Extent>
+    span<byte, _Extent == dynamic_extent
+       ? dynamic_extent : _Extent * sizeof(_Type)>
+    as_writable_bytes(span<_Type, _Extent> __sp) noexcept
+    {
+      return {reinterpret_cast<byte*>(__sp.data()), __sp.size_bytes()};
+    }
+
+  // tuple helpers
+  template<size_t _Index, typename _Type, size_t _Extent>
+    constexpr _Type& 
+    get(span<_Type, _Extent> __sp) noexcept
+    {
+      static_assert(_Extent != dynamic_extent 
+        && (_Extent > 0) && (_Index < _Extent), 
+        "get can only be used with a span of non-dynamic "
+        "(fixed) extent.");
+      return __sp[_Index];
+    }
+
+  template<typename _Type, size_t _Extent>
+    struct tuple_size<span<_Type, _Extent>>
+    : public integral_constant<size_t, _Extent>
+    {
+      static_assert(_Extent != dynamic_extent, "tuple_size can only "
+        "be used with a span of non-dynamic (fixed) extent");
+    };
+
+  template<size_t _Index, typename _Type, size_t _Extent>
+    struct tuple_element<_Index, span<_Type, _Extent>>
+    {
+      static_assert(_Extent != dynamic_extent, "tuple_size can only "
+        "be used with a span of non-dynamic (fixed) extent");
+      static_assert(_Index < _Extent, "Index is less than Extent");
+      using type = typename span<_Type, _Extent>::element_type;
+    };
+
+  _GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std_GLIBCXX_VISIBILITY(default)
+
+#endif // C++20
+
+#endif
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 7f7d05fd8f2..4341c9f0c1b 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -167,6 +167,9 @@
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
 #define __cpp_lib_to_array 201907L
+// FIXME: they forgot this feature test macro
+// get on someone's back about it in Belfast!!!
+#define __cpp_lib_span 201911
 #endif // C++2a
 #endif // C++17
 #endif // C++14
diff --git a/libstdc++-v3/testsuite/23_containers/span/everything.cc b/libstdc++-v3/testsuite/23_containers/span/everything.cc
new file mode 100644
index 00000000000..1ee1f6e004c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/everything.cc
@@ -0,0 +1,203 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++2a" }
+// { dg-do run { target c++2a } }
+
+#include <testsuite_hooks.h>
+
+#include <span>
+#include <type_traits>
+#include <cstdint>
+#include <vector>
+#include <algorithm>
+#include <cassert>
+
+int
+main()
+{
+  struct alignas(256) strawman
+  {
+    int x;
+    int y;
+    bool z;
+    int w;
+  };
+
+  struct naked_span
+  {
+    char* p;
+    std::size_t n;
+  };
+
+  struct strawman_span
+  {
+    strawman* p;
+    std::size_t n;
+  };
+
+  static_assert(sizeof(std::span<char, 0>) <= sizeof(char*));
+  static_assert(sizeof(std::span<const char, 0>) <= sizeof(const char*));
+  static_assert(sizeof(std::span<strawman, 0>) <= sizeof(strawman*));
+  static_assert(sizeof(std::span<strawman, 1>) <= sizeof(strawman*));
+  static_assert(sizeof(std::span<char>) <= sizeof(naked_span));
+  static_assert(sizeof(std::span<strawman>) <= sizeof(strawman_span));
+
+  constexpr static std::array<int, 9> arr_data{ 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+  constexpr auto arr_data_span = std::span(arr_data);
+  static_assert(arr_data_span.size() == 9);
+  static_assert(arr_data_span.size_bytes() == 9 * sizeof(int));
+  static_assert(*arr_data_span.begin() == 0);
+  static_assert(*arr_data_span.data() == 0);
+  static_assert(arr_data_span.front() == 0);
+  static_assert(arr_data_span.back() == 8);
+  static_assert(arr_data_span[0] == 0);
+  static_assert(arr_data_span[1] == 1);
+  static_assert(arr_data_span[2] == 2);
+  static_assert(arr_data_span[3] == 3);
+  static_assert(arr_data_span[4] == 4);
+  static_assert(arr_data_span[5] == 5);
+  static_assert(arr_data_span[6] == 6);
+  static_assert(arr_data_span[7] == 7);
+  static_assert(arr_data_span[8] == 8);
+  static_assert(!arr_data_span.empty());
+  static_assert(decltype(arr_data_span)::extent == 9);
+
+  constexpr static int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+  constexpr auto data_span    = std::span(data);
+  static_assert(data_span.size() == 9);
+  static_assert(data_span.size_bytes() == 9 * sizeof(int));
+  static_assert(*data_span.begin() == 0);
+  static_assert(*data_span.data() == 0);
+  static_assert(data_span.front() == 0);
+  static_assert(data_span.back() == 8);
+  static_assert(data_span[0] == 0);
+  static_assert(data_span[1] == 1);
+  static_assert(data_span[2] == 2);
+  static_assert(data_span[3] == 3);
+  static_assert(data_span[4] == 4);
+  static_assert(data_span[5] == 5);
+  static_assert(data_span[6] == 6);
+  static_assert(data_span[7] == 7);
+  static_assert(data_span[8] == 8);
+  static_assert(!data_span.empty());
+  static_assert(decltype(data_span)::extent == 9);
+
+  constexpr auto data_span_first = data_span.first<3>();
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_first)>, std::span<const int, 3>>);
+  static_assert(decltype(data_span_first)::extent == 3);
+  static_assert(data_span_first.size() == 3);
+  static_assert(data_span_first.front() == 0);
+  static_assert(data_span_first.back() == 2);
+  static_assert(std::tuple_size_v<decltype(data_span_first)> == 3);
+  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(data_span_first)>, const int>);
+
+  constexpr auto data_span_first_dyn = data_span.first(4);
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_first_dyn)>, std::span<const int>>);
+  static_assert(decltype(data_span_first_dyn)::extent == std::dynamic_extent);
+  static_assert(data_span_first_dyn.size() == 4);
+  static_assert(data_span_first_dyn.front() == 0);
+  static_assert(data_span_first_dyn.back() == 3);
+
+  constexpr auto data_span_last = data_span.last<5>();
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_last)>, std::span<const int, 5>>);
+  static_assert(decltype(data_span_last)::extent == 5);
+  static_assert(data_span_last.size() == 5);
+  static_assert(data_span_last.front() == 4);
+  static_assert(data_span_last.back() == 8);
+  static_assert(std::tuple_size_v<decltype(data_span_last)> == 5);
+  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(data_span_last)>, const int>);
+
+  constexpr auto data_span_last_dyn = data_span.last(6);
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_last_dyn)>, std::span<const int>>);
+  static_assert(decltype(data_span_last_dyn)::extent == std::dynamic_extent);
+  static_assert(data_span_last_dyn.size() == 6);
+  static_assert(data_span_last_dyn.front() == 3);
+  static_assert(data_span_last_dyn.back() == 8);
+
+  constexpr auto data_span_subspan = data_span.subspan<1, 3>();
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_subspan)>, std::span<const int, 3>>);
+  static_assert(decltype(data_span_subspan)::extent == 3);
+  static_assert(data_span_subspan.size() == 3);
+  static_assert(data_span_subspan.front() == 1);
+  static_assert(data_span_subspan.back() == 3);
+
+  constexpr auto data_span_subspan_offset = data_span.subspan<8>();
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_subspan_offset)>, std::span<const int, 1>>);
+  static_assert(decltype(data_span_subspan_offset)::extent == 1);
+  static_assert(data_span_subspan_offset.size() == 1);
+  static_assert(data_span_subspan_offset.front() == 8);
+  static_assert(data_span_subspan_offset.back() == 8);
+
+  constexpr auto data_span_subspan_empty = data_span.subspan(9, 0);
+  static_assert(
+    std::is_same_v<std::remove_cv_t<decltype(data_span_subspan_empty)>, std::span<const int>>);
+  static_assert(decltype(data_span_subspan_empty)::extent == std::dynamic_extent);
+  static_assert(data_span_subspan_empty.size() == 0);
+
+  constexpr auto data_span_subspan_empty_static = data_span.subspan<9>();
+  static_assert(std::is_same_v<std::remove_cv_t<decltype(data_span_subspan_empty_static)>,
+    std::span<const int, 0>>);
+  static_assert(decltype(data_span_subspan_empty_static)::extent == 0);
+  static_assert(data_span_subspan_empty.size() == 0);
+
+  std::span<short> shorts{};
+  bool really_empty0 = shorts.empty();
+  bool really_empty1 = std::empty(shorts);
+  bool really_empty2 = shorts.data() == nullptr;
+  bool really_empty3 = shorts.begin() == shorts.end();
+  bool really_empty4 = shorts.cbegin() == shorts.cend();
+  bool really_empty =
+    really_empty0 && really_empty1 && really_empty2 && really_empty3 && really_empty4;
+  (void)really_empty;
+  VERIFY(really_empty);
+
+  std::vector<std::int_least32_t> value{ 0 };
+  std::span<int32_t> muh_span(value);
+  VERIFY(muh_span.size() == 1);
+  std::byte* original_bytes                  = reinterpret_cast<std::byte*>(value.data());
+  original_bytes[0]                          = static_cast<std::byte>(1);
+  original_bytes[1]                          = static_cast<std::byte>(2);
+  original_bytes[2]                          = static_cast<std::byte>(3);
+  original_bytes[3]                          = static_cast<std::byte>(4);
+  std::span<const std::byte> muh_byte_span   = std::as_bytes(muh_span);
+  std::span<std::byte> muh_mutable_byte_span = std::as_writable_bytes(muh_span);
+  std::span<std::byte> muh_original_byte_span(original_bytes, original_bytes + 4);
+  bool definitely_reinterpret_casted0 = std::equal(muh_byte_span.cbegin(), muh_byte_span.cend(),
+    muh_original_byte_span.cbegin(), muh_original_byte_span.cend());
+  bool definitely_reinterpret_casted1 = std::equal(muh_mutable_byte_span.cbegin(),
+    muh_mutable_byte_span.cend(), muh_original_byte_span.cbegin(), muh_original_byte_span.cend());
+  bool definitely_reinterpret_casted =
+    definitely_reinterpret_casted0 && definitely_reinterpret_casted1;
+  (void)definitely_reinterpret_casted;
+  VERIFY(definitely_reinterpret_casted);
+
+  std::span<std::byte> muh_original_byte_span_ptr_size(original_bytes, 4);
+  bool definitely_equivalent =
+    std::equal(muh_original_byte_span_ptr_size.cbegin(), muh_original_byte_span_ptr_size.cend(),
+      muh_original_byte_span.cbegin(), muh_original_byte_span.cend());
+  (void)definitely_equivalent;
+  VERIFY(definitely_equivalent);
+
+  return definitely_equivalent && definitely_reinterpret_casted && really_empty ? 0 : 1;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.contiguous_range.cc b/libstdc++-v3/testsuite/23_containers/span/fail.contiguous_range.cc
new file mode 100644
index 00000000000..a1135d8e63b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.contiguous_range.cc
@@ -0,0 +1,29 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+#include <deque>
+
+int
+main()
+{
+  std::deque<int> d{};
+  std::span<int, std::dynamic_extent> myspan(d);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.get.cc b/libstdc++-v3/testsuite/23_containers/span/fail.get.cc
new file mode 100644
index 00000000000..d07d454fd60
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.get.cc
@@ -0,0 +1,29 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+#include <tuple>
+
+int
+main()
+{
+  std::span<int, std::dynamic_extent> myspan(nullptr, 0);
+  std::get<0>(myspan);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.last.cc b/libstdc++-v3/testsuite/23_containers/span/fail.last.cc
new file mode 100644
index 00000000000..3d3d1a323fc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.last.cc
@@ -0,0 +1,28 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+
+int
+main()
+{
+  std::span<int, 2> myspan(nullptr, 2);
+  myspan.last<3>();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.subspan.cc b/libstdc++-v3/testsuite/23_containers/span/fail.subspan.cc
new file mode 100644
index 00000000000..6ac0cd6d049
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.subspan.cc
@@ -0,0 +1,28 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+
+int
+main()
+{
+  std::span<int, 2> myspan(nullptr, 2);
+  myspan.subspan<3, 1>();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.dynamic.cc b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.dynamic.cc
new file mode 100644
index 00000000000..8dac14271c0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.dynamic.cc
@@ -0,0 +1,29 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+#include <tuple>
+
+int
+main()
+{
+  std::tuple_element<0, std::span<int, std::dynamic_extent>> ts;
+  (void)ts;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.oob.cc b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.oob.cc
new file mode 100644
index 00000000000..8cf57e40e6c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_element.oob.cc
@@ -0,0 +1,29 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+#include <tuple>
+
+int
+main()
+{
+  std::tuple_element<3, std::span<int, 2>> te;
+  (void)te;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/fail.tuple_size.cc b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_size.cc
new file mode 100644
index 00000000000..bd6b1e814a7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/fail.tuple_size.cc
@@ -0,0 +1,29 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-excess-errors { xfail c++2a } }
+
+#include <span>
+#include <tuple>
+
+int
+main()
+{
+  std::tuple_size<std::span<int, std::dynamic_extent>> ts;
+  (void)ts;
+  return 0;
+}


More information about the Gcc-patches mailing list