From: Jonathan Wakely Date: Sat, 2 May 2015 12:38:44 +0000 (+0100) Subject: any (any::_Storage): Make non-copyable. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9407c6fa534498ea87bbd6640cc212016779cd52;p=gcc.git any (any::_Storage): Make non-copyable. * include/experimental/any (any::_Storage): Make non-copyable. (any::any): Do not copy _Storage object. (any::operator=): Implement more efficiently than swapping. (any::swap): Use new _Op_xfer operation. (any::_Op::_Op_xfer): New enumerator. (_Manager_internal::_S_alloc): Remove unused function. (_Manager_internal::_S_create, _Manager_external::_S_create): Use out parameter instead of returning a _Storage object. (_Manager_internal::_S_manage, _Manager_external::_S_manage): Add _Op_xfer operation for moving and swapping. * testsuite/experimental/any/cons/nontrivial.cc: New. * testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error. From-SVN: r222721 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d9e58d0cf19..9ebae195eda 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,18 @@ 2015-05-02 Jonathan Wakely + * include/experimental/any (any::_Storage): Make non-copyable. + (any::any): Do not copy _Storage object. + (any::operator=): Implement more efficiently than swapping. + (any::swap): Use new _Op_xfer operation. + (any::_Op::_Op_xfer): New enumerator. + (_Manager_internal::_S_alloc): Remove unused function. + (_Manager_internal::_S_create, _Manager_external::_S_create): Use out + parameter instead of returning a _Storage object. + (_Manager_internal::_S_manage, _Manager_external::_S_manage): Add + _Op_xfer operation for moving and swapping. + * testsuite/experimental/any/cons/nontrivial.cc: New. + * testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error. + * include/experimental/fs_path.h (filesystem_error::~filesystem_error): Declare. * src/filesystem/path.cc (filesystem_error::~filesystem_error): diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index 8c205d5cad0..b2d1b9c1e48 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -90,6 +90,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Holds either pointer to a heap object or the contained object itself. union _Storage { + // This constructor intentionally doesn't initialize anything. + _Storage() = default; + + // Prevent trivial copies of this type, buffer might hold a non-POD. + _Storage(const _Storage&) = delete; + _Storage& operator=(const _Storage&) = delete; + void* _M_ptr; std::aligned_storage::type _M_buffer; }; @@ -119,33 +126,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION any() noexcept : _M_manager(nullptr) { } /// Copy constructor, copies the state of @p __other - any(const any& __other) : _M_manager(__other._M_manager) + any(const any& __other) { - if (!__other.empty()) + if (__other.empty()) + _M_manager = nullptr; + else { _Arg __arg; __arg._M_any = this; - _M_manager(_Op_clone, &__other, &__arg); + __other._M_manager(_Op_clone, &__other, &__arg); } } /** * @brief Move constructor, transfer the state from @p __other * - * @post @c __other.empty() (not guaranteed for other implementations) + * @post @c __other.empty() (this postcondition is a GNU extension) */ any(any&& __other) noexcept - : _M_manager(__other._M_manager), - _M_storage(__other._M_storage) - { __other._M_manager = nullptr; } + { + if (__other.empty()) + _M_manager = nullptr; + else + { + _Arg __arg; + __arg._M_any = this; + __other._M_manager(_Op_xfer, &__other, &__arg); + } + } /// Construct with a copy of @p __value as the contained object. template , typename _Mgr = _Manager<_Tp>> any(_ValueType&& __value) - : _M_manager(&_Mgr::_S_manage), - _M_storage(_Mgr::_S_create(std::forward<_ValueType>(__value))) + : _M_manager(&_Mgr::_S_manage) { + _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value)); static_assert(is_copy_constructible<_Tp>::value, "The contained object must be CopyConstructible"); } @@ -155,10 +171,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // assignments - /// Copy the state of + /// Copy the state of another object. any& operator=(const any& __rhs) { - any(__rhs).swap(*this); + if (__rhs.empty()) + clear(); + else + { + if (!empty()) + _M_manager(_Op_destroy, this, nullptr); + _Arg __arg; + __arg._M_any = this; + __rhs._M_manager(_Op_clone, &__rhs, &__arg); + } return *this; } @@ -169,7 +194,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ any& operator=(any&& __rhs) noexcept { - any(std::move(__rhs)).swap(*this); + if (__rhs.empty()) + clear(); + else + { + if (!empty()) + _M_manager(_Op_destroy, this, nullptr); + _Arg __arg; + __arg._M_any = this; + __rhs._M_manager(_Op_xfer, &__rhs, &__arg); + } return *this; } @@ -177,7 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template any& operator=(_ValueType&& __rhs) { - any(std::forward<_ValueType>(__rhs)).swap(*this); + *this = any(std::forward<_ValueType>(__rhs)); return *this; } @@ -195,10 +229,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Exchange state with another object. void swap(any& __rhs) noexcept - { - std::swap(_M_manager, __rhs._M_manager); - std::swap(_M_storage, __rhs._M_storage); - } + { + if (empty() && __rhs.empty()) + return; + + if (!empty() && !__rhs.empty()) + { + any __tmp; + _Arg __arg; + __arg._M_any = &__tmp; + __rhs._M_manager(_Op_xfer, &__rhs, &__arg); + __arg._M_any = &__rhs; + _M_manager(_Op_xfer, this, &__arg); + __arg._M_any = this; + __tmp._M_manager(_Op_xfer, &__tmp, &__arg); + } + else + { + any* __empty = empty() ? this : &__rhs; + any* __full = empty() ? &__rhs : this; + _Arg __arg; + __arg._M_any = __empty; + __full->_M_manager(_Op_xfer, __full, &__arg); + } + } // observers @@ -222,7 +276,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __or_, is_copy_constructible<_Tp>>::value; } private: - enum _Op { _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy }; + enum _Op { + _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer + }; union _Arg { @@ -252,20 +308,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_manage(_Op __which, const any* __anyp, _Arg* __arg); template - static _Storage - _S_create(_Up&& __value) + static void + _S_create(_Storage& __storage, _Up&& __value) { - _Storage __storage; void* __addr = &__storage._M_buffer; ::new (__addr) _Tp(std::forward<_Up>(__value)); - return __storage; - } - - template - static _Storage - _S_alloc(const _Alloc&, _Up&& __value) - { - return _S_create(std::forward<_Up>(__value)); } }; @@ -277,12 +324,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_manage(_Op __which, const any* __anyp, _Arg* __arg); template - static _Storage - _S_create(_Up&& __value) + static void + _S_create(_Storage& __storage, _Up&& __value) { - _Storage __storage; __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); - return __storage; } }; }; @@ -393,10 +438,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION break; case _Op_clone: ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); + __arg->_M_any->_M_manager = __any->_M_manager; break; case _Op_destroy: __ptr->~_Tp(); break; + case _Op_xfer: + ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); + __ptr->~_Tp(); + __arg->_M_any->_M_manager = __any->_M_manager; + const_cast(__any)->_M_manager = nullptr; + break; } } @@ -419,10 +471,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION break; case _Op_clone: __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); + __arg->_M_any->_M_manager = __any->_M_manager; break; case _Op_destroy: delete __ptr; break; + case _Op_xfer: + __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr; + __arg->_M_any->_M_manager = __any->_M_manager; + const_cast(__any)->_M_manager = nullptr; + break; } } diff --git a/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc new file mode 100644 index 00000000000..14b77655c48 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2015 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-options "-std=gnu++14" } + +#include +#include + +struct LocationAware +{ + LocationAware() { } + ~LocationAware() { VERIFY(self == this); } + LocationAware(const LocationAware&) { } + LocationAware& operator=(const LocationAware&) { return *this; } + LocationAware(LocationAware&&) noexcept { } + LocationAware& operator=(LocationAware&&) noexcept { return *this; } + + void* const self = this; +}; +static_assert(std::is_nothrow_move_constructible::value, ""); +static_assert(!std::is_trivially_copyable::value, ""); + +using std::experimental::any; + +void +test01() +{ + + LocationAware l; + any a = l; +} + +void +test02() +{ + LocationAware l; + any a = l; + any b = a; + { + any tmp = std::move(a); + a = std::move(b); + b = std::move(tmp); + } +} + +void +test03() +{ + LocationAware l; + any a = l; + any b = a; + swap(a, b); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc index f1992d95444..5823175cbeb 100644 --- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc @@ -26,5 +26,5 @@ void test01() using std::experimental::any_cast; const any y(1); - any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 310 } + any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 355 } }