libstdc++/77334 move assign RB trees of non-copyable types
authorJonathan Wakely <jwakely@redhat.com>
Tue, 23 Aug 2016 13:15:12 +0000 (14:15 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 23 Aug 2016 13:15:12 +0000 (14:15 +0100)
PR libstdc++/77334
* include/bits/stl_tree.h (_Rb_tree::_M_move_assign): New functions.
(_Rb_tree::operator=(_Rb_tree&&)): Dispatch to _M_move_assign.
* testsuite/23_containers/map/77334.cc: New test.

From-SVN: r239698

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_tree.h
libstdc++-v3/testsuite/23_containers/map/77334.cc [new file with mode: 0644]

index ddbbb73d3ccf67acdf73dcffb9a10001187890af..5e943b130d81d27a427bca6b08d42c02e9bea6ad 100644 (file)
@@ -1,5 +1,10 @@
 2016-08-23  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/77334
+       * include/bits/stl_tree.h (_Rb_tree::_M_move_assign): New functions.
+       (_Rb_tree::operator=(_Rb_tree&&)): Dispatch to _M_move_assign.
+       * testsuite/23_containers/map/77334.cc: New test.
+
        * doc/xml/manual/using.xml: Remove reference to -pthreads option.
        * doc/html/*: Regenerate.
 
index 8697a711a5f5c367b471193677d7de0d59f46b99..25580e4cc5c6eba6a92a3cee8f873c0a29fb778c 100644 (file)
@@ -1264,6 +1264,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // which might result in a copy not a move.
       void
       _M_move_data(_Rb_tree&, std::false_type);
+
+      // Move assignment from container with equal allocator.
+      void
+      _M_move_assign(_Rb_tree&, std::true_type);
+
+      // Move assignment from container with possibly non-equal allocator,
+      // which might result in a copy not a move.
+      void
+      _M_move_assign(_Rb_tree&, std::false_type);
 #endif
     };
 
@@ -1379,24 +1388,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
+    inline void
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    operator=(_Rb_tree&& __x)
-    noexcept(_Alloc_traits::_S_nothrow_move()
-            && is_nothrow_move_assignable<_Compare>::value)
+    _M_move_assign(_Rb_tree& __x, true_type)
     {
-      _M_impl._M_key_compare = __x._M_impl._M_key_compare;
-      if (_Alloc_traits::_S_propagate_on_move_assign()
-         || _Alloc_traits::_S_always_equal()
-         || _M_get_Node_allocator() == __x._M_get_Node_allocator())
-       {
-         clear();
-         if (__x._M_root() != nullptr)
-           _M_move_data(__x, std::true_type());
-         std::__alloc_on_move(_M_get_Node_allocator(),
-                              __x._M_get_Node_allocator());
-         return *this;
-       }
+      clear();
+      if (__x._M_root() != nullptr)
+       _M_move_data(__x, std::true_type());
+      std::__alloc_on_move(_M_get_Node_allocator(),
+                          __x._M_get_Node_allocator());
+    }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    void
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+    _M_move_assign(_Rb_tree& __x, false_type)
+    {
+      if (_M_get_Node_allocator() == __x._M_get_Node_allocator())
+       return _M_move_assign(__x, true_type{});
 
       // Try to move each node reusing existing nodes and copying __x nodes
       // structure.
@@ -1416,6 +1426,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_impl._M_node_count = __x._M_impl._M_node_count;
          __x.clear();
        }
+    }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    inline _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+    operator=(_Rb_tree&& __x)
+    noexcept(_Alloc_traits::_S_nothrow_move()
+            && is_nothrow_move_assignable<_Compare>::value)
+    {
+      _M_impl._M_key_compare = __x._M_impl._M_key_compare;
+      constexpr bool __move_storage =
+         _Alloc_traits::_S_propagate_on_move_assign()
+         || _Alloc_traits::_S_always_equal();
+      _M_move_assign(__x, __bool_constant<__move_storage>());
       return *this;
     }
 
diff --git a/libstdc++-v3/testsuite/23_containers/map/77334.cc b/libstdc++-v3/testsuite/23_containers/map/77334.cc
new file mode 100644 (file)
index 0000000..917896b
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 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 <map>
+
+struct A { A(A&&) = delete; };
+
+void test01()
+{
+   std::map<int, A> m1, m2;
+   m2 = std::move(m1);
+}