From patchwork Sun Apr 1 22:09:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 149994 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 5A44DB6F6E for ; Mon, 2 Apr 2012 08:10:23 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1333923025; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=f4s8Jpf QTHxmKY5eoGFEq9wJe9c=; b=C3UzuTel0kkMT34bKHtjnHRjIC29O3hFUqYokEF G2ZgHsIdY2aTJV5ut64nKXNayIakUzBpPM1Jgk+1feNmmQTMZG25kSGGIdyGE5DN Zfw9oBkpPkSjqikFqg+7bbRalWvlH6d9p4az7NpF3vMf75/cQWPiamRIH6eZT1Js OjUc= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=LiR62DK9l54sD4cPna80Hi95ESdMaUupD/2glMLa/7Cv1WCrCdTSsdVt685IeE YnGxBd6WvbtWQkR3UKJFJZ5a6j0nJXKPWQk3WWGGH3oWK+U2l8P9wskZipVFvyhu l7Q2lsir66RAWE59wLr0RMKCmn8+MhKdchiaJ8OaY4UZY=; Received: (qmail 4330 invoked by alias); 1 Apr 2012 22:10:17 -0000 Received: (qmail 4135 invoked by uid 22791); 1 Apr 2012 22:10:14 -0000 X-SWARE-Spam-Status: No, hits=-4.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE X-Spam-Check-By: sourceware.org Received: from mail-lpp01m010-f47.google.com (HELO mail-lpp01m010-f47.google.com) (209.85.215.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 01 Apr 2012 22:09:56 +0000 Received: by lagw12 with SMTP id w12so2738921lag.20 for ; Sun, 01 Apr 2012 15:09:55 -0700 (PDT) MIME-Version: 1.0 Received: by 10.152.146.163 with SMTP id td3mr6964901lab.31.1333318194972; Sun, 01 Apr 2012 15:09:54 -0700 (PDT) Received: by 10.112.85.98 with HTTP; Sun, 1 Apr 2012 15:09:54 -0700 (PDT) Date: Sun, 1 Apr 2012 23:09:54 +0100 Message-ID: Subject: [v3] fix libstdc++/52591 From: Jonathan Wakely To: "libstdc++" , gcc-patches Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This allows move-assignment for std::vector when T is not MoveAssignable but the allocator is moved or equal, as a QoI extension. It also makes the code a bit cleaner and simpler, so I plan to use the same pattern as I make the rest of the library meet the allocator-aware container requirements. 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. Tested x86_64-linux, committed to trunk. After this has been on the trunk for a while I plan to apply it to the 4.7 branch too. commit e08d4fbd65667448fd93505acefc4828baff7a69 Author: Jonathan Wakely Date: Fri Mar 16 22:22:31 2012 +0000 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. diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 239f8b9..31660d3 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -428,36 +428,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @brief %Vector move assignment operator. * @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. */ vector& operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) { - if (_Alloc_traits::_S_propagate_on_move_assign()) - { - // We're moving the rvalue's allocator so can move the data too. - const vector __tmp(std::move(*this)); // discard existing data - this->_M_impl._M_swap_data(__x._M_impl); - 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(); - } + constexpr bool __move_storage = + _Alloc_traits::_S_propagate_on_move_assign() + || _Alloc_traits::_S_always_equal(); + _M_move_assign(std::move(__x), + integral_constant()); return *this; } @@ -1363,6 +1345,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator()); 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 }; diff --git a/libstdc++-v3/testsuite/23_containers/vector/52591.cc b/libstdc++-v3/testsuite/23_containers/vector/52591.cc new file mode 100644 index 0000000..c018c72 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/52591.cc @@ -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 +// . + +// { dg-do compile } +// { dg-options "-std=gnu++0x" } + +// libstdc++/52591 + +#include + +// 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 a; + a = std::vector(); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc index 73de8ae..644750c 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1251 } +// { dg-error "no matching" "" { target *-*-* } 1233 } #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc index fa479c7..bbd4cfe 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1181 } +// { dg-error "no matching" "" { target *-*-* } 1163 } #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc index 231cace..d2282cc 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1181 } +// { dg-error "no matching" "" { target *-*-* } 1163 } #include #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc index b8e18bb..d2cde66 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1292 } +// { dg-error "no matching" "" { target *-*-* } 1274 } #include