libstdc++: Correct noexcept-specifiers on span constructors

Message ID 20191210234945.GA2095928@redhat.com
State New
Headers show
Series
  • libstdc++: Correct noexcept-specifiers on span constructors
Related show

Commit Message

Jonathan Wakely Dec. 10, 2019, 11:49 p.m.
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 <jwakely@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.

Patch

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