This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Make safe_iterator inline friends


On 28/08/2018 21:04, Jonathan Wakely wrote:
On 23/08/18 22:59 +0200, François Dumont wrote:
On 22/08/2018 23:45, Jonathan Wakely wrote:
On 22/08/18 23:08 +0200, François Dumont wrote:
Only operator== and != remains outside _Safe_iterator because all my attempts to make them inline friends failed. I understand that an inline friend within a base class is not a very clean design.

Compiler error was:

/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:459: error: redefinition of 'bool __gnu_debug::operator==(const _Self&, const _OtherSelf&)' /home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:452: note: 'bool __gnu_debug::operator==(const _Self&, const _Self&)' previously declared here /home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:473: error: redefinition of 'bool __gnu_debug::operator!=(const _Self&, const _OtherSelf&)' /home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:466: note: 'bool __gnu_debug::operator!=(const _Self&, const _Self&)' previously declared here

I don't know if it is a compiler issue

I don't think so. The error seems clear: when _Self and _OtherSelf are
the same type the friend declarations are the same function.


_Self and _OtherSelf and like the types defined in _Safe_iterator<_It, _Sq, random_access_interator_tag> in this patch. Depending on __conditional_type so definitely different.

What about containers like std::set where iterator and const_iterator
are the same type?

Good idear but no, it is not that.

It really looks like g++ consider the inline friend definition in the context of the instantiation of _Safe_iterator<It, Seq, std::forward_access_iterator_tag> but also in the context of _Safe_iterator<t, Seq, std::bidirectionnal_iterator_tag> and same for RAI.

I don't know if this behavior is correct or not but for sure it is not a clean design so I would prefer to avoid it keeping those operators in __gnu_debug namespace. Attach is my attempt to inline those if you want to have a closer look and maybe fill a compiler bug entry.

However I considered this good remark to constraint even more the conversion constructor iterator -> const_iterator, the new patch is attached.


There's no changelog in the email with the patch

    * include/debug/safe_iterator.h
    (_Safe_iterator<_It, _Seq, std::random_access_iterator_tag>::_Self):
    New.
    (_Safe_iterator<_It, _Seq, std::random_access_iterator_tag>
    ::_OtherSelf): New.
    (_GLIBCXX_DEBUG_VERIFY_OPERANDS, _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS)
    (_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS)
    (_GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS): Define macros.
    (_Safe_iterator<_It, _Seq, std::random_access_iterator_tag>
    ::operator+(difference_type)): Use latters, inline as friend.
    (_Safe_iterator<_It, _Seq, std::random_access_iterator_tag>
    ::operator-(difference_type)): Likewise.
    (operator<(const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.
    (operator<=(const _Safe_iterator<>&, const _Safe_iterator<>&)):
    Likewise.
    (operator>(const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.
    (operator>=(const _Safe_iterator<>&, const _Safe_iterator<>&)):
    Likewise.
    (operator-(const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.
    (operator+(difference_type, const _Safe_iterator<>&)): Likewise.
    (operator-(const _Safe_iterator<>&, difference_type)): Likewise.
    (operator==(const _Safe_iterator<>&, const _Safe_iterator<>&)):
    Use _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS.
    (operator!=(const _Safe_iterator<>&, const _Safe_iterator<>&)):
    Likewise.
    * include/debug/safe_iterator.tcc
    (_Safe_iterator<>::_M_can_advance(difference_type)): Take parameter by
    copy.
    * include/debug/safe_local_iterator.h
    (_Safe_local_iterator<_It, _Seq>::_Self): New.
    (_Safe_local_iterator<_It, _Seq>::_OtherSelf): New.
    (_GLIBCXX_DEBUG_VERIFY_OPERANDS): Define macro.
    (operator==(const _Safe_local_iterator<>&,
    const _Safe_local_iterator<>&)): Use latter, inline as friend.
    (operator!=(const _Safe_local_iterator<>&,
    const _Safe_local_iterator<>&)): Likewise.
    * testsuite/util/testsuite_containers.h
    (struct forward_members_unordered<_Tp, bool>): Remove 2nd template
    parameter.
(forward_members_unordered<>::forward_members_unordered(value_type&)):
    Add using namespace std::rel_ops.
    Add iterator_concept_checks on local_iterator and const_local_iterator.
    Add asserts on comparison between const_local_iterator and
    local_iterator.
    (struct forward_members_unordered<_Tp, false>): Remove partial
    specialization.
    * testsuite/23_containers/forward_list/types/1.cc: New.
    * testsuite/23_containers/list/types/1.cc: New.

Ok to commit ?

François
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index af1b3a0ad3f..4298302a47e 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -444,6 +444,46 @@ namespace __gnu_debug
       bool
       _M_is_beginnest() const
       { return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(*this); }
+
+      template<typename _IteL, typename _IteR, typename _Seq>
+	friend bool
+	operator==(const _Safe_iterator<_IteL, _Seq>& __lhs,
+		   const _Safe_iterator<_IteR, _Seq>& __rhs)
+	  _GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() == __rhs.base();
+	}
+
+      template<typename _Ite, typename _Seq>
+	friend bool
+	operator==(const _Safe_iterator<_Ite, _Seq>& __lhs,
+		   const _Safe_iterator<_Ite, _Seq>& __rhs)
+	  _GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() == __rhs.base();
+	}
+
+      template<typename _IteL, typename _IteR, typename _Seq>
+	friend bool
+	operator!=(const _Safe_iterator<_IteL, _Seq>& __lhs,
+		   const _Safe_iterator<_IteR, _Seq>& __rhs)
+	  _GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() != __rhs.base();
+	}
+
+      template<typename _Ite, typename _Seq>
+	friend bool
+	operator!=(const _Safe_iterator<_Ite, _Seq>& __lhs,
+		   const _Safe_iterator<_Ite, _Seq>& __rhs)
+	  _GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() != __rhs.base();
+	}
     };
 
   template<typename _Iterator, typename _Sequence>
@@ -869,46 +909,6 @@ namespace __gnu_debug
       }
     };
 
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator==(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
-	       const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
-      return __lhs.base() == __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator==(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
-	       const _Safe_iterator<_Iterator, _Sequence>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
-      return __lhs.base() == __rhs.base();
-    }
-
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator!=(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
-	       const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
-      return __lhs.base() != __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator!=(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
-	       const _Safe_iterator<_Iterator, _Sequence>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
-      return __lhs.base() != __rhs.base();
-    }
-
   /** Safe iterators know how to check if they form a valid range. */
   template<typename _Iterator, typename _Sequence, typename _Category>
     inline bool
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 86211b9ca3d..af1b3a0ad3f 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -36,6 +36,28 @@
 #include <bits/stl_pair.h>
 #include <ext/type_traits.h>
 
+#define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \
+  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(),	\
+			_M_message(_BadMsgId)				\
+			._M_iterator(_Lhs, #_Lhs)			\
+			._M_iterator(_Rhs, #_Rhs));			\
+  _GLIBCXX_DEBUG_VERIFY(_Lhs._M_can_compare(_Rhs),			\
+			_M_message(_DiffMsgId)				\
+			._M_iterator(_Lhs, #_Lhs)			\
+			._M_iterator(_Rhs, #_Rhs))
+
+#define _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(_Lhs, _Rhs)			\
+  _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_iter_compare_bad,	\
+				 __msg_compare_different)
+
+#define _GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(_Lhs, _Rhs)		\
+  _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_iter_order_bad,	\
+				 __msg_order_different)
+
+#define _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(_Lhs, _Rhs)			\
+  _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_distance_bad,	\
+				 __msg_distance_different)
+
 namespace __gnu_debug
 {
   /** Helper struct to deal with sequence offering a before_begin
@@ -180,8 +202,9 @@ namespace __gnu_debug
       template<typename _MutableIterator>
 	_Safe_iterator(
 	  const _Safe_iterator<_MutableIterator, _Sequence,
-	  typename __gnu_cxx::__enable_if<_IsConstant::__value &&
-	    std::__are_same<_MutableIterator, _OtherIterator>::__value,
+	    typename __gnu_cxx::__enable_if<_IsConstant::__value &&
+	      !std::__are_same<_MutableIterator, _Iterator>::__value &&
+	      std::__are_same<_MutableIterator, _OtherIterator>::__value,
 					  _Category>::__type>& __x)
 	_GLIBCXX_NOEXCEPT
 	: _Iter_base(__x.base())
@@ -374,7 +397,7 @@ namespace __gnu_debug
 
       // Can we advance the iterator @p __n steps (@p __n may be negative)
       bool
-      _M_can_advance(const difference_type& __n) const;
+      _M_can_advance(difference_type __n) const;
 
       // Is the iterator range [*this, __rhs) valid?
       bool
@@ -474,8 +497,9 @@ namespace __gnu_debug
       template<typename _MutableIterator>
 	_Safe_iterator(
 	  const _Safe_iterator<_MutableIterator, _Sequence,
-	  typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
-	    std::__are_same<_MutableIterator, _OtherIterator>::__value,
+	    typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
+	      !std::__are_same<_MutableIterator, _Iterator>::__value &&
+	      std::__are_same<_MutableIterator, _OtherIterator>::__value,
 			       std::bidirectional_iterator_tag>::__type>& __x)
 	_GLIBCXX_NOEXCEPT
 	: _Safe_base(__x)
@@ -574,6 +598,11 @@ namespace __gnu_debug
 			     std::bidirectional_iterator_tag> _Safe_base;
       typedef typename _Safe_base::_OtherIterator _OtherIterator;
 
+      typedef _Safe_iterator<_Iterator, _Sequence,
+			     std::random_access_iterator_tag> _Self;
+      typedef _Safe_iterator<_OtherIterator, _Sequence,
+			     std::random_access_iterator_tag> _OtherSelf;
+
       typedef typename _Safe_base::_Attach_single _Attach_single;
 
       _Safe_iterator(_Iterator __i, _Safe_sequence_base* __seq, _Attach_single)
@@ -620,6 +649,7 @@ namespace __gnu_debug
 	_Safe_iterator(
 	  const _Safe_iterator<_MutableIterator, _Sequence,
 	    typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
+	      !std::__are_same<_MutableIterator, _Iterator>::__value &&
 	      std::__are_same<_MutableIterator, _OtherIterator>::__value,
 			       std::random_access_iterator_tag>::__type>& __x)
 	_GLIBCXX_NOEXCEPT
@@ -706,7 +736,7 @@ namespace __gnu_debug
 
       // ------ Random access iterator requirements ------
       reference
-      operator[](const difference_type& __n) const _GLIBCXX_NOEXCEPT
+      operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
       {
 	_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
 			      && this->_M_can_advance(__n + 1),
@@ -716,7 +746,7 @@ namespace __gnu_debug
       }
 
       _Safe_iterator&
-      operator+=(const difference_type& __n) _GLIBCXX_NOEXCEPT
+      operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
       {
 	_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
 			      _M_message(__msg_advance_oob)
@@ -726,17 +756,8 @@ namespace __gnu_debug
 	return *this;
       }
 
-      _Safe_iterator
-      operator+(const difference_type& __n) const _GLIBCXX_NOEXCEPT
-      {
-	_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
-			      _M_message(__msg_advance_oob)
-			      ._M_iterator(*this)._M_integer(__n));
-	return _Safe_iterator(this->base() + __n, this->_M_sequence);
-      }
-
       _Safe_iterator&
-      operator-=(const difference_type& __n) _GLIBCXX_NOEXCEPT
+      operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
       {
 	_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
 			      _M_message(__msg_retreat_oob)
@@ -746,13 +767,105 @@ namespace __gnu_debug
 	return *this;
       }
 
-      _Safe_iterator
-      operator-(const difference_type& __n) const _GLIBCXX_NOEXCEPT
+      friend bool
+      operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
-	_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() < __rhs.base();
+      }
+
+      friend bool
+      operator<(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() < __rhs.base();
+      }
+
+      friend bool
+      operator<=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() <= __rhs.base();
+      }
+
+      friend bool
+      operator<=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() <= __rhs.base();
+      }
+
+      friend bool
+      operator>(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() > __rhs.base();
+      }
+
+      friend bool
+      operator>(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() > __rhs.base();
+      }
+
+      friend bool
+      operator>=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() >= __rhs.base();
+      }
+
+      friend bool
+      operator>=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
+	return __lhs.base() >= __rhs.base();
+      }
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // According to the resolution of DR179 not only the various comparison
+      // operators but also operator- must accept mixed iterator/const_iterator
+      // parameters.
+      friend difference_type
+      operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
+	return __lhs.base() - __rhs.base();
+      }
+
+      friend difference_type
+      operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
+	return __lhs.base() - __rhs.base();
+      }
+
+      friend _Self
+      operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
+			      _M_message(__msg_advance_oob)
+			      ._M_iterator(__x)._M_integer(__n));
+	return _Safe_iterator(__x.base() + __n, __x._M_sequence);
+      }
+
+      friend _Self
+      operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
+			      _M_message(__msg_advance_oob)
+			      ._M_iterator(__x)._M_integer(__n));
+	return _Safe_iterator(__n + __x.base(), __x._M_sequence);
+      }
+
+      friend _Self
+      operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
 			      _M_message(__msg_retreat_oob)
-			      ._M_iterator(*this)._M_integer(__n));
-	return _Safe_iterator(this->base() - __n, this->_M_sequence);
+			      ._M_iterator(__x)._M_integer(__n));
+	return _Safe_iterator(__x.base() - __n, __x._M_sequence);
       }
     };
 
@@ -762,14 +875,7 @@ namespace __gnu_debug
 	       const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
     _GLIBCXX_NOEXCEPT
     {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
       return __lhs.base() == __rhs.base();
     }
 
@@ -779,14 +885,7 @@ namespace __gnu_debug
 	       const _Safe_iterator<_Iterator, _Sequence>& __rhs)
     _GLIBCXX_NOEXCEPT
     {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
       return __lhs.base() == __rhs.base();
     }
 
@@ -796,14 +895,7 @@ namespace __gnu_debug
 	       const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
     _GLIBCXX_NOEXCEPT
     {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
       return __lhs.base() != __rhs.base();
     }
 
@@ -813,222 +905,10 @@ namespace __gnu_debug
 	       const _Safe_iterator<_Iterator, _Sequence>& __rhs)
     _GLIBCXX_NOEXCEPT
     {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+      _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
       return __lhs.base() != __rhs.base();
     }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator<(const _Safe_iterator<_IteratorL, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_IteratorR, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() < __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator<(const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() < __rhs.base();
-    }
-
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator<=(const _Safe_iterator<_IteratorL, _Sequence,
-				    std::random_access_iterator_tag>& __lhs,
-	       const _Safe_iterator<_IteratorR, _Sequence,
-				    std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() <= __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator<=(const _Safe_iterator<_Iterator, _Sequence,
-				    std::random_access_iterator_tag>& __lhs,
-	       const _Safe_iterator<_Iterator, _Sequence,
-				    std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() <= __rhs.base();
-    }
-
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator>(const _Safe_iterator<_IteratorL, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_IteratorR, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() > __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator>(const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() > __rhs.base();
-    }
-
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator>=(const _Safe_iterator<_IteratorL, _Sequence,
-				    std::random_access_iterator_tag>& __lhs,
-	       const _Safe_iterator<_IteratorR, _Sequence,
-				    std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() >= __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator>=(const _Safe_iterator<_Iterator, _Sequence,
-				    std::random_access_iterator_tag>& __lhs,
-	       const _Safe_iterator<_Iterator, _Sequence,
-				    std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_order_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_order_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() >= __rhs.base();
-    }
-
-  // _GLIBCXX_RESOLVE_LIB_DEFECTS
-  // According to the resolution of DR179 not only the various comparison
-  // operators but also operator- must accept mixed iterator/const_iterator
-  // parameters.
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline typename _Safe_iterator<_IteratorL, _Sequence,
-			std::random_access_iterator_tag>::difference_type
-    operator-(const _Safe_iterator<_IteratorL, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_IteratorR, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_distance_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_distance_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() - __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline typename _Safe_iterator<_Iterator, _Sequence,
-			std::random_access_iterator_tag>::difference_type
-    operator-(const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __lhs,
-	      const _Safe_iterator<_Iterator, _Sequence,
-				   std::random_access_iterator_tag>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_distance_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_distance_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() - __rhs.base();
-    }
-
-  template<typename _Iterator, typename _Sequence>
-    inline _Safe_iterator<_Iterator, _Sequence, std::random_access_iterator_tag>
-    operator+(typename _Safe_iterator<_Iterator,_Sequence,
-		std::random_access_iterator_tag>::difference_type __n,
-	      const _Safe_iterator<_Iterator, _Sequence,
-		std::random_access_iterator_tag>& __i)
-    _GLIBCXX_NOEXCEPT
-    { return __i + __n; }
-
   /** Safe iterators know how to check if they form a valid range. */
   template<typename _Iterator, typename _Sequence, typename _Category>
     inline bool
@@ -1076,6 +956,11 @@ namespace __gnu_debug
 
 } // namespace __gnu_debug
 
+#undef _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS
+#undef _GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS
+#undef _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS
+#undef _GLIBCXX_DEBUG_VERIFY_OPERANDS
+
 #include <debug/safe_iterator.tcc>
 
 #endif
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc
index 2841583667f..2bfe134a3a4 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -82,7 +82,7 @@ namespace __gnu_debug
   template<typename _Iterator, typename _Sequence, typename _Category>
     bool
     _Safe_iterator<_Iterator, _Sequence, _Category>::
-    _M_can_advance(const difference_type& __n) const
+    _M_can_advance(difference_type __n) const
     {
       if (this->_M_singular())
 	return false;
diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h
index 854518848f9..8e3ae443e9c 100644
--- a/libstdc++-v3/include/debug/safe_local_iterator.h
+++ b/libstdc++-v3/include/debug/safe_local_iterator.h
@@ -31,6 +31,20 @@
 
 #include <debug/safe_unordered_base.h>
 
+#define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs) \
+  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(),	\
+			_M_message(__msg_iter_compare_bad)		\
+			._M_iterator(_Lhs, "lhs")			\
+			._M_iterator(_Rhs, "rhs"));			\
+  _GLIBCXX_DEBUG_VERIFY(_Lhs._M_can_compare(_Rhs),			\
+			_M_message(__msg_compare_different)		\
+			._M_iterator(_Lhs, "lhs")			\
+			._M_iterator(_Rhs, "rhs"));			\
+  _GLIBCXX_DEBUG_VERIFY(_Lhs._M_in_same_bucket(_Rhs),			\
+			_M_message(__msg_local_iter_compare_bad)	\
+			._M_iterator(_Lhs, "lhs")			\
+			._M_iterator(_Rhs, "rhs"))
+
 namespace __gnu_debug
 {
   /** \brief Safe iterator wrapper.
@@ -65,6 +79,9 @@ namespace __gnu_debug
 	typename _Sequence::_Base::const_local_iterator>::__type
       _OtherIterator;
 
+      typedef _Safe_local_iterator _Self;
+      typedef _Safe_local_iterator<_OtherIterator, _Sequence> _OtherSelf;
+
       struct _Attach_single
       { };
 
@@ -354,87 +371,35 @@ namespace __gnu_debug
 	_M_in_same_bucket(const _Safe_local_iterator<_Other,
 						     _Sequence>& __other) const
 	{ return bucket() == __other.bucket(); }
-    };
 
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator==(const _Safe_local_iterator<_IteratorL, _Sequence>& __lhs,
-	       const _Safe_local_iterator<_IteratorR, _Sequence>& __rhs)
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() == __rhs.base();
-    }
+      friend inline bool
+      operator==(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs);
+	return __lhs.base() == __rhs.base();
+      }
 
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator==(const _Safe_local_iterator<_Iterator, _Sequence>& __lhs,
-	       const _Safe_local_iterator<_Iterator, _Sequence>& __rhs)
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() == __rhs.base();
-    }
+      friend inline bool
+      operator==(const _Self& __lhs, const _Self& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs);
+	return __lhs.base() == __rhs.base();
+      }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator!=(const _Safe_local_iterator<_IteratorL, _Sequence>& __lhs,
-	       const _Safe_local_iterator<_IteratorR, _Sequence>& __rhs)
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() != __rhs.base();
-    }
+      friend inline bool
+      operator!=(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs);
+	return __lhs.base() != __rhs.base();
+      }
 
-  template<typename _Iterator, typename _Sequence>
-    inline bool
-    operator!=(const _Safe_local_iterator<_Iterator, _Sequence>& __lhs,
-	       const _Safe_local_iterator<_Iterator, _Sequence>& __rhs)
-    {
-      _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(),
-			    _M_message(__msg_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_can_compare(__rhs),
-			    _M_message(__msg_compare_different)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      _GLIBCXX_DEBUG_VERIFY(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
-      return __lhs.base() != __rhs.base();
-    }
+      friend inline bool
+      operator!=(const _Self& __lhs, const _Self& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs);
+	return __lhs.base() != __rhs.base();
+      }
+    };
 
   /** Safe local iterators know how to check if they form a valid range. */
   template<typename _Iterator, typename _Sequence>
@@ -466,6 +431,8 @@ namespace __gnu_debug
 
 } // namespace __gnu_debug
 
+#undef _GLIBCXX_DEBUG_VERIFY_OPERANDS
+
 #include <debug/safe_local_iterator.tcc>
 
 #endif
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/types/1.cc b/libstdc++-v3/testsuite/23_containers/forward_list/types/1.cc
new file mode 100644
index 00000000000..164b9c4a14b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/types/1.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <forward_list>
+#include <testsuite_greedy_ops.h>
+
+int main()
+{
+  std::forward_list<greedy_ops::X> fl;
+  const std::forward_list<greedy_ops::X> cfl;
+
+  fl.insert_after(fl.before_begin(), greedy_ops::X());
+  fl.insert_after(fl.before_begin(), 1, greedy_ops::X());
+  fl.insert_after(fl.before_begin(), cfl.begin(), cfl.end());
+  fl = cfl;
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/types/1.cc b/libstdc++-v3/testsuite/23_containers/list/types/1.cc
new file mode 100644
index 00000000000..a7bb217c623
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/types/1.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile }
+
+#include <list>
+#include <testsuite_greedy_ops.h>
+
+int main()
+{
+  std::list<greedy_ops::X> l;
+  const std::list<greedy_ops::X> cl;
+
+  l.size();
+  l.insert(l.begin(), greedy_ops::X());
+  l.insert(l.begin(), 1, greedy_ops::X());
+  l.insert(l.begin(), cl.begin(), cl.end());
+  l = cl;
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_containers.h b/libstdc++-v3/testsuite/util/testsuite_containers.h
index d05d3acaa05..eadd43768d2 100644
--- a/libstdc++-v3/testsuite/util/testsuite_containers.h
+++ b/libstdc++-v3/testsuite/util/testsuite_containers.h
@@ -171,33 +171,38 @@ namespace __gnu_test
       reverse_members(_Tp& container) { }
     };
 
+  template<typename _Iterator,
+	   bool _Mutable,
+	   typename = typename std::iterator_traits<_Iterator>::iterator_category>
+    struct iterator_concept_checks;
+
   // DR 691.
-  template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
+  template<typename _Tp>
     struct forward_members_unordered
     {
       forward_members_unordered(typename _Tp::value_type& v)
       {
+	// Make sure that even if rel_ops is injected there is no ambiguity
+	// when comparing iterators.
+	using namespace std::rel_ops;
+
 	typedef _Tp					test_type;
 	test_type container;
 	container.insert(v);
+
+	iterator_concept_checks<typename _Tp::local_iterator, false> cc;
+	iterator_concept_checks<typename _Tp::const_local_iterator,
+				false> ccc;
+
 	assert( container.cbegin(0) == container.begin(0) );
 	assert( container.cend(0) == container.end(0) );
 	const typename test_type::size_type bn = container.bucket(1);
 	assert( container.cbegin(bn) != container.cend(bn) );
+	assert( container.cbegin(bn) != container.end(bn) );
+	assert( container.begin(bn) != container.cend(bn) );
       }
     };
 
-  template<typename _Tp>
-    struct forward_members_unordered<_Tp, false>
-    {
-      forward_members_unordered(_Tp& container) { }
-    };
-
-  template<typename _Iterator,
-	   bool _Mutable,
-	   typename = typename std::iterator_traits<_Iterator>::iterator_category>
-    struct iterator_concept_checks;
-
   template<typename _Iterator>
     struct iterator_concept_checks<_Iterator, false,
 				   std::forward_iterator_tag>
@@ -264,6 +269,82 @@ namespace __gnu_test
       }
     };
 
+  template<typename _Tp>
+    struct forward_members
+    {
+      forward_members(_Tp& container)
+      {
+	// Make sure that even if rel_ops is injected there is no ambiguity
+	// when comparing iterators.
+	using namespace std::rel_ops;
+
+	typedef traits<_Tp> traits_type;
+	iterator_concept_checks<typename _Tp::iterator,
+				!(traits_type::is_associative::value
+				  || traits_type::is_unordered::value)> cc;
+	iterator_concept_checks<typename _Tp::const_iterator, false> ccc;
+
+	assert( container.cbegin() == container.begin() );
+	assert( container.end() == container.cend() );
+	assert( container.cbegin() != container.cend() );
+	assert( container.cbegin() != container.end() );
+	assert( container.begin() != container.cend() );
+      }
+  };
+
+  template<typename _Tp,
+	   typename
+    = typename std::iterator_traits<typename _Tp::iterator>::iterator_category>
+    struct category_members : forward_members<_Tp>
+    {
+      category_members(_Tp& container)
+	: forward_members<_Tp>(container)
+      { };
+    };
+
+  template<typename _Tp>
+    struct category_members<_Tp, std::random_access_iterator_tag>
+    : forward_members<_Tp>
+    {
+      category_members(_Tp& container)
+	: forward_members<_Tp>(container)
+      {
+	// Make sure that even if rel_ops is injected there is no ambiguity
+	// when comparing iterators.
+	using namespace std::rel_ops;
+
+	assert( !(container.begin() < container.begin()) );
+	assert( !(container.cbegin() < container.cbegin()) );
+	assert( !(container.cbegin() < container.begin()) );
+	assert( !(container.begin() < container.cbegin()) );
+	assert( container.begin() <= container.begin() );
+	assert( container.cbegin() <= container.cbegin() );
+	assert( container.cbegin() <= container.begin() );
+	assert( container.begin() <= container.cbegin() );
+
+	assert( !(container.begin() > container.begin()) );
+	assert( !(container.cbegin() > container.cbegin()) );
+	assert( !(container.cbegin() > container.begin()) );
+	assert( !(container.begin() > container.cbegin()) );
+	assert( container.begin() >= container.begin() );
+	assert( container.cbegin() >= container.cbegin() );
+	assert( container.cbegin() >= container.begin() );
+	assert( container.begin() >= container.cbegin() );
+
+	assert( container.begin() - container.begin() == 0 );
+	assert( container.cbegin() - container.cbegin() == 0 );
+	assert( container.cbegin() - container.begin() == 0 );
+	assert( container.begin() - container.cbegin() == 0 );
+
+	assert( container.begin() + 0 == container.begin() );
+	assert( container.cbegin() + 0 == container.cbegin() );
+	assert( 0 + container.begin() == container.begin() );
+	assert( 0 + container.cbegin() == container.cbegin() );
+	assert( container.begin() - 0 == container.begin() );
+	assert( container.cbegin() - 0 == container.cbegin() );
+      }
+  };
+
   template<typename _Tp>
     struct citerator
     {
@@ -274,32 +355,17 @@ namespace __gnu_test
       static test_type _S_container;
 
       // Unconditional.
-      struct forward_members
+      struct members : category_members<_Tp>
       {
-	forward_members()
-	{
-	  // Make sure that even if rel_ops is injected there is no ambiguity
-	  // when comparing iterators.
-	  using namespace std::rel_ops;
-
-	  iterator_concept_checks<typename _Tp::iterator,
-				  !(traits_type::is_associative::value
-				    || traits_type::is_unordered::value)> cc;
-	  iterator_concept_checks<typename _Tp::const_iterator, false> ccc;
-
-	  assert( _S_container.cbegin() == _S_container.begin() );
-	  assert( _S_container.end() == _S_container.cend() );
-	  assert( _S_container.cbegin() != _S_container.cend() );
-	  assert( _S_container.cbegin() != _S_container.end() );
-	  assert( _S_container.begin() != _S_container.cend() );
-	}
+	members() : category_members<_Tp>(_S_container)
+	{ }
       };
 
       // Run test.
       citerator()
       {
 	populate<test_type> p(_S_container);
-	forward_members m1;
+	members m1;
 	reverse_members<test_type> m2(_S_container);
       }
   };

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]