Patchwork [v3] Fix allocator-aware container requirements for forward_list

login
register
mail settings
Submitter Jonathan Wakely
Date Nov. 5, 2012, 9:13 p.m.
Message ID <CAH6eHdR64CVqyjz2TBFHM+_ZUQu5Zdd60Ehg5EMsxFqTAwq45w@mail.gmail.com>
Download mbox | patch
Permalink /patch/197308/
State New
Headers show

Comments

Jonathan Wakely - Nov. 5, 2012, 9:13 p.m.
This updates the debug-mode and profile-mode forward_list code to
match my recent allocator changes to the default mode.  It also adds
checking for unswappable allocators, and fixes some tests that those
new checks showed were broken.

        * include/profile/forward_list: Update to meet allocator-aware
        requirements.
        * include/debug/forward_list: Likewise.
        * include/debug/vector: Verify allocators are swapped or equal.
        * include/debug/macros.h (__glibcxx_check_equal_allocs): Define.
        * include/debug/formatter.h: Add new debug message.
        * src/c++11/debug.cc: Likewise.
        * testsuite/23_containers/forward_list/allocator/swap.cc: Do not
        swap containers with non-propagating, non-equal allocators.
        * testsuite/23_containers/vector/allocator/swap.cc: Likewise.

Tested x86_64-linux, committed to trunk.
commit e537dbf92d79d68a4ff2f15864183da1cf17c821
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Mon Nov 5 00:15:12 2012 +0000

    	* include/profile/forward_list: Update to meet allocator-aware
    	requirements.
    	* include/debug/forward_list: Likewise.
    	* include/debug/vector: Verify allocators are swapped or equal.
    	* include/debug/macros.h (__glibcxx_check_equal_allocs): Define.
    	* include/debug/formatter.h: Add new debug message.
    	* src/c++11/debug.cc: Likewise.
    	* testsuite/23_containers/forward_list/allocator/swap.cc: Do not
    	swap containers with non-propagating, non-equal allocators.
    	* testsuite/23_containers/vector/allocator/swap.cc: Likewise.

Patch

diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index 1d29d8c..d622ed1 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -114,7 +114,8 @@  namespace __gnu_debug
     __msg_self_move_assign,
     // unordered container buckets
     __msg_bucket_index_oob,
-    __msg_valid_load_factor
+    __msg_valid_load_factor,
+    __msg_equal_allocs
   };
 
   class _Error_formatter
diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list
index 8ad4336..61ae6ed 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -49,6 +49,12 @@  namespace __debug
 
       typedef typename _Base::iterator       _Base_iterator;
       typedef typename _Base::const_iterator _Base_const_iterator;
+
+      typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
+        rebind<_GLIBCXX_STD_C::_Fwd_list_node<_Tp>>::other _Node_alloc_type;
+
+      typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;
+
     public:
       typedef typename _Base::reference             reference;
       typedef typename _Base::const_reference       const_reference;
@@ -78,12 +84,15 @@  namespace __debug
       forward_list(forward_list&& __list, const _Alloc& __al)
       : _Base(std::move(__list._M_base()), __al)
       {
-	this->_M_swap(__list);
+	if (__list.get_allocator() == __al)
+	  this->_M_swap(__list);
+	else
+	  __list._M_invalidate_all();
       }
 
       explicit
