diff mbox series

[committed] libstdc++: Add noexcept to std::begin etc as per LWG 2280 and 3537

Message ID YFi+mDUILzASQiHE@redhat.com
State New
Headers show
Series [committed] libstdc++: Add noexcept to std::begin etc as per LWG 2280 and 3537 | expand

Commit Message

Jonathan Wakely March 22, 2021, 3:58 p.m. UTC
This implements the proposed changes for LWG 3537 (which we're allowed
to do as an extension whatever the outcome of the issue). I noticed we
didn't implement LWG 2280 completely, as the std::begin and std::end
overloads for arrays were not noexcept.

libstdc++-v3/ChangeLog:

	* include/bits/range_access.h (begin(T (&)[N]), end(T (&)[N])):
	Add missing 'noexcept' as per LWG 2280.
	(rbegin(T (&)[N]), rend(T (&)[N]), rbegin(initializer_list<T>))
	(rend(initializer_list<T>)): Add 'noexcept' as per LWG 3537.
	* testsuite/24_iterators/range_access/range_access.cc: Check for
	expected noexcept specifiers. Check result types of generic
	std::begin and std::end overloads.
	* testsuite/24_iterators/range_access/range_access_cpp14.cc:
	Check for expected noexcept specifiers.
	* testsuite/24_iterators/range_access/range_access_cpp17.cc:
	Likewise.

Tested powerpc64le-linux. Committed to trunk.

I've pushed this now because the missing piece of LWG 2280 is a
conformance bug for C++14 and later, and adding these is obviously
safe to do now.
commit 00b46c00c8d9003c61e8f817668ad3380e16fedb
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Mar 22 15:15:12 2021

    libstdc++: Add noexcept to std::begin etc as per LWG 2280 and 3537
    
    This implements the proposed changes for LWG 3537 (which we're allowed
    to do as an extension whatever the outcome of the issue). I noticed we
    didn't implement LWG 2280 completely, as the std::begin and std::end
    overloads for arrays were not noexcept.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/range_access.h (begin(T (&)[N]), end(T (&)[N])):
            Add missing 'noexcept' as per LWG 2280.
            (rbegin(T (&)[N]), rend(T (&)[N]), rbegin(initializer_list<T>))
            (rend(initializer_list<T>)): Add 'noexcept' as per LWG 3537.
            * testsuite/24_iterators/range_access/range_access.cc: Check for
            expected noexcept specifiers. Check result types of generic
            std::begin and std::end overloads.
            * testsuite/24_iterators/range_access/range_access_cpp14.cc:
            Check for expected noexcept specifiers.
            * testsuite/24_iterators/range_access/range_access_cpp17.cc:
            Likewise.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index ab26b64e44c..71ad28c3ab0 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -87,7 +87,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp, size_t _Nm>
     inline _GLIBCXX14_CONSTEXPR _Tp*
