re PR libstdc++/52591 ([C++0x] [4.7 Regression] moving std::vector relies on movable elements)

PR libstdc++/52591
	* include/bits/stl_vector.h (vector::operator=(vector&&)): Dispatch
	to _M_move_assign depending on whether allocator is moved.
	(vector::_M_move_assign): Add overloaded functions.
	* testsuite/23_containers/vector/52591.cc: New.
	* testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
	Adjust dg-error line number.
	* testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
	Likewise.
	* testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
	Likewise.
	* testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
	Likewise.

From-SVN: r186057
This commit is contained in:
Jonathan Wakely 2012-04-01 22:04:54 +00:00 committed by Jonathan Wakely
parent 181c9de2a6
commit ea2c1a6d67
7 changed files with 98 additions and 29 deletions

View File

@ -1,3 +1,19 @@
2012-04-01 Jonathan Wakely <jwakely.gcc@gmail.com>
PR libstdc++/52591
* include/bits/stl_vector.h (vector::operator=(vector&&)): Dispatch
to _M_move_assign depending on whether allocator is moved.
(vector::_M_move_assign): Add overloaded functions.
* testsuite/23_containers/vector/52591.cc: New.
* testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
Adjust dg-error line number.
* testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
Likewise.
2012-04-01 Jonathan Wakely <jwakely.gcc@gmail.com> 2012-04-01 Jonathan Wakely <jwakely.gcc@gmail.com>
* include/std/functional (__callable_functor): Overload for * include/std/functional (__callable_functor): Overload for

View File

@ -428,36 +428,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* @brief %Vector move assignment operator. * @brief %Vector move assignment operator.
* @param __x A %vector of identical element and allocator types. * @param __x A %vector of identical element and allocator types.
* *
* The contents of @a __x are moved into this %vector (without copying). * The contents of @a __x are moved into this %vector (without copying,
* if the allocators permit it).
* @a __x is a valid, but unspecified %vector. * @a __x is a valid, but unspecified %vector.
*/ */
vector& vector&
operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
{ {
if (_Alloc_traits::_S_propagate_on_move_assign()) constexpr bool __move_storage =
{ _Alloc_traits::_S_propagate_on_move_assign()
// We're moving the rvalue's allocator so can move the data too. || _Alloc_traits::_S_always_equal();
const vector __tmp(std::move(*this)); // discard existing data _M_move_assign(std::move(__x),
this->_M_impl._M_swap_data(__x._M_impl); integral_constant<bool, __move_storage>());
std::__alloc_on_move(_M_get_Tp_allocator(),
__x._M_get_Tp_allocator());
}
else if (_Alloc_traits::_S_always_equal()
|| __x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
{
// The rvalue's allocator can free our storage and vice versa,
// so can swap the data storage after destroying our contents.
this->clear();
this->_M_impl._M_swap_data(__x._M_impl);
}
else
{
// The rvalue's allocator cannot be moved, or is not equal,
// so we need to individually move each element.
this->assign(std::__make_move_if_noexcept_iterator(__x.begin()),
std::__make_move_if_noexcept_iterator(__x.end()));
__x.clear();
}
return *this; return *this;
} }
@ -1363,6 +1345,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator()); std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator());
this->_M_impl._M_finish = __pos; this->_M_impl._M_finish = __pos;
} }
#ifdef __GXX_EXPERIMENTAL_CXX0X__
private:
// Constant-time move assignment when source object's memory can be
// moved, either because the source's allocator will move too
// or because the allocators are equal.
void
_M_move_assign(vector&& __x, std::true_type) noexcept
{
const vector __tmp(std::move(*this));
this->_M_impl._M_swap_data(__x._M_impl);
if (_Alloc_traits::_S_propagate_on_move_assign())
std::__alloc_on_move(_M_get_Tp_allocator(),
__x._M_get_Tp_allocator());
}
// Do move assignment when it might not be possible to move source
// object's memory, resulting in a linear-time operation.
void
_M_move_assign(vector&& __x, std::false_type)
{
if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
_M_move_assign(std::move(__x), std::true_type());
else
{
// The rvalue's allocator cannot be moved and is not equal,
// so we need to individually move each element.
this->assign(std::__make_move_if_noexcept_iterator(__x.begin()),
std::__make_move_if_noexcept_iterator(__x.end()));
__x.clear();
}
}
#endif
}; };

View File

@ -0,0 +1,38 @@
// Copyright (C) 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
// 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 }
// { dg-options "-std=gnu++0x" }
// libstdc++/52591
#include <vector>
// As an extension we allow move-assignment of std::vector when the element
// type is not MoveAssignable, as long as the allocator type propagates or
// is known to always compare equal.
struct C
{
C& operator=(C&&) = delete;
};
void test01()
{
std::vector<C> a;
a = std::vector<C>();
}

View File

@ -18,7 +18,7 @@
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-do compile } // { dg-do compile }
// { dg-error "no matching" "" { target *-*-* } 1251 } // { dg-error "no matching" "" { target *-*-* } 1233 }
#include <vector> #include <vector>

View File

@ -18,7 +18,7 @@
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-do compile } // { dg-do compile }
// { dg-error "no matching" "" { target *-*-* } 1181 } // { dg-error "no matching" "" { target *-*-* } 1163 }
#include <vector> #include <vector>

View File

@ -18,7 +18,7 @@
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-do compile } // { dg-do compile }
// { dg-error "no matching" "" { target *-*-* } 1181 } // { dg-error "no matching" "" { target *-*-* } 1163 }
#include <vector> #include <vector>
#include <utility> #include <utility>

View File

@ -18,7 +18,7 @@
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-do compile } // { dg-do compile }
// { dg-error "no matching" "" { target *-*-* } 1292 } // { dg-error "no matching" "" { target *-*-* } 1274 }
#include <vector> #include <vector>