public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jonathan Wakely <jwakely@redhat.com>
To: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++ <libstdc++@gcc.gnu.org>
Subject: Re: [ PATCH ] C++20 <span>
Date: Thu, 05 Sep 2019 11:27:00 -0000	[thread overview]
Message-ID: <20190905112747.GM9487@redhat.com> (raw)
In-Reply-To: <CANHA4OhFRbE=ieqgvnE8OW=fcXas--bvt3Ak0JWdZHF3yxZkJA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 6017 bytes --]

On 04/09/19 18:47 -0400, JeanHeyd Meneide wrote:
>     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).

OK, then it's fine as is, thanks.

>+/** @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>

This header isn't needed. <bits/c++config.h> defines std::size_t and
std::ptrdiff_t, and every libstdc++ header should include
<bits/c++config.h> already. Not including <cstddef> is a minor
optimisation for compile time, because we don't need to open <cstddef>
and <stddef.h>.

>+    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;

Something else I forgot to mention (which I'll add to the coding
conventions documentation) is that we use TABs for indentation at the
start of lines. Tabstop should be set to 8, so anything indented by 8
chars or more should use TABs. Anything indented by fewer than 8 chars
just uses spaces.

>+
>+        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>

This line is too long, it needs to be split before 80 columns.

>+        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) &&

N.B. line breaks should come before logical operators like && e.g.

      foo
      && bar

Not:

      foo &&
      bar

The rationale for this is to make it easy to see the operator. You can
look at the start of  the line (at a predictable, easily findable
position) instead of having to look at the right hand side to see if
it's a && or || operator.


>+      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>> &&

Here's a good example where the && operators are all at different
columns, but if you put line breaks before the operator it looks like:

          (_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>>
          && ...

This is easier to see that it's a series of AND conditions with a
quick glance.

As discussed on IRC the new XFAIL tests need some adjustment. The
attached patch changes the whitespace as discussed above, and fixes
the tests.

Our convention for XFAIL tests is to call them foo_neg.cc (not
fail.foo.cc like libc++ uses).

The attached patch is what I've tested and committed to trunk - thanks
very much!

I'll make some additional fixes (e.g. LWG 3103) and update the docs
later today.


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 49737 bytes --]

commit 24bcbc6f622c6371d1fdf28bab25f64ff6d2dae1
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Sep 5 09:58:09 2019 +0100

    Implement std::span for C++20
    
    2019-09-05  JeanHeyd Meneide  <phdofthehouse@gmail.com>
    
            * include/Makefile.am: Add <span> header.
            * include/Makefile.in: Regenerate.
            * include/bits/range_access.h (__adl_begin, __adl_end, __adl_cbegin)
            (__adl_cend, __adl_rbegin, __adl_rend, __adl_crbegin, __adl_crend)
            (__adl_data, __adl_cdata, __adl_size, __adl_empty, __adl_to_address):
            New functions for performing argument-dependent lookup of range
            customization points.
            * include/bits/stl_iterator.h (__normal_iterator): Add
            _GLIBCXX20_CONSTEXPR to all functions.
            * include/std/span: New header.
            * include/std/version (__cpp_lib_span): Define feature test macro.
            * testsuite/23_containers/span/contiguous_range_neg.cc: New test.
            * testsuite/23_containers/span/everything.cc: New test.
            * testsuite/23_containers/span/get_neg.cc: New test.
            * testsuite/23_containers/span/last_neg.cc: New test.
            * testsuite/23_containers/span/subspan_neg.cc: New test.
            * testsuite/23_containers/span/tuple_element_dynamic_neg.cc: New test.
            * testsuite/23_containers/span/tuple_element_oob_neg.cc: New test.
            * testsuite/23_containers/span/tuple_size_neg.cc: New test.

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/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index d1e74711433..44b9c6c3596 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..4ce2f31a131
--- /dev/null
+++ b/libstdc++-v3/include/std/span
@@ -0,0 +1,521 @@
+// 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 <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),
+	"std::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
+
+#endif // C++20
+#endif // _GLIBCXX_SPAN
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/contiguous_range_neg.cc b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc
new file mode 100644
index 00000000000..475be1e900d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc
@@ -0,0 +1,32 @@
+// 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 compile { target c++2a } }
+
+#include <span>
+#include <deque>
+
+int
+main()
+{
+  std::deque<int> d{};
+  std::span<int, std::dynamic_extent> myspan(d); // { dg-error "no match" }
+}
+
+// { dg-prune-output "data" }
+// { dg-prune-output "invalid operands" }
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..719015a8714
--- /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/get_neg.cc b/libstdc++-v3/testsuite/23_containers/span/get_neg.cc
new file mode 100644
index 00000000000..37d188ed073
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/get_neg.cc
@@ -0,0 +1,30 @@
+// 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 compile { target c++2a } }
+
+#include <span>
+#include <tuple>
+
+int
+main()
+{
+  std::span<int, std::dynamic_extent> myspan((int*)nullptr, 0ul);
+  std::get<0>(myspan); // { dg-error "here" }
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/span/last_neg.cc b/libstdc++-v3/testsuite/23_containers/span/last_neg.cc
new file mode 100644
index 00000000000..8f0145f7012
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/last_neg.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-options "-std=c++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <span>
+
+int
+main()
+{
+  std::span<int, 2> myspan(nullptr, 2);
+  myspan.last<3>(); // { dg-error "here" }
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/span/subspan_neg.cc b/libstdc++-v3/testsuite/23_containers/span/subspan_neg.cc
new file mode 100644
index 00000000000..5ecbff937cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/subspan_neg.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-options "-std=c++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <span>
+
+int
+main()
+{
+  std::span<int, 2> myspan(nullptr, 2);
+  myspan.subspan<3, 1>(); // { dg-error "here" }
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/span/tuple_element_dynamic_neg.cc b/libstdc++-v3/testsuite/23_containers/span/tuple_element_dynamic_neg.cc
new file mode 100644
index 00000000000..cf8436099ce
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/tuple_element_dynamic_neg.cc
@@ -0,0 +1,25 @@
+// 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 compile { target c++2a } }
+
+#include <span>
+#include <tuple>
+
+std::tuple_element<0, std::span<int, std::dynamic_extent>> ts; // { dg-error "here" }
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/span/tuple_element_oob_neg.cc b/libstdc++-v3/testsuite/23_containers/span/tuple_element_oob_neg.cc
new file mode 100644
index 00000000000..bf97735cd55
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/tuple_element_oob_neg.cc
@@ -0,0 +1,25 @@
+// 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 compile { target c++2a } }
+
+#include <span>
+#include <tuple>
+
+std::tuple_element<3, std::span<int, 2>> te; // { dg-error "here" }
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/span/tuple_size_neg.cc b/libstdc++-v3/testsuite/23_containers/span/tuple_size_neg.cc
new file mode 100644
index 00000000000..99e95b3243a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/tuple_size_neg.cc
@@ -0,0 +1,25 @@
+// 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 compile { target c++2a } }
+
+#include <span>
+#include <tuple>
+
+std::tuple_size<std::span<int, std::dynamic_extent>> ts; // { dg-error "here" }
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }

  reply	other threads:[~2019-09-05 11:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-30 20:05 JeanHeyd Meneide
2019-08-30 21:37 ` Jonathan Wakely
2019-08-30 23:42   ` JeanHeyd Meneide
2019-08-31  1:06     ` JeanHeyd Meneide
2019-09-03 13:31       ` Jonathan Wakely
2019-09-04 22:47         ` JeanHeyd Meneide
2019-09-05 11:27           ` Jonathan Wakely [this message]
2019-09-05 13:52             ` Jonathan Wakely
2019-09-09 11:12               ` Jonathan Wakely

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190905112747.GM9487@redhat.com \
    --to=jwakely@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    --cc=phdofthehouse@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).