From 05a30af3f237984b4dcf1dbbc17fdac583c46506 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Dumont?= <fdumont@gcc.gnu.org>
Date: Fri, 1 Jan 2021 17:35:56 +0100
Subject: [PATCH] libstdc++: Implement N3644 for _GLIBCXX_DEBUG iterators

libstdc++-v3/ChangeLog:

	PR libstdc++/98466
	* include/bits/hashtable_policy.h (_Node_iterator_base()): Set _M_cur to nullptr.
	(_Node_iterator()): Make default.
	(_Node_const_iterator()): Make default.
	* include/debug/macros.h (__glibcxx_check_erae_range_after): Add _M_singular
	iterator checks.
	* include/debug/safe_iterator.h
	(_GLIBCXX_DEBUG_VERIFY_OPERANDS): Accept if both iterator are value initialized.
	* include/debug/safe_local_iterator.h (_GLIBCXX_DEBUG_VERIFY_OPERANDS):
	Likewise.
	* include/debug/safe_iterator.tcc (_Safe_iterator<>::_M_valid_range): Add
	_M_singular checks on input iterators.
	* src/c++11/debug.cc (_Safe_iterator_base::_M_can_compare): Remove _M_singular
	checks.
	* testsuite/23_containers/deque/debug/98466.cc: New test.
	* testsuite/23_containers/unordered_map/debug/98466.cc: New test.
---
 libstdc++-v3/include/bits/hashtable_policy.h  |  8 ++--
 libstdc++-v3/include/debug/macros.h           |  5 +++
 libstdc++-v3/include/debug/safe_iterator.h    |  4 +-
 libstdc++-v3/include/debug/safe_iterator.tcc  |  5 ++-
 .../include/debug/safe_local_iterator.h       |  4 +-
 libstdc++-v3/src/c++11/debug.cc               |  5 +--
 .../23_containers/deque/debug/98466.cc        | 38 ++++++++++++++++
 .../unordered_map/debug/98466.cc              | 44 +++++++++++++++++++
 8 files changed, 100 insertions(+), 13 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/23_containers/deque/debug/98466.cc
 create mode 100644 libstdc++-v3/testsuite/23_containers/unordered_map/debug/98466.cc

diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 84961849fb45..999147a68d4e 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -290,7 +290,7 @@ namespace __detail
 
       __node_type* _M_cur;
 
-      _Node_iterator_base() = default;
+      _Node_iterator_base() : _M_cur(nullptr) { }
       _Node_iterator_base(__node_type* __p) noexcept
       : _M_cur(__p) { }
 
@@ -331,8 +331,7 @@ namespace __detail
       using reference = typename std::conditional<__constant_iterators,
 				  const value_type&, value_type&>::type;
 
-      _Node_iterator() noexcept
-      : __base_type(nullptr) { }
+      _Node_iterator() = default;
 
       explicit
       _Node_iterator(__node_type* __p) noexcept
@@ -379,8 +378,7 @@ namespace __detail
       typedef const value_type*				pointer;
       typedef const value_type&				reference;
 
-      _Node_const_iterator() noexcept
-      : __base_type(nullptr) { }
+      _Node_const_iterator() = default;
 
       explicit
       _Node_const_iterator(__node_type* __p) noexcept
diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
index 08c49eca5546..0988437046f6 100644
--- a/libstdc++-v3/include/debug/macros.h
+++ b/libstdc++-v3/include/debug/macros.h
@@ -244,6 +244,11 @@ _GLIBCXX_DEBUG_VERIFY(_First._M_attached_to(this),			\
  *  valid iterator range within this sequence.
 */
 #define __glibcxx_check_erase_range_after(_First,_Last)			\
+_GLIBCXX_DEBUG_VERIFY(!_First._M_singular() && !_Last._M_singular(),	\
+		      _M_message(__gnu_debug::__msg_erase_different)	\
+		      ._M_sequence(*this, "this")			\
+		      ._M_iterator(_First, #_First)			\
+		      ._M_iterator(_Last, #_Last));			\
 _GLIBCXX_DEBUG_VERIFY(_First._M_can_compare(_Last),			\
 		      _M_message(__gnu_debug::__msg_erase_different)	\
 		      ._M_sequence(*this, "this")			\
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 11e0f0b14a30..a10df190969f 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -40,7 +40,9 @@
 #endif
 
 #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \
-  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(),	\
+  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular()	\
+			|| (_Lhs.base() == _Iterator()			\
+			    && _Rhs.base() == _Iterator()),		\
 			_M_message(_BadMsgId)				\
 			._M_iterator(_Lhs, #_Lhs)			\
 			._M_iterator(_Rhs, #_Rhs));			\
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc
index 7d6f91782d55..81deb10125b8 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -186,7 +186,7 @@ namespace __gnu_debug
 		   std::pair<difference_type, _Distance_precision>& __dist,
 		   bool __check_dereferenceable) const
     {
-      if (!_M_can_compare(__rhs))
+      if (_M_singular() || __rhs._M_singular() || !_M_can_compare(__rhs))
 	return false;
 
       /* Determine iterators order */
@@ -217,7 +217,8 @@ namespace __gnu_debug
 		   std::pair<difference_type,
 			     _Distance_precision>& __dist) const
     {
-      if (!this->_M_can_compare(__rhs))
+      if (this->_M_singular() || __rhs._M_singular()
+	  || !this->_M_can_compare(__rhs))
 	return false;
 
       /* Determine iterators order */
diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h
index 39bb9790e05a..31c48e65a249 100644
--- a/libstdc++-v3/include/debug/safe_local_iterator.h
+++ b/libstdc++-v3/include/debug/safe_local_iterator.h
@@ -32,7 +32,9 @@
 #include <debug/safe_unordered_base.h>
 
 #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs) \
-  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(),	\
+  _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular()	\
+			|| (_Lhs.base() == _Iterator{}			\
+			    && _Rhs.base() == _Iterator{}),		\
 			_M_message(__msg_iter_compare_bad)		\
 			._M_iterator(_Lhs, "lhs")			\
 			._M_iterator(_Rhs, "rhs"));			\
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 6cf99186a824..5a642097d179 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -424,10 +424,7 @@ namespace __gnu_debug
   bool
   _Safe_iterator_base::
   _M_can_compare(const _Safe_iterator_base& __x) const throw ()
-  {
-    return (!_M_singular()
-	    && !__x._M_singular() && _M_sequence == __x._M_sequence);
-  }
+  { return _M_sequence == __x._M_sequence; }
 
   __gnu_cxx::__mutex&
   _Safe_iterator_base::
diff --git a/libstdc++-v3/testsuite/23_containers/deque/debug/98466.cc b/libstdc++-v3/testsuite/23_containers/deque/debug/98466.cc
new file mode 100644
index 000000000000..720977e56222
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/debug/98466.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 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 run { target c++11 } }
+
+#include <debug/deque>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/98466
+
+void test01()
+{
+  __gnu_debug::deque<int>::iterator it{};
+  VERIFY( it == it );
+
+  __gnu_debug::deque<int>::const_iterator cit{};
+  VERIFY( cit == cit );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/98466.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/98466.cc
new file mode 100644
index 000000000000..cc22b9ff80ae
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/98466.cc
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 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 run { target c++11 } }
+
+#include <debug/unordered_map>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/98466
+
+void test01()
+{
+  __gnu_debug::unordered_map<int, int>::iterator it{};
+  VERIFY( it == it );
+
+  __gnu_debug::unordered_map<int, int>::const_iterator cit{};
+  VERIFY( cit == cit );
+
+  __gnu_debug::unordered_map<int, int>::local_iterator lit{};
+  VERIFY( lit == lit );
+
+  __gnu_debug::unordered_map<int, int>::const_local_iterator clit{};
+  VERIFY( clit == clit );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
-- 
GitLab