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.
This commit is contained in:
Jonathan Wakely 2021-03-22 15:15:12 +00:00
parent 87e3c2ef68
commit 00b46c00c8
4 changed files with 65 additions and 6 deletions

View File

@ -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()); }
/**

View File

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

View File

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

View File

@ -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" );
}