-    begin(_Tp (&__arr)[_Nm])
+    begin(_Tp (&__arr)[_Nm]) noexcept
     { return __arr; }
 
   /**
@@ -97,7 +97,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp, size_t _Nm>
     inline _GLIBCXX14_CONSTEXPR _Tp*
-    end(_Tp (&__arr)[_Nm])
+    end(_Tp (&__arr)[_Nm]) noexcept
     { return __arr + _Nm; }
 
 #if __cplusplus >= 201402L
@@ -178,7 +178,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp, size_t _Nm>
     inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Tp*>
-    rbegin(_Tp (&__arr)[_Nm])
+    rbegin(_Tp (&__arr)[_Nm]) noexcept
     { return reverse_iterator<_Tp*>(__arr + _Nm); }
 
   /**
@@ -188,7 +188,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp, size_t _Nm>
     inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Tp*>
-    rend(_Tp (&__arr)[_Nm])
+    rend(_Tp (&__arr)[_Nm]) noexcept
     { return reverse_iterator<_Tp*>(__arr); }
 
   /**
@@ -198,7 +198,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp>
     inline _GLIBCXX17_CONSTEXPR reverse_iterator<const _Tp*>
-    rbegin(initializer_list<_Tp> __il)
+    rbegin(initializer_list<_Tp> __il) noexcept
     { return reverse_iterator<const _Tp*>(__il.end()); }
 
   /**
@@ -208,7 +208,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp>
     inline _GLIBCXX17_CONSTEXPR reverse_iterator<const _Tp*>
-    rend(initializer_list<_Tp> __il)
+    rend(initializer_list<_Tp> __il) noexcept
     { return reverse_iterator<const _Tp*>(__il.begin()); }
 
   /**
diff --git a/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc b/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
index 2380b1e0e31..b0b379c6ea5 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
@@ -27,4 +27,34 @@  test01()
   int arr[3] = {1, 2, 3};
   std::begin(arr);
   std::end(arr);
+
+  static_assert( noexcept(std::begin(arr)), "LWG 2280" );
+  static_assert( noexcept(std::end(arr)), "LWG 2280" );
+}
+
+void
+test02()
+{
+  extern void require_int(int*);
+  extern void require_long(long*);
+
+  struct B
+  {
+    int* begin() { return nullptr; }
+    long* begin() const { return nullptr; }
+  };
+
+  B b;
+  require_int( std::begin(b) );
+  require_long( std::begin(const_cast<const B&>(b)) );
+
+  struct E
+  {
+    int* end() { return nullptr; }
+    long* end() const { return nullptr; }
+  };
+
+  E e;
+  require_int( std::end(e) );
+  require_long( std::end(const_cast<const E&>(e)) );
 }
diff --git a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp14.cc b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp14.cc
index 5a235de1678..75531719eeb 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp14.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp14.cc
@@ -39,10 +39,21 @@  void
 test02()
 {
   static int i[1];
+  // LWG 2280
   constexpr auto b  __attribute__((unused)) = std::begin(i);
   constexpr auto e  __attribute__((unused)) = std::end(i);
   constexpr auto cb __attribute__((unused)) = std::cbegin(i);
   constexpr auto ce __attribute__((unused)) = std::cend(i);
+
+  // LWG 2280
+  static_assert( noexcept(std::begin(i)),  "LWG 2280" );
+  static_assert( noexcept(std::end(i)),    "LWG 2280" );
+  static_assert( noexcept(std::cbegin(i)), "LWG 2280" );
+  static_assert( noexcept(std::cend(i)),   "LWG 2280" );
+
+  // LWG 3537
+  static_assert( noexcept(std::rbegin(i)),  "LWG 3537" );
+  static_assert( noexcept(std::rend(i)),    "LWG 3537" );
 }
 
 void
@@ -55,6 +66,10 @@  test03()
   VERIFY(std::rend(il) == std::reverse_iterator<const int*>(il.begin()));
   VERIFY(std::crbegin(il) == std::reverse_iterator<const int*>(il.end()));
   VERIFY(std::crend(il) == std::reverse_iterator<const int*>(il.begin()));
+
+  // LWG 3537
+  static_assert( noexcept(std::rbegin(il)),  "LWG 3537" );
+  static_assert( noexcept(std::rend(il)),    "LWG 3537" );
 }
 
 void
diff --git a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp17.cc b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp17.cc
index 481a52a1606..358e19345e1 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp17.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp17.cc
@@ -41,6 +41,16 @@  test02()
   static int i[] = { 1, 2 };
   static_assert(std::distance(std::begin(i), std::end(i)) == 2);
   static_assert(std::distance(std::cbegin(i), std::cend(i)) == 2);
+
+  // LWG 2280
+  static_assert( noexcept(std::begin(i)),  "LWG 2280" );
+  static_assert( noexcept(std::end(i)),    "LWG 2280" );
+  static_assert( noexcept(std::cbegin(i)), "LWG 2280" );
+  static_assert( noexcept(std::cend(i)),   "LWG 2280" );
+
+  // LWG 3537
+  static_assert( noexcept(std::rbegin(i)),  "LWG 3537" );
+  static_assert( noexcept(std::rend(i)),    "LWG 3537" );
 }
 
 void
@@ -54,4 +64,8 @@  test03()
   static_assert(std::rend(il) == reverse_iterator<const int*>(il.begin()));
   static_assert(std::crbegin(il) == reverse_iterator<const int*>(il.end()));
   static_assert(std::crend(il) == reverse_iterator<const int*>(il.begin()));
+
+  // LWG 3537
+  static_assert( noexcept(std::rbegin(il)),  "LWG 3537" );
+  static_assert( noexcept(std::rend(il)),    "LWG 3537" );
 }