From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 173693857810; Fri, 1 Oct 2021 19:38:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 173693857810 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-4063] libstdc++: Use conditional noexcept in std::reverse_iterator [PR 94418] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 681707ec28d56494fa61a80c62500724d55f8586 X-Git-Newrev: d335d73889d897d073b987b4323db05317fccad3 Message-Id: <20211001193829.173693857810@sourceware.org> Date: Fri, 1 Oct 2021 19:38:29 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Oct 2021 19:38:29 -0000 https://gcc.gnu.org/g:d335d73889d897d073b987b4323db05317fccad3 commit r12-4063-gd335d73889d897d073b987b4323db05317fccad3 Author: Jonathan Wakely Date: Wed Apr 28 11:40:47 2021 +0100 libstdc++: Use conditional noexcept in std::reverse_iterator [PR 94418] This adds a noexcept-specifier to each constructor and assignment operator of std::reverse_iterator so that they are noexcept when the corresponding operation on the underlying iterator is noexcept. The std::reverse_iterator class template already requires that the operations on the underlying type are valid, so we don't need to use the std::is_nothrow_xxx traits to protect against errors when the expression isn't even valid. We can just use a noexcept operator to test if the expression can throw, without the overhead of redundantly checking if the initialization/assignment would be valid. Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: PR libstdc++/94418 * include/bits/stl_iterator.h (reverse_iterator): Use conditional noexcept on constructors and assignment operators. * testsuite/24_iterators/reverse_iterator/noexcept.cc: New test. Diff: --- libstdc++-v3/include/bits/stl_iterator.h | 20 ++++- .../24_iterators/reverse_iterator/noexcept.cc | 92 ++++++++++++++++++++++ 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 004d767224d..4973f792b56 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -174,20 +174,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 235 No specification of default ctor for reverse_iterator // 1012. reverse_iterator default ctor should value initialize _GLIBCXX17_CONSTEXPR - reverse_iterator() : current() { } + reverse_iterator() + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator())) + : current() + { } /** * This %iterator will move in the opposite direction that @p x does. */ explicit _GLIBCXX17_CONSTEXPR - reverse_iterator(iterator_type __x) : current(__x) { } + reverse_iterator(iterator_type __x) + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x))) + : current(__x) + { } /** * The copy constructor is normal. */ _GLIBCXX17_CONSTEXPR reverse_iterator(const reverse_iterator& __x) - : current(__x.current) { } + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x.current))) + : current(__x.current) + { } #if __cplusplus >= 201103L reverse_iterator& operator=(const reverse_iterator&) = default; @@ -203,7 +211,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif _GLIBCXX17_CONSTEXPR reverse_iterator(const reverse_iterator<_Iter>& __x) - : current(__x.current) { } + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x.current))) + : current(__x.current) + { } #if __cplusplus >= 201103L template @@ -214,6 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX17_CONSTEXPR reverse_iterator& operator=(const reverse_iterator<_Iter>& __x) + _GLIBCXX_NOEXCEPT_IF(noexcept(current = __x.current)) { current = __x.current; return *this; @@ -226,6 +237,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD _GLIBCXX17_CONSTEXPR iterator_type base() const + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(current))) { return current; } /** diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc new file mode 100644 index 00000000000..df4b1b0763d --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc @@ -0,0 +1,92 @@ +// { dg-do compile { target c++11 } } + +#include + +template +struct bidi +{ + using value_type = T; + using pointer = T*; + using reference = T&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + + T* ptr; + + bidi(T* ptr = nullptr) noexcept(Nothrow) : ptr(ptr) { } + + bidi(const bidi& iter) noexcept(Nothrow) : ptr(iter.ptr) { } + + template + bidi(const bidi& iter) noexcept(Nothrow) : ptr(iter.ptr) { } + + bidi& operator=(const bidi& iter) noexcept(Nothrow) + { + ptr = iter.ptr; + return *this; + } + + template + bidi& operator=(const bidi& iter) noexcept(Nothrow) + { + ptr = iter.ptr; + return *this; + } + + bidi& operator++() { ++ptr; return *this; } + bidi& operator--() { --ptr; return *this; } + bidi operator++(int) { bidi tmp = *this; ++ptr; return tmp; } + bidi operator--(int) { bidi tmp = *this; --ptr; return tmp; } + + reference operator*() const { return *ptr; } + pointer operator->() const { return ptr; } +}; + +void +test01() +{ + using B1 = bidi; + using R1 = std::reverse_iterator; + static_assert( std::is_nothrow_default_constructible(), "" ); + static_assert( std::is_nothrow_copy_constructible(), "" ); + static_assert( std::is_nothrow_move_constructible(), "" ); + static_assert( std::is_nothrow_copy_assignable(), "" ); + static_assert( std::is_nothrow_move_assignable(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + + using B2 = bidi; + using R2 = std::reverse_iterator; + // Test conversions from reverse_iterator to reverse_iterator. + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_assignable(), "" ); + // And from B1 to reverse_iterator. + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + + using B3 = bidi; + using R3 = std::reverse_iterator; + static_assert( ! std::is_nothrow_default_constructible(), "" ); + static_assert( ! std::is_nothrow_copy_constructible(), "" ); + static_assert( ! std::is_nothrow_move_constructible(), "" ); + static_assert( ! std::is_nothrow_copy_assignable(), "" ); + static_assert( ! std::is_nothrow_move_assignable(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + + using B4 = bidi; + using R4 = std::reverse_iterator; + // Test conversions from reverse_iterator to reverse_iterator. + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_assignable(), "" ); + // And from B3 to reverse_iterator. + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + + static_assert( noexcept(std::declval().base()), "" ); + static_assert( ! noexcept(std::declval().base()), "" ); +}