public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org>
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]
Date: Fri,  1 Oct 2021 19:38:29 +0000 (GMT)	[thread overview]
Message-ID: <20211001193829.173693857810@sourceware.org> (raw)

https://gcc.gnu.org/g:d335d73889d897d073b987b4323db05317fccad3

commit r12-4063-gd335d73889d897d073b987b4323db05317fccad3
Author: Jonathan Wakely <jwakely@redhat.com>
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 <jwakely@redhat.com>
    
    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<typename _Iter>
@@ -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 <iterator>
+
+template<typename T, bool Nothrow>
+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<typename U>
+    bidi(const bidi<U, Nothrow>& iter) noexcept(Nothrow) : ptr(iter.ptr) { }
+
+  bidi& operator=(const bidi& iter) noexcept(Nothrow)
+  {
+    ptr = iter.ptr;
+    return *this;
+  }
+
+  template<typename U>
+  bidi& operator=(const bidi<U, Nothrow>& 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<int, true>;
+  using R1 = std::reverse_iterator<B1>;
+  static_assert( std::is_nothrow_default_constructible<R1>(), "" );
+  static_assert( std::is_nothrow_copy_constructible<R1>(), "" );
+  static_assert( std::is_nothrow_move_constructible<R1>(), "" );
+  static_assert( std::is_nothrow_copy_assignable<R1>(), "" );
+  static_assert( std::is_nothrow_move_assignable<R1>(), "" );
+  static_assert( std::is_nothrow_constructible<R1, const B1&>(), "" );
+  static_assert( std::is_nothrow_constructible<R1, B1>(), "" );
+
+  using B2 = bidi<const int, true>;
+  using R2 = std::reverse_iterator<B2>;
+  // Test conversions from reverse_iterator<B1> to reverse_iterator<B2>.
+  static_assert( std::is_nothrow_constructible<R2, const R1&>(), "" );
+  static_assert( std::is_nothrow_assignable<R2&, const R1&>(), "" );
+  // And from B1 to reverse_iterator<B2>.
+  static_assert( std::is_nothrow_constructible<R2, const B2&>(), "" );
+  static_assert( std::is_nothrow_constructible<R2, B2>(), "" );
+  static_assert( std::is_nothrow_constructible<R2, const B1&>(), "" );
+  static_assert( std::is_nothrow_constructible<R2, B1>(), "" );
+
+  using B3 = bidi<int, false>;
+  using R3 = std::reverse_iterator<B3>;
+  static_assert( ! std::is_nothrow_default_constructible<R3>(), "" );
+  static_assert( ! std::is_nothrow_copy_constructible<R3>(), "" );
+  static_assert( ! std::is_nothrow_move_constructible<R3>(), "" );
+  static_assert( ! std::is_nothrow_copy_assignable<R3>(), "" );
+  static_assert( ! std::is_nothrow_move_assignable<R3>(), "" );
+  static_assert( ! std::is_nothrow_constructible<R3, const B3&>(), "" );
+  static_assert( ! std::is_nothrow_constructible<R3, B3>(), "" );
+
+  using B4 = bidi<const int, false>;
+  using R4 = std::reverse_iterator<B4>;
+  // Test conversions from reverse_iterator<B3> to reverse_iterator<B4>.
+  static_assert( ! std::is_nothrow_constructible<R4, const R3&>(), "" );
+  static_assert( ! std::is_nothrow_assignable<R4&, const R3&>(), "" );
+  // And from B3 to reverse_iterator<B4>.
+  static_assert( ! std::is_nothrow_constructible<R4, const B4&>(), "" );
+  static_assert( ! std::is_nothrow_constructible<R4, B4>(), "" );
+  static_assert( ! std::is_nothrow_constructible<R4, const B3&>(), "" );
+  static_assert( ! std::is_nothrow_constructible<R4, B3>(), "" );
+
+  static_assert( noexcept(std::declval<R1&>().base()), "" );
+  static_assert( ! noexcept(std::declval<R3&>().base()), "" );
+}


                 reply	other threads:[~2021-10-01 19:38 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211001193829.173693857810@sourceware.org \
    --to=redi@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    --cc=libstdc++-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).