As an extension, this adds conditional noexcept to std::begin, std::end,
and std::ssize.
libstdc++-v3/ChangeLog:
* include/bits/range_access.h (begin, end, ssize): Add
conditional noexcept.
* testsuite/18_support/initializer_list/range_access.cc: Check
results and noexcept-specifier for std::begin and std::end.
* testsuite/24_iterators/headers/iterator/range_access_c++11.cc:
Check for conditional noexcept on std::begin and std::end.
* testsuite/24_iterators/headers/iterator/range_access_c++14.cc:
Likewise.
* testsuite/24_iterators/headers/iterator/range_access_c++17.cc:
Likewise.
* testsuite/24_iterators/range_access/range_access.cc: Check
conditional noexcept is correct.
* testsuite/24_iterators/range_access/range_access_cpp17.cc:
Check std::size, std::empty and std::data.
* testsuite/24_iterators/range_access/range_access_cpp20.cc:
Check conditional noexcept on std::ssize.
---
I plan to push this when testing finishes.
libstdc++-v3/include/bits/range_access.h | 15 +++--
.../initializer_list/range_access.cc | 10 ++++
.../headers/iterator/range_access_c++11.cc | 15 +++--
.../headers/iterator/range_access_c++14.cc | 15 +++--
.../headers/iterator/range_access_c++17.cc | 15 +++--
.../24_iterators/range_access/range_access.cc | 18 ++++++
.../range_access/range_access_cpp17.cc | 57 +++++++++++++++++++
.../range_access/range_access_cpp20.cc | 8 ++-
8 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/libstdc++-v3/include/bits/range_access.h
b/libstdc++-v3/include/bits/range_access.h
index 2dacbedfa53..ae58710e4a2 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -51,7 +51,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Container>
[[__nodiscard__, __gnu__::__always_inline__]]
inline _GLIBCXX17_CONSTEXPR auto
- begin(_Container& __cont) -> decltype(__cont.begin())
+ begin(_Container& __cont) noexcept(noexcept(__cont.begin()))
+ -> decltype(__cont.begin())
{ return __cont.begin(); }
/**
@@ -62,7 +63,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Container>
[[__nodiscard__, __gnu__::__always_inline__]]
inline _GLIBCXX17_CONSTEXPR auto
- begin(const _Container& __cont) -> decltype(__cont.begin())
+ begin(const _Container& __cont) noexcept(noexcept(__cont.begin()))
+ -> decltype(__cont.begin())
{ return __cont.begin(); }
/**
@@ -73,7 +75,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Container>
[[__nodiscard__, __gnu__::__always_inline__]]
inline _GLIBCXX17_CONSTEXPR auto
- end(_Container& __cont) -> decltype(__cont.end())
+ end(_Container& __cont) noexcept(noexcept(__cont.end()))
+ -> decltype(__cont.end())
{ return __cont.end(); }
/**
@@ -84,7 +87,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Container>
[[__nodiscard__, __gnu__::__always_inline__]]
inline _GLIBCXX17_CONSTEXPR auto
- end(const _Container& __cont) -> decltype(__cont.end())
+ end(const _Container& __cont) noexcept(noexcept(__cont.end()))
+ -> decltype(__cont.end())
{ return __cont.end(); }
/**
@@ -351,8 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Container>
[[nodiscard, __gnu__::__always_inline__]]
constexpr auto
- ssize(const _Container& __cont)
- noexcept(noexcept(__cont.size()))
+ ssize(const _Container& __cont) noexcept(noexcept(__cont.size()))
-> common_type_t<ptrdiff_t, make_signed_t<decltype(__cont.size())>>
{
using type = make_signed_t<decltype(__cont.size())>;
diff --git a/libstdc++-v3/testsuite/18_support/initializer_list/range_access.cc
b/libstdc++-v3/testsuite/18_support/initializer_list/range_access.cc
index ca572dc25df..3d4e2fefd39 100644
--- a/libstdc++-v3/testsuite/18_support/initializer_list/range_access.cc
+++ b/libstdc++-v3/testsuite/18_support/initializer_list/range_access.cc
@@ -27,3 +27,13 @@ test01()
std::begin({1, 2, 3});
std::end({1, 2, 3});
}
+
+void
+test02()
+{
+ static constexpr std::initializer_list<int> il{1};
+ static_assert( std::begin(il) == il.begin() );
+ static_assert( std::end(il) == il.end() );
+ static_assert( noexcept(std::begin(il)) );
+ static_assert( noexcept(std::end(il)) );
+}
diff --git
a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++11.cc
b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++11.cc
index 448e86bce2f..89143d5dfa0 100644
--- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++11.cc
+++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++11.cc
@@ -20,13 +20,20 @@
#include <iterator>
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
namespace std
{
- template<class C> auto begin(C& c) -> decltype(c.begin());
- template<class C> auto begin(const C& c) -> decltype(c.begin());
+ template<class C> auto begin(C& c) NOTHROW(begin) -> decltype(c.begin());
+ template<class C> auto begin(const C& c) NOTHROW(begin) ->
decltype(c.begin());
- template<class C> auto end(C& c) -> decltype(c.end());
- template<class C> auto end(const C& c) -> decltype(c.end());
+ template<class C> auto end(C& c) NOTHROW(end) -> decltype(c.end());
+ template<class C> auto end(const C& c) NOTHROW(end) -> decltype(c.end());
template<class T, size_t N> T* begin(T (&array)[N]) noexcept;
template<class T, size_t N> T* end(T (&array)[N]) noexcept;
diff --git
a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++14.cc
b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++14.cc
index 1bbe4ad2c59..2c803dba3e5 100644
--- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++14.cc
+++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++14.cc
@@ -20,13 +20,20 @@
#include <iterator>
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
namespace std
{
- template<class C> auto begin(C& c) -> decltype(c.begin());
- template<class C> auto begin(const C& c) -> decltype(c.begin());
+ template<class C> auto begin(C& c) NOTHROW(begin) -> decltype(c.begin());
+ template<class C> auto begin(const C& c) NOTHROW(begin) ->
decltype(c.begin());
- template<class C> auto end(C& c) -> decltype(c.end());
- template<class C> auto end(const C& c) -> decltype(c.end());
+ template<class C> auto end(C& c) NOTHROW(end) -> decltype(c.end());
+ template<class C> auto end(const C& c) NOTHROW(end) -> decltype(c.end());
template<class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept;
template<class T, size_t N> constexpr T* end(T (&array)[N]) noexcept;
diff --git
a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++17.cc
b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++17.cc
index 54e10b5616e..573d9f9fa7a 100644
--- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++17.cc
+++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++17.cc
@@ -19,13 +19,20 @@
#include <iterator>
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
namespace std
{
- template<class C> constexpr auto begin(C& c) -> decltype(c.begin());
- template<class C> constexpr auto begin(const C& c) -> decltype(c.begin());
+ template<class C> constexpr auto begin(C& c) NOTHROW(begin) ->
decltype(c.begin());
+ template<class C> constexpr auto begin(const C& c) NOTHROW(begin) ->
decltype(c.begin());
- template<class C> constexpr auto end(C& c) -> decltype(c.end());
- template<class C> constexpr auto end(const C& c) -> decltype(c.end());
+ template<class C> constexpr auto end(C& c) NOTHROW(end) -> decltype(c.end());
+ template<class C> constexpr auto end(const C& c) NOTHROW(end) ->
decltype(c.end());
template<class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept;
template<class T, size_t N> constexpr T* end(T (&array)[N]) noexcept;
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 66994b607a2..5ed6bfbd51a 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
@@ -57,4 +57,22 @@ test02()
E e;
require_int( std::end(e) );
require_long( std::end(const_cast<const E&>(e)) );
+
+ static_assert( ! noexcept(std::begin(b)), "throws" );
+ static_assert( ! noexcept(std::begin(const_cast<const B&>(b))), "throws" );
+ static_assert( ! noexcept(std::end(e)), "throws" );
+ static_assert( ! noexcept(std::end(const_cast<const E&>(e))), "throws" );
+
+ struct S
+ {
+ int* begin() noexcept { return nullptr; }
+ int* begin() const noexcept { return nullptr; }
+ int* end() noexcept { return nullptr; }
+ int* end() const noexcept { return nullptr; }
+ };
+ S s;
+ static_assert( noexcept(std::begin(s)), "nothrow" );
+ static_assert( noexcept(std::begin(const_cast<const S&>(s))), "nothrow" );
+ static_assert( noexcept(std::end(s)), "nothrow" );
+ static_assert( noexcept(std::end(const_cast<const S&>(s))), "nothrow" );
}
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 ea4fb756806..50d15c91601 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
@@ -68,3 +68,60 @@ test03()
static_assert( noexcept(std::rbegin(il)), "LWG 3537" );
static_assert( noexcept(std::rend(il)), "LWG 3537" );
}
+
+void
+test04()
+{
+ static int i[1]{};
+ static_assert( std::size(i) == 1 );
+ static_assert( noexcept(std::size(i)) );
+ static const int ci[2]{};
+ static_assert( std::size(ci) == 2 );
+ static_assert( noexcept(std::size(ci)) );
+ static constexpr std::initializer_list<int> il{1, 2, 3};
+ static_assert( std::size(il) == 3 );
+ struct Cont
+ {
+ constexpr unsigned size() const { return 4; }
+ };
+ constexpr Cont c;
+ static_assert( std::size(c) == 4 );
+}
+
+void
+test05()
+{
+ static int i[1]{};
+ static_assert( std::empty(i) == false );
+ static_assert( noexcept(std::size(i)) );
+ static const int ci[2]{};
+ static_assert( std::empty(ci) == false );
+ static_assert( noexcept(std::size(ci)) );
+ static constexpr std::initializer_list<int> il{1, 2, 3};
+ static_assert( std::empty(il) == false );
+ struct Cont
+ {
+ constexpr bool empty() const { return true; }
+ };
+ constexpr Cont c;
+ static_assert( std::empty(c) == true );
+}
+
+void
+test06()
+{
+ static int i[1]{};
+ static_assert( std::data(i) == i );
+ static_assert( noexcept(std::size(i)) );
+ static const int ci[2]{};
+ static_assert( std::data(ci) == ci );
+ static_assert( noexcept(std::size(ci)) );
+ static constexpr std::initializer_list<int> il{1, 2, 3};
+ static_assert( std::data(il) == il.begin() );
+ struct Cont
+ {
+ constexpr int* data() const { return nullptr; }
+ };
+ constexpr Cont c;
+ static_assert( std::data(c) == nullptr );
+}
diff --git
a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp20.cc
b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp20.cc
index 5b6bc370f01..8148d6c80ef 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp20.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp20.cc
@@ -44,12 +44,16 @@ test03()
{
struct Cont
{
- constexpr unsigned short size() const { return 3; }
+ constexpr unsigned short size() const noexcept { return 3; }
};
constexpr Cont c;
constexpr auto s = std::ssize(c);
const std::ptrdiff_t* check_type = &s;
static_assert(s == 3);
+
+#ifdef _GLIBCXX_RELEASE
+ static_assert( noexcept(std::ssize(c)) ); // This is a libstdc++ extension.
+#endif
}
void
@@ -63,4 +67,6 @@ test04()
constexpr auto s = std::ssize(c);
const long long* check_type = &s;
static_assert(s == 4);
+
+ static_assert( ! noexcept(std::ssize(c)) );
}
--
2.47.0