Commit 1725d05d by Ville Voutilainen Committed by Ville Voutilainen

Make any's copy assignment operator exception-safe,

don't copy the underlying value when any is moved,
make in_place constructors explicit.
* include/std/any (any(in_place_type_t<_ValueType>, _Args&&...)):
Make explicit.
(any(in_place_type_t<_ValueType>, initializer_list<_Up>, _Args&&...)):
Likewise.
(operator=(const any&)): Make strongly exception-safe.
(operator=(any&&)): reset() unconditionally in the case where
rhs has a value.
(operator=(_ValueType&&)): Indent the return type.
(_Manager_internal<_Tp>::_S_manage): Move in _Op_xfer, don't copy.
* testsuite/20_util/any/assign/2.cc: Adjust.
* testsuite/20_util/any/assign/exception.cc: New.
* testsuite/20_util/any/cons/2.cc: Adjust.
* testsuite/20_util/any/cons/explicit.cc: New.
* testsuite/20_util/any/misc/any_cast_neg.cc: Ajust.

From-SVN: r240951
parent 496f8eea
2016-10-10 Ville Voutilainen <ville.voutilainen@gmail.com>
Make any's copy assignment operator exception-safe,
don't copy the underlying value when any is moved,
make in_place constructors explicit.
* include/std/any (any(in_place_type_t<_ValueType>, _Args&&...)):
Make explicit.
(any(in_place_type_t<_ValueType>, initializer_list<_Up>, _Args&&...)):
Likewise.
(operator=(const any&)): Make strongly exception-safe.
(operator=(any&&)): reset() unconditionally in the case where
rhs has a value.
(operator=(_ValueType&&)): Indent the return type.
(_Manager_internal<_Tp>::_S_manage): Move in _Op_xfer, don't copy.
* testsuite/20_util/any/assign/2.cc: Adjust.
* testsuite/20_util/any/assign/exception.cc: New.
* testsuite/20_util/any/cons/2.cc: Adjust.
* testsuite/20_util/any/cons/explicit.cc: New.
* testsuite/20_util/any/misc/any_cast_neg.cc: Ajust.
2016-10-10 Jonathan Wakely <jwakely@redhat.com> 2016-10-10 Jonathan Wakely <jwakely@redhat.com>
* doc/xml/manual/appendix_contributing.xml (contrib.organization): * doc/xml/manual/appendix_contributing.xml (contrib.organization):
......
...@@ -179,6 +179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -179,6 +179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename _Tp = _Decay<_ValueType>, typename _Tp = _Decay<_ValueType>,
typename _Mgr = _Manager<_Tp>, typename _Mgr = _Manager<_Tp>,
__any_constructible_t<_Tp, _Args&&...> = false> __any_constructible_t<_Tp, _Args&&...> = false>
explicit
any(in_place_type_t<_ValueType>, _Args&&... __args) any(in_place_type_t<_ValueType>, _Args&&... __args)
: _M_manager(&_Mgr::_S_manage) : _M_manager(&_Mgr::_S_manage)
{ {
...@@ -192,6 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -192,6 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename _Mgr = _Manager<_Tp>, typename _Mgr = _Manager<_Tp>,
__any_constructible_t<_Tp, initializer_list<_Up>, __any_constructible_t<_Tp, initializer_list<_Up>,
_Args&&...> = false> _Args&&...> = false>
explicit
any(in_place_type_t<_ValueType>, any(in_place_type_t<_ValueType>,
initializer_list<_Up> __il, _Args&&... __args) initializer_list<_Up> __il, _Args&&... __args)
: _M_manager(&_Mgr::_S_manage) : _M_manager(&_Mgr::_S_manage)
...@@ -207,16 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -207,16 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Copy the state of another object. /// Copy the state of another object.
any& operator=(const any& __rhs) any& operator=(const any& __rhs)
{ {
if (!__rhs.has_value()) *this = any(__rhs);
reset();
else if (this != &__rhs)
{
if (has_value())
_M_manager(_Op_destroy, this, nullptr);
_Arg __arg;
__arg._M_any = this;
__rhs._M_manager(_Op_clone, &__rhs, &__arg);
}
return *this; return *this;
} }
...@@ -231,8 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -231,8 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
reset(); reset();
else if (this != &__rhs) else if (this != &__rhs)
{ {
if (has_value()) reset();
_M_manager(_Op_destroy, this, nullptr);
_Arg __arg; _Arg __arg;
__arg._M_any = this; __arg._M_any = this;
__rhs._M_manager(_Op_xfer, &__rhs, &__arg); __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
...@@ -243,7 +235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -243,7 +235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Store a copy of @p __rhs as the contained object. /// Store a copy of @p __rhs as the contained object.
template<typename _ValueType, template<typename _ValueType,
typename _Tp = _Decay<_ValueType>> typename _Tp = _Decay<_ValueType>>
enable_if_t<is_copy_constructible<_Tp>::value, any&> enable_if_t<is_copy_constructible<_Tp>::value, any&>
operator=(_ValueType&& __rhs) operator=(_ValueType&& __rhs)
{ {
*this = any(std::forward<_ValueType>(__rhs)); *this = any(std::forward<_ValueType>(__rhs));
...@@ -556,7 +548,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -556,7 +548,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__ptr->~_Tp(); __ptr->~_Tp();
break; break;
case _Op_xfer: case _Op_xfer:
::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp
(std::move(*const_cast<_Tp*>(__ptr)));
__ptr->~_Tp(); __ptr->~_Tp();
__arg->_M_any->_M_manager = __any->_M_manager; __arg->_M_any->_M_manager = __any->_M_manager;
const_cast<any*>(__any)->_M_manager = nullptr; const_cast<any*>(__any)->_M_manager = nullptr;
......
...@@ -24,28 +24,69 @@ ...@@ -24,28 +24,69 @@
using std::any; using std::any;
using std::any_cast; using std::any_cast;
bool moved = false;
bool copied = false;
struct X struct X
{ {
bool moved = false;
bool moved_from = false;
X() = default; X() = default;
X(const X&) = default; X(const X&) { copied = true; }
X(X&& x) : moved(true) { x.moved_from = true; } X(X&& x) { moved = true; }
};
struct X2
{
X2() = default;
X2(const X2&) { copied = true; }
X2(X2&& x) noexcept { moved = true; }
}; };
void test01() void test01()
{ {
moved = false;
X x; X x;
any a1; any a1;
a1 = x; a1 = x;
VERIFY(x.moved_from == false); VERIFY(moved == false);
any a2; any a2;
copied = false;
a2 = std::move(x); a2 = std::move(x);
VERIFY(x.moved_from == true); VERIFY(moved == true);
VERIFY(any_cast<X&>(a2).moved == true ); VERIFY(copied == false);
}
void test02()
{
moved = false;
X x;
any a1;
a1 = x;
VERIFY(moved == false);
any a2;
copied = false;
a2 = std::move(a1);
VERIFY(moved == false);
VERIFY(copied == false);
}
void test03()
{
moved = false;
X2 x;
any a1;
a1 = x;
VERIFY(copied && moved);
any a2;
moved = false;
copied = false;
a2 = std::move(a1);
VERIFY(moved == true);
VERIFY(copied == false);
} }
int main() int main()
{ {
test01(); test01();
test02();
test03();
} }
// { dg-options "-std=gnu++17" }
// { dg-do run }
// 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/>.
#include <any>
#include <testsuite_hooks.h>
using std::any;
bool should_throw = false;
struct Bad
{
Bad() = default;
Bad(const Bad&) {if (should_throw) throw 666;}
};
struct Bad2
{
Bad2() = default;
Bad2(const Bad2&) {if (should_throw) throw 666;}
Bad2(Bad2&&) noexcept {}
};
int del_count = 0;
struct Good
{
Good() = default;
Good(const Good&) = default;
Good(Good&&) = default;
~Good() {++del_count;}
};
int main()
{
std::any a1 = Good();
del_count = 0;
try {
Bad b;
std::any a2 = b;
should_throw = true;
a1 = a2;
} catch (...) {
auto x = std::any_cast<Good>(a1);
assert(del_count == 0);
assert(a1.has_value());
std::any_cast<Good>(a1);
}
std::any a3 = Good();
del_count = 0;
try {
Bad2 b;
std::any a4 = b;
should_throw = true;
a3 = a4;
} catch (...) {
auto x = std::any_cast<Good>(a1);
assert(del_count == 0);
assert(a1.has_value());
std::any_cast<Good>(a1);
}
}
...@@ -24,26 +24,59 @@ ...@@ -24,26 +24,59 @@
using std::any; using std::any;
using std::any_cast; using std::any_cast;
bool moved = false;
bool copied = false;
struct X struct X
{ {
bool moved = false;
bool moved_from = false;
X() = default; X() = default;
X(const X&) = default; X(const X&) { copied = true; }
X(X&& x) : moved(true) { x.moved_from = true; } X(X&& x) { moved = true; }
};
struct X2
{
X2() = default;
X2(const X2&) { copied = true; }
X2(X2&& x) noexcept { moved = true; }
}; };
void test01() void test01()
{ {
moved = false;
X x; X x;
any a1(x); any a1(x);
VERIFY(x.moved_from == false); VERIFY(moved == false);
any a2(std::move(x)); any a2(std::move(x));
VERIFY(x.moved_from == true); VERIFY(moved == true);
VERIFY(any_cast<X&>(a2).moved == true ); }
void test02()
{
moved = false;
X x;
any a1(x);
VERIFY(moved == false);
copied = false;
any a2(std::move(a1));
VERIFY(copied == false);
}
void test03()
{
moved = false;
X2 x;
any a1(x);
VERIFY(moved == false);
copied = false;
any a2(std::move(a1));
VERIFY(copied == false);
VERIFY(moved == true);
} }
int main() int main()
{ {
test01(); test01();
test02();
test03();
} }
// { dg-options "-std=gnu++17" }
// { dg-do compile }
// 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/>.
#include <any>
#include <testsuite_hooks.h>
#include <vector>
int main()
{
std::any a = {std::in_place<int>, 42}; // { dg-error "converting" }
std::any a2 =
{std::in_place<std::vector<int>>, {42, 666}}; // { dg-error "converting" }
}
...@@ -26,5 +26,5 @@ void test01() ...@@ -26,5 +26,5 @@ void test01()
using std::any_cast; using std::any_cast;
const any y(1); const any y(1);
any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 440 } any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 432 }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment