diff mbox series

Make safe_iterator inline friends

Message ID 3da11787-c1d0-953a-434c-76865dfb8e43@gmail.com
State New
Headers show
Series Make safe_iterator inline friends | expand

Commit Message

François Dumont Aug. 22, 2018, 9:08 p.m. UTC
Now that _Safe_iterator has been revisited I would like to cleanup its 
operators to make them globals and inline friends as much as possible.

This patch transform operator-(const _Safe_iterator<>&, difference_type) 
and operator+(const _Safe_iterator<>&, difference_type) into global 
namespace operators.

Otherwise it just make all operators inline friend.

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 but keeping those operators that 
should apply for any category of safe iterator at namespace level is ok. 
There are not much operators within __gnu_debug and users normally don't 
explicitely use this namespace.

I added even more checks in testsuite_containers.h especially using 
std::rel_ops to make sure we have no ambiguity.

Tested under Linux x86_64 debug mode.

Ok to commit ?

François

Comments

Jonathan Wakely Aug. 22, 2018, 9:45 p.m. UTC | #1
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.
François Dumont Aug. 23, 2018, 8:59 p.m. UTC | #2
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.

In _Safe_iterator representing the container iterator type we have 
friend operators:

operator==(iterator, iterator);

operator==(iterator, const_iterator);

And in the one representing const_iterator:

operator==(const_iterator, const_iterator);

operator==(const_iterator, iterator);

but gcc do not see it this way.

I try again without the _Self and _OtherSelf types, using directly 
_Safe_iterator as it should and got:

/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h: 
In instantiation of 'class 
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const 
std::__cxx11::basic_string<char>*, 
std::__cxx1998::vector<std::__cxx11::basic_string<char>, 
std::allocator<std::__cxx11::basic_string<char> > > >, 
std::__debug::vector<std::__cxx11::basic_string<char> >, 
std::forward_iterator_tag>':
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:489: 
required from 'class 
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const 
std::__cxx11::basic_string<char>*, 
std::__cxx1998::vector<std::__cxx11::basic_string<char>, 
std::allocator<std::__cxx11::basic_string<char> > > >, 
std::__debug::vector<std::__cxx11::basic_string<char> >, 
std::bidirectional_iterator_tag>'
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:631: 
required from 'class 
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const 
std::__cxx11::basic_string<char>*, 
std::__cxx1998::vector<std::__cxx11::basic_string<char>, 
std::allocator<std::__cxx11::basic_string<char> > > >, 
std::__debug::vector<std::__cxx11::basic_string<char> >, 
std::random_access_iterator_tag>'
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/util/testsuite_abi.cc:419: 
required from here
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:449: 
error: redefinition of 'template<class _IteL, class _IteR, class _Seq, 
class _Cat> bool __gnu_debug::operator==(const 
__gnu_debug::_Safe_iterator<_IteL, _Seq, _Cat>&, const 
__gnu_debug::_Safe_iterator<_IteR, _Seq, _Cat>&)'
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:449: 
note: 'template<class _IteL, class _IteR, class _Seq, class _Cat> bool 
__gnu_debug::operator==(const __gnu_debug::_Safe_iterator<_IteL, _Seq, 
_Cat>&, const __gnu_debug::_Safe_iterator<_IteR, _Seq, _Cat>&)' 
previously declared here

redefinition and previous declaration are targetting the exact same 
line. This is why I think it has something to do with the inheritance 
between the different iterator types.

But as I said it doesn't really matter for the patch. We can go with 
those 2 operators not inline friends.

So appart from that is it ok to commit ?

François
Jonathan Wakely Aug. 28, 2018, 7:04 p.m. UTC | #3
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?

There's no changelog in the email with the patch.
François Dumont Aug. 28, 2018, 7:21 p.m. UTC | #4
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 point, thanks, I'll consider this point.
>
> There's no changelog in the email with the patch.
>
And I'll also provide ChangeLog next time.

François
François Dumont Aug. 29, 2018, 5:54 a.m. UTC | #5
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);
       }
   };
Jonathan Wakely Aug. 29, 2018, 11:34 a.m. UTC | #6
On 29/08/18 07:54 +0200, François Dumont wrote:
>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.

Yes, that's expected.

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

I'm sure there is no compiler bug here. Consider:

template<typename T>
struct Iter
{
  template<typename U>
    friend bool
    operator==(Iter<U>, Iter<U>) { return true; }
};

Iter<int> i;
Iter<long> j;


This fails:

dup_friend.cc: In instantiation of 'struct Iter<long int>':
dup_friend.cc:10:12:   required from here
dup_friend.cc:6:5: error: redefinition of 'template<class U> bool operator==(Iter<U>, Iter<U>)'
6 |     operator==(Iter<U>, Iter<U>) { return true; }
  |     ^~~~~~~~
dup_friend.cc:6:5: note: 'template<class U> bool operator==(Iter<U>, Iter<U>)' previously declared here


The problem is that the friend function does not depend on the
template parameters of the enclosing class. That means that every
different specialization of Iter defines an identical friend function.

The specialization Iter<int> defines:

  template<typename U>
    friend bool
    operator==(Iter<U>, Iter<U>) { return true; }

and the specialization Iter<long> defines:

  template<typename U>
    friend bool
    operator==(Iter<U>, Iter<U>) { return true; }

That means you have two function definitions with identical
signatures, which is invalid. You can only define a function once.

A friend function defined inline in a class template needs to depend
on the enclosing class, so that each specialization of the class
template defines a *different* friend function.

For example:

template<typename T>
struct Iter
{
  friend bool
  operator==(Iter, Iter) { return true; }
};

Or:

template<typename T>
struct Iter
{
  template<typename U>
    friend bool
    operator==(Iter, Iter<U>) { return true; }

  template<typename U> friend class Iter<U>;
};

(This latter case will only be a friend of the left operand, not the
right operand. So access to private members of the right operand would
have to be via some other function, maybe a member of the left
operand, because Iter<T> and Iter<U> are friends.)
François Dumont Aug. 30, 2018, 7:56 p.m. UTC | #7
Thanks for all those explanations. It helped me to find the solution.

So here is the final patch with all operators inline friends.

Tested under Linux x86_64.

     * 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>=(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.
     * 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 86211b9ca3d..8ccd21bdc91 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
@@ -374,7 +396,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
@@ -421,6 +443,44 @@ namespace __gnu_debug
       bool
       _M_is_beginnest() const
       { return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(*this); }
+
+      // ------ Operators ------
+
+      typedef _Safe_iterator<_Iterator, _Sequence, iterator_category> _Self;
+
+      friend bool
+      operator==(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	return __lhs.base() == __rhs.base();
+      }
+
+      template<typename _IteR>
+	friend bool
+	operator==(const _Self& __lhs,
+	  const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
+	_GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() == __rhs.base();
+	}
+
+      friend bool
+      operator!=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
+      {
+	_GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	return __lhs.base() != __rhs.base();
+      }
+
+      template<typename _IteR>
+	friend bool
+	operator!=(const _Self& __lhs,
+	  const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
+	_GLIBCXX_NOEXCEPT
+	{
+	  _GLIBCXX_DEBUG_VERIFY_CMP_OPERANDS(__lhs, __rhs);
+	  return __lhs.base() != __rhs.base();
+	}
     };
 
   template<typename _Iterator, typename _Sequence>
@@ -574,6 +634,10 @@ namespace __gnu_debug
 			     std::bidirectional_iterator_tag> _Safe_base;
       typedef typename _Safe_base::_OtherIterator _OtherIterator;
 
+      typedef typename _Safe_base::_Self _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)
@@ -706,7 +770,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 +780,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 +790,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,233 +801,59 @@ 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_retreat_oob)
-			      ._M_iterator(*this)._M_integer(__n));
-	return _Safe_iterator(this->base() - __n, this->_M_sequence);
-      }
-    };
-
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
-    inline bool
-    operator==(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
-	       const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
-    _GLIBCXX_NOEXCEPT
+      friend bool
+      operator<(const _Self& __lhs, const _Self& __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"));
-      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(!__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"));
-      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(!__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"));
-      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(!__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"));
-      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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __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
+      friend bool
+      operator<(const _Self& __lhs, const _OtherSelf& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_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
+      friend bool
+      operator<=(const _Self& __lhs, const _Self& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __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
+      friend bool
+      operator<=(const _Self& __lhs, const _OtherSelf& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_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
+      friend bool
+      operator>(const _Self& __lhs, const _Self& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __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
+      friend bool
+      operator>(const _Self& __lhs, const _OtherSelf& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_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
+      friend bool
+      operator>=(const _Self& __lhs, const _Self& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __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
+      friend bool
+      operator>=(const _Self& __lhs, const _OtherSelf& __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"));
+	_GLIBCXX_DEBUG_VERIFY_ORDER_OPERANDS(__lhs, __rhs);
 	return __lhs.base() >= __rhs.base();
       }
 
@@ -980,54 +861,47 @@ namespace __gnu_debug
       // 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
+      friend difference_type
+      operator-(const _Self& __lhs, const _OtherSelf& __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"));
+	_GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __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
+      friend difference_type
+      operator-(const _Self& __lhs, const _Self& __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"));
+	_GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __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; }
+      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(__x)._M_integer(__n));
+	return _Safe_iterator(__x.base() - __n, __x._M_sequence);
+      }
+    };
 
   /** Safe iterators know how to check if they form a valid range. */
   template<typename _Iterator, typename _Sequence, typename _Category>
@@ -1076,6 +950,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)
+      friend inline bool
+      operator==(const _Self& __lhs, const _OtherSelf& __rhs) 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(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+	_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)
+      friend inline bool
+      operator==(const _Self& __lhs, const _Self& __rhs) 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(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+	_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)
+      friend inline bool
+      operator!=(const _Self& __lhs, const _OtherSelf& __rhs) 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(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+	_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)
+      friend inline bool
+      operator!=(const _Self& __lhs, const _Self& __rhs) 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(__lhs._M_in_same_bucket(__rhs),
-			    _M_message(__msg_local_iter_compare_bad)
-			    ._M_iterator(__lhs, "lhs")
-			    ._M_iterator(__rhs, "rhs"));
+	_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>
@@ -265,41 +270,102 @@ namespace __gnu_test
     };
 
   template<typename _Tp>
-    struct citerator
-    {
-      typedef _Tp 					test_type;
-      typedef traits<test_type>				traits_type;
-      typedef typename test_type::value_type 		value_type;
-
-      static test_type _S_container;
-
-      // Unconditional.
     struct forward_members
     {
-	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( _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() );
+	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
+    {
+      typedef _Tp 					test_type;
+      typedef traits<test_type>				traits_type;
+      typedef typename test_type::value_type 		value_type;
+
+      static test_type _S_container;
+
+      // Unconditional.
+      struct members : category_members<_Tp>
+      {
+	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);
       }
   };
Jonathan Wakely Aug. 31, 2018, 10:12 p.m. UTC | #8
On 30/08/18 21:56 +0200, François Dumont wrote:
>--- 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)

Please use "EQ" instead of "CMP" and "REL" instead of "ORDER". Those
are the names used in the standard (the relational operators like less
than are still "comparisons" so only using CMP/compare for equality is
wrong).

OK for trunk with that change.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 86211b9..b573197 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
@@ -374,7 +396,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
@@ -574,6 +596,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)
@@ -706,7 +733,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 +743,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 +753,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 +764,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 +872,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 +882,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 +892,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 +902,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 +953,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 2841583..2bfe134 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 8545188..8e3ae44 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 0000000..164b9c4
--- /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 0000000..a7bb217
--- /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 d05d3ac..eadd437 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>
@@ -265,6 +270,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
     {
       typedef _Tp 					test_type;
@@ -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);
       }
   };