-      forward_list(size_type __n)
-      : _Base(__n)
+      forward_list(size_type __n, const _Alloc& __al = _Alloc())
+      : _Base(__n, __al)
       { }
 
       forward_list(size_type __n, const _Tp& __value,
@@ -128,12 +137,17 @@  namespace __debug
 
       forward_list&
       operator=(forward_list&& __list)
+      noexcept(_Node_alloc_traits::_S_nothrow_move())
       {
-	// NB: DR 1204.
-	// NB: DR 675.
 	__glibcxx_check_self_move_assign(__list);
-	clear();
-	swap(__list);
+	bool xfer_memory = _Node_alloc_traits::_S_propagate_on_move_assign()
+	    || __list.get_allocator() == this->get_allocator();
+	static_cast<_Base&>(*this) = std::move(__list);
+	if (xfer_memory)
+	  this->_M_swap(__list);
+	else
+	  this->_M_invalidate_all();
+	__list._M_invalidate_all();
 	return *this;
       }
 
@@ -333,7 +347,10 @@  namespace __debug
 
       void
       swap(forward_list& __list)
+      noexcept(_Node_alloc_traits::_S_nothrow_swap())
       {
+	if (!_Node_alloc_traits::_S_propagate_on_swap())
+	  __glibcxx_check_equal_allocs(__list);
 	_Base::swap(__list);
 	this->_M_swap(__list);
       }
diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
index 3df0c9b..30606d5 100644
--- a/libstdc++-v3/include/debug/macros.h
+++ b/libstdc++-v3/include/debug/macros.h
@@ -333,6 +333,11 @@  _GLIBCXX_DEBUG_VERIFY(_F > 0.0f,					\
 		      _M_message(__gnu_debug::__msg_valid_load_factor)	\
                       ._M_sequence(*this, "this"))
 
+#define __glibcxx_check_equal_allocs(_Other)			\
+_GLIBCXX_DEBUG_VERIFY(this->get_allocator() == _Other.get_allocator(),	\
+		      _M_message(__gnu_debug::__msg_equal_allocs)	\
+		      ._M_sequence(*this, "this"))
+
 #ifdef _GLIBCXX_DEBUG_PEDANTIC
 #  define __glibcxx_check_string(_String) _GLIBCXX_DEBUG_ASSERT(_String != 0)
 #  define __glibcxx_check_string_len(_String,_Len) \
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index 9e0f843..9c33fdf 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -550,6 +550,10 @@  namespace __debug
 			noexcept(_Alloc_traits::_S_nothrow_swap())
 #endif
       {
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+	if (!_Alloc_traits::_S_propagate_on_swap())
+	  __glibcxx_check_equal_allocs(__x);
+#endif
 	_Base::swap(__x);
 	this->_M_swap(__x);
         std::swap(_M_guaranteed_capacity, __x._M_guaranteed_capacity);
diff --git a/libstdc++-v3/include/profile/forward_list b/libstdc++-v3/include/profile/forward_list
index 618b248..a44ea7a 100644
--- a/libstdc++-v3/include/profile/forward_list
+++ b/libstdc++-v3/include/profile/forward_list
@@ -1,6 +1,6 @@ 
 // <forward_list> -*- C++ -*-
 
-// Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2010-2012 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
@@ -46,10 +46,14 @@  namespace __profile
     {
       typedef _GLIBCXX_STD_C::forward_list<_Tp, _Alloc> _Base;
 
+      typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
+        rebind<_GLIBCXX_STD_C::_Fwd_list_node<_Tp>>::other _Node_alloc_type;
+
+      typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;
+
     public:
       typedef typename _Base::size_type             size_type;
 
-    public:
       // 23.2.3.1 construct/copy/destroy:
       explicit
       forward_list(const _Alloc& __al = _Alloc())
@@ -64,8 +68,8 @@  namespace __profile
       { }
 
       explicit
-      forward_list(size_type __n)
-      : _Base(__n)
+      forward_list(size_type __n, const _Alloc& __al = _Alloc())
+      : _Base(__n, __al)
       { }
 
       forward_list(size_type __n, const _Tp& __value,
@@ -103,11 +107,9 @@  namespace __profile
 
       forward_list&
       operator=(forward_list&& __list)
+      noexcept(_Node_alloc_traits::_S_nothrow_move())
       {
-	// NB: DR 1204.
-	// NB: DR 675.
-	_Base::clear();
-	_Base::swap(__list);
+	static_cast<_Base&>(*this) = std::move(__list);
 	return *this;
       }
 
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 8a18026..f7725ed 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -181,7 +181,8 @@  namespace __gnu_debug
     "attempt to self move assign",
     "attempt to access container with out-of-bounds bucket index %2;,"
     " container only holds %3; buckets",
-    "load factor shall be positive"
+    "load factor shall be positive",
+    "allocators must be equal"
   };
 
   void
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc
index 60d83d4..1d1e217 100644
--- a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc
@@ -25,6 +25,23 @@  struct T { int i; };
 
 using __gnu_test::propagating_allocator;
 
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return false;
+}
+
 void test01()
 {
   bool test __attribute__((unused)) = true;
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc
index 808753e..2ca19db 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc
@@ -1,4 +1,4 @@ 
-// Copyright (C) 2011 Free Software Foundation
+// Copyright (C) 2011-2012 Free Software Foundation
 //
 // 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
@@ -25,6 +25,23 @@  struct T { int i; };
 
 using __gnu_test::propagating_allocator;
 
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return false;
+}
+
 void test01()
 {
   bool test __attribute__((unused)) = true;