From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 84766 invoked by alias); 5 Sep 2019 11:27:59 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 84750 invoked by uid 89); 5 Sep 2019 11:27:58 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.4 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,SPF_HELO_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 05 Sep 2019 11:27:51 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2072B30860A5; Thu, 5 Sep 2019 11:27:49 +0000 (UTC) Received: from localhost (unknown [10.33.36.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 70E2C5D9CA; Thu, 5 Sep 2019 11:27:48 +0000 (UTC) Date: Thu, 05 Sep 2019 11:27:00 -0000 From: Jonathan Wakely To: JeanHeyd Meneide Cc: gcc-patches@gcc.gnu.org, libstdc++ Subject: Re: [ PATCH ] C++20 Message-ID: <20190905112747.GM9487@redhat.com> References: <20190830194119.GS9487@redhat.com> <20190903133122.GC9487@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nWEzmRaGLXxZdI3i" Content-Disposition: inline In-Reply-To: X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.0 (2019-05-25) X-SW-Source: 2019-09/txt/msg00282.txt.bz2 --nWEzmRaGLXxZdI3i Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Content-length: 6017 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 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 This header isn't needed. defines std::size_t and std::ptrdiff_t, and every libstdc++ header should include already. Not including is a minor optimisation for compile time, because we don't need to open and . >+ template >+ inline constexpr bool >+ __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true; >+ >+#ifdef _GLIBCXX_DEBUG >+ template >+ inline constexpr bool >+ __is_std_array_v> = true; >+#endif // debug/array >+ >+ template >+ 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(-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 >+ 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; >+ using const_iterator = __gnu_cxx::__normal_iterator; >+ using reverse_iterator = ::std::reverse_iterator; >+ using const_reverse_iterator = ::std::reverse_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; >+ >+ public: >+ // constructors >+ template && (_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+ 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+ enable_if_t< >+ (_Extent == dynamic_extent) && >+ !is_same_v, span> && >+ !__detail::__is_std_array_v> && >+ !is_array_v> && 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, span> && !__detail::__is_std_array_v> && !is_array_v> && ... 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. --nWEzmRaGLXxZdI3i Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" Content-length: 49737 commit 24bcbc6f622c6371d1fdf28bab25f64ff6d2dae1 Author: Jonathan Wakely Date: Thu Sep 5 09:58:09 2019 +0100 Implement std::span for C++20 2019-09-05 JeanHeyd Meneide * include/Makefile.am: Add 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 + constexpr auto + __adl_begin(_Container& __cont) noexcept(noexcept(begin(__cont))) + { return begin(__cont); } + + template + constexpr auto + __adl_end(_Container& __cont) noexcept(noexcept(end(__cont))) + { return end(__cont); } + + template + constexpr auto + __adl_cbegin(_Container& __cont) noexcept(noexcept(cbegin(__cont))) + { return cbegin(__cont); } + + template + constexpr auto + __adl_cend(_Container& __cont) noexcept(noexcept(cend(__cont))) + { return cend(__cont); } + + template + constexpr auto + __adl_rbegin(_Container& __cont) noexcept(noexcept(rbegin(__cont))) + { return rbegin(__cont); } + + template + constexpr auto + __adl_rend(_Container& __cont) noexcept(noexcept(rend(__cont))) + { return rend(__cont); } + + template + constexpr auto + __adl_crbegin(_Container& __cont) noexcept(noexcept(crbegin(__cont))) + { return crbegin(__cont); } + + template + constexpr auto + __adl_crend(_Container& __cont) noexcept(noexcept(crend(__cont))) + { return crend(__cont); } + + template + constexpr auto + __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) + { return data(__cont); } + + template + constexpr auto + __adl_cdata(_Container& __cont) noexcept(noexcept(cdata(__cont))) + { return cdata(__cont); } + + template + constexpr auto + __adl_size(_Container& __cont) noexcept(noexcept(size(__cont))) + { return size(__cont); } + + template + constexpr auto + __adl_empty(_Container& __cont) noexcept(noexcept(empty(__cont))) + { return empty(__cont); } + +#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 + template + constexpr auto + __adl_to_address(_Container& __cont) noexcept(noexcept(to_address(__cont))) + { return to_address(__cont); } +#endif // P1394 and new contiguous_iterator requirements [iterator.concept.contiguous] +#endif // C++20 + _GLIBCXX_END_NAMESPACE_VERSION } // 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 - _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 - _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 + _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 #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 + _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 + _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 + _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 +// . + +/** @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 +#include +#include +#include +#include +#include + +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(-1); + + namespace __detail + { + template + static constexpr inline bool __is_base_derived_safe_convertible_v + = is_convertible_v<_Element (*)[], _ToElement (*)[]>; + + template + inline constexpr bool __is_std_array_v = false; + + template + inline constexpr bool + __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true; + +#ifdef _GLIBCXX_DEBUG + template + inline constexpr bool + __is_std_array_v> = true; +#endif // debug/array + + template + 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(-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 + 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; + using const_iterator + = __gnu_cxx::__normal_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_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; + + public: + // constructors + + template + && (_Extent == dynamic_extent || _Extent == 0)>* = nullptr> + constexpr + span() noexcept : __base_t(0), _M_ptr(nullptr) + { } + + constexpr + span(const span&) noexcept = default; + + template()))>, + element_type>>* = nullptr> + constexpr span(element_type (&__arr)[_ArrayExtent]) + noexcept(noexcept(::std::__adl_data(__arr))) + : span(::std::__adl_data(__arr), _ArrayExtent) + { } + + template&>()))>, + element_type>>* = nullptr> + constexpr + span(array& __arr) + noexcept(noexcept(::std::__adl_data(__arr))) + : span(::std::__adl_data(__arr), _ArrayExtent) + { } + + template&>()))>, + element_type>>* = nullptr> + constexpr + span(const array& __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, span> + && !__detail::__is_std_array_v> + && !is_array_v> + && __detail::__is_base_derived_safe_convertible_v< + remove_pointer_t()) + + ::std::__adl_size(::std::declval<_Range&>()))>, + element_type>>* = nullptr> + 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 + && __detail::__is_base_derived_safe_convertible_v< + remove_reference_t::reference>, + element_type>>* = nullptr> + constexpr + span(_ContiguousIterator __first, _Sentinel __last) + : span(::std::move(__first), static_cast(__last - __first)) + { } + + template + 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, span> + && !__detail::__is_std_array_v> + && !is_array_v> + && __detail::__is_base_derived_safe_convertible_v< + remove_pointer_t()) + + ::std::__adl_size(::std::declval<_Container&>()))>, + element_type>>* = nullptr> + constexpr + span(_Container& __range) + noexcept(noexcept(::std::__adl_data(__range)) + && noexcept(::std::__adl_size(__range))) + : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + { } + + template, span> + && !__detail::__is_std_array_v> + && !is_array_v> + && __detail::__is_base_derived_safe_convertible_v< + remove_pointer_t()) + + ::std::__adl_size(::std::declval<_Container&>()))>, + element_type>>* = nullptr> + constexpr span(const _Container& __range) + noexcept(noexcept(::std::__adl_data(__range)) + && noexcept(::std::__adl_size(__range))) + : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + { } + + constexpr + span(pointer __first, index_type __count) noexcept + : __base_t(__count), _M_ptr(static_cast(__first)) + { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } + + constexpr + span(pointer __first, pointer __last) noexcept + : span(::std::move(__first), static_cast(__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 + constexpr span + first() const + { + __glibcxx_assert(_Count < size()); + return { this->data(), _Count }; + } + + constexpr span + first(index_type __count) const + { + __glibcxx_assert(__count < size()); + return { this->data(), __count }; + } + + template + constexpr span + 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 + last(index_type __count) const + { + __glibcxx_assert(__count < size()); + index_type __offset = (this->size() - __count); + return { this->data() + __offset, __count }; + } + + template + 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; + 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 + 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 + span(_Type(&)[_ArrayExtent])->span<_Type, _ArrayExtent>; + + template + span(array<_Type, _ArrayExtent>&)->span<_Type, _ArrayExtent>; + + template + span(const array<_Type, _ArrayExtent>&) + ->span; + +#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 + + template + span(_ContiguousIterator, _Sentinel) + ->span::reference>>; + + template + span(_Range &&) + ->span()))>::reference>>; + +#else + + template + span(_Container&)->span; + + template + span(const _Container&)->span; + +#endif // P1394 + + template + span + inline as_bytes(span<_Type, _Extent> __sp) noexcept + { + return {reinterpret_cast(__sp.data()), __sp.size_bytes()}; + } + + template + span + as_writable_bytes(span<_Type, _Extent> __sp) noexcept + { + return {reinterpret_cast(__sp.data()), __sp.size_bytes()}; + } + + // tuple helpers + template + 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 + struct tuple_size> + : public integral_constant + { + static_assert(_Extent != dynamic_extent, "tuple_size can only " + "be used with a span of non-dynamic (fixed) extent"); + }; + + template + 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +int +main() +{ + std::deque d{}; + std::span 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do run { target c++2a } } + +#include + +#include +#include +#include +#include +#include +#include + +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) <= sizeof(char*)); + static_assert(sizeof(std::span) <= sizeof(const char*)); + static_assert(sizeof(std::span) <= sizeof(strawman*)); + static_assert(sizeof(std::span) <= sizeof(strawman*)); + static_assert(sizeof(std::span) <= sizeof(naked_span)); + static_assert(sizeof(std::span) <= sizeof(strawman_span)); + + constexpr static std::array 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::span>); + 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 == 3); + static_assert(std::is_same_v, const int>); + + constexpr auto data_span_first_dyn = data_span.first(4); + static_assert( + std::is_same_v, std::span>); + 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::span>); + 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 == 5); + static_assert(std::is_same_v, const int>); + + constexpr auto data_span_last_dyn = data_span.last(6); + static_assert( + std::is_same_v, std::span>); + 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::span>); + 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::span>); + 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::span>); + 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::span>); + static_assert(decltype(data_span_subspan_empty_static)::extent == 0); + static_assert(data_span_subspan_empty.size() == 0); + + std::span 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 value{ 0 }; + std::span muh_span(value); + VERIFY(muh_span.size() == 1); + std::byte* original_bytes = reinterpret_cast(value.data()); + original_bytes[0] = static_cast(1); + original_bytes[1] = static_cast(2); + original_bytes[2] = static_cast(3); + original_bytes[3] = static_cast(4); + std::span muh_byte_span = std::as_bytes(muh_span); + std::span muh_mutable_byte_span = std::as_writable_bytes(muh_span); + std::span 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 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +int +main() +{ + std::span 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include + +int +main() +{ + std::span 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include + +int +main() +{ + std::span 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +std::tuple_element<0, std::span> 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +std::tuple_element<3, std::span> 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 +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +std::tuple_size> ts; // { dg-error "here" } +// { dg-error "static assertion failed" "" { target *-*-* } 0 } --nWEzmRaGLXxZdI3i--