As discussed at https://github.com/cplusplus/draft/issues/3534 two std::span constructors specify incorrect conditions for throwing exceptions. This patch makes those constructors have correct noexcept-specifiers that accurately reflect what can actually throw.
(span(ContiguousIterator, Sentinel)): Add conditional noexcept. * include/std/span (span(ContiguousIterator, size_type)): Change noexcept to be unconditionally true. * testsuite/23_containers/span/nothrow_cons.cc: New test. Tested x86_64-linux, committed to trunk.
commit a1cc0205b3a297db1399519f5169a6a1f245a421 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Dec 10 23:39:22 2019 +0000 libstdc++: Correct noexcept-specifiers on span constructors As discussed at https://github.com/cplusplus/draft/issues/3534 two std::span constructors specify incorrect conditions for throwing exceptions. This patch makes those constructors have correct noexcept-specifiers that accurately reflect what can actually throw. (span(ContiguousIterator, Sentinel)): Add conditional noexcept. * include/std/span (span(ContiguousIterator, size_type)): Change noexcept to be unconditionally true. * testsuite/23_containers/span/nothrow_cons.cc: New test. diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index ecce0b33b0b..6328ecbcde5 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -210,6 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && (!is_convertible_v<_Sentinel, size_type>) constexpr span(_ContiguousIterator __first, _Sentinel __last) + noexcept(noexcept(__last - __first)) : _M_extent(static_cast<size_type>(__last - __first)), _M_ptr(std::to_address(__first)) { @@ -221,7 +222,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires (__is_compatible_iterator<_ContiguousIterator>::value) constexpr span(_ContiguousIterator __first, size_type __count) - noexcept(noexcept(std::to_address(__first))) + noexcept : _M_extent(__count), _M_ptr(std::to_address(__first)) { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } diff --git a/libstdc++-v3/testsuite/23_containers/span/nothrow_cons.cc b/libstdc++-v3/testsuite/23_containers/span/nothrow_cons.cc new file mode 100644 index 00000000000..f28a3386aaf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/span/nothrow_cons.cc @@ -0,0 +1,59 @@ +// 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=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <span> + +using std::span; +using std::is_nothrow_constructible_v; + +static_assert( is_nothrow_constructible_v<span<int>> ); +static_assert( is_nothrow_constructible_v<span<int, 0>> ); + +static_assert( is_nothrow_constructible_v<span<int>, span<int>&> ); +static_assert( is_nothrow_constructible_v<span<const int>, span<int>&> ); +static_assert( is_nothrow_constructible_v<span<int>, span<int, 1>&> ); +static_assert( is_nothrow_constructible_v<span<const int>, span<int, 1>&> ); +static_assert( is_nothrow_constructible_v<span<int, 1>, span<int, 1>&> ); +static_assert( is_nothrow_constructible_v<span<const int, 1>, span<int, 1>&> ); + +static_assert( is_nothrow_constructible_v<span<int>, int(&)[1]> ); +static_assert( is_nothrow_constructible_v<span<int, 1>, int(&)[1]> ); +static_assert( is_nothrow_constructible_v<span<int>, std::array<int, 1>&> ); +static_assert( is_nothrow_constructible_v<span<int, 1>, std::array<int, 1>&> ); + +template<bool> +struct sentinel { int* p; }; + +template<bool B> +bool operator==(sentinel<B> s, int* p) noexcept { return s.p == p; } + +template<bool B> +std::ptrdiff_t operator-(sentinel<B> s, int* p) noexcept(B) { return s.p - p; } + +template<bool B> +std::ptrdiff_t operator-(int* p, sentinel<B> s) noexcept { return p - s.p; } + +static_assert(std::sized_sentinel_for<sentinel<true>, int*>); +static_assert(std::sized_sentinel_for<sentinel<false>, int*>); + +static_assert(is_nothrow_constructible_v<span<int>, int*, std::size_t>); +static_assert(is_nothrow_constructible_v<span<int>, int*, const int*>); +static_assert(is_nothrow_constructible_v<span<int>, int*, sentinel<true>>); +static_assert(!is_nothrow_constructible_v<span<int>, int*, sentinel<false>>);