aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Voutilainen <ville.voutilainen@gmail.com>2016-10-11 01:08:58 +0300
committerVille Voutilainen <ville@gcc.gnu.org>2016-10-11 01:08:58 +0300
commit1725d05d199fc256844040d2900d5ee206c9d289 (patch)
treec60362f3d076a1ba42ebcccf84d7b65f06bfa9e1
parent496f8eead85efa20e9b17bca6039dde2b46f08c4 (diff)
downloadgcc-1725d05d199fc256844040d2900d5ee206c9d289.zip
gcc-1725d05d199fc256844040d2900d5ee206c9d289.tar.gz
gcc-1725d05d199fc256844040d2900d5ee206c9d289.tar.bz2
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
-rw-r--r--libstdc++-v3/ChangeLog20
-rw-r--r--libstdc++-v3/include/std/any21
-rw-r--r--libstdc++-v3/testsuite/20_util/any/assign/2.cc55
-rw-r--r--libstdc++-v3/testsuite/20_util/any/assign/exception.cc77
-rw-r--r--libstdc++-v3/testsuite/20_util/any/cons/2.cc47
-rw-r--r--libstdc++-v3/testsuite/20_util/any/cons/explicit.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc2
7 files changed, 223 insertions, 29 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 7987c5e..411474c 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,23 @@
+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>
* doc/xml/manual/appendix_contributing.xml (contrib.organization):
diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any
index 9160035..45a2145 100644
--- a/libstdc++-v3/include/std/any
+++ b/libstdc++-v3/include/std/any
@@ -179,6 +179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename _Tp = _Decay<_ValueType>,
typename _Mgr = _Manager<_Tp>,
__any_constructible_t<_Tp, _Args&&...> = false>
+ explicit
any(in_place_type_t<_ValueType>, _Args&&... __args)
: _M_manager(&_Mgr::_S_manage)
{
@@ -192,6 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename _Mgr = _Manager<_Tp>,
__any_constructible_t<_Tp, initializer_list<_Up>,
_Args&&...> = false>
+ explicit
any(in_place_type_t<_ValueType>,
initializer_list<_Up> __il, _Args&&... __args)
: _M_manager(&_Mgr::_S_manage)
@@ -207,16 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Copy the state of another object.
any& operator=(const any& __rhs)
{
- if (!__rhs.has_value())
- 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);
- }
+ *this = any(__rhs);
return *this;
}
@@ -231,8 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
reset();
else if (this != &__rhs)
{
- if (has_value())
- _M_manager(_Op_destroy, this, nullptr);
+ reset();
_Arg __arg;
__arg._M_any = this;
__rhs._M_manager(_Op_xfer, &__rhs, &__arg);
@@ -243,7 +235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Store a copy of @p __rhs as the contained object.
template<typename _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)
{
*this = any(std::forward<_ValueType>(__rhs));
@@ -556,7 +548,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__ptr->~_Tp();
break;
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();
__arg->_M_any->_M_manager = __any->_M_manager;
const_cast<any*>(__any)->_M_manager = nullptr;
diff --git a/libstdc++-v3/testsuite/20_util/any/assign/2.cc b/libstdc++-v3/testsuite/20_util/any/assign/2.cc
index b333e5d..28f06a0 100644
--- a/libstdc++-v3/testsuite/20_util/any/assign/2.cc
+++ b/libstdc++-v3/testsuite/20_util/any/assign/2.cc
@@ -24,28 +24,69 @@
using std::any;
using std::any_cast;
+bool moved = false;
+bool copied = false;
+
struct X
{
- bool moved = false;
- bool moved_from = false;
X() = default;
- X(const X&) = default;
- X(X&& x) : moved(true) { x.moved_from = true; }
+ X(const X&) { copied = true; }
+ X(X&& x) { moved = true; }
+};
+
+struct X2
+{
+ X2() = default;
+ X2(const X2&) { copied = true; }
+ X2(X2&& x) noexcept { moved = true; }
};
void test01()
{
+ moved = false;
X x;
any a1;
a1 = x;
- VERIFY(x.moved_from == false);
+ VERIFY(moved == false);
any a2;
+ copied = false;
a2 = std::move(x);
- VERIFY(x.moved_from == true);
- VERIFY(any_cast<X&>(a2).moved == true );
+ VERIFY(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()
{
test01();
+ test02();
+ test03();
}
diff --git a/libstdc++-v3/testsuite/20_util/any/assign/exception.cc b/libstdc++-v3/testsuite/20_util/any/assign/exception.cc
new file mode 100644
index 0000000..11a1a55
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/any/assign/exception.cc
@@ -0,0 +1,77 @@
+// { 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);
+ }
+}
diff --git a/libstdc++-v3/testsuite/20_util/any/cons/2.cc b/libstdc++-v3/testsuite/20_util/any/cons/2.cc
index 613fa62..be410cd 100644
--- a/libstdc++-v3/testsuite/20_util/any/cons/2.cc
+++ b/libstdc++-v3/testsuite/20_util/any/cons/2.cc
@@ -24,26 +24,59 @@
using std::any;
using std::any_cast;
+bool moved = false;
+bool copied = false;
+
struct X
{
- bool moved = false;
- bool moved_from = false;
X() = default;
- X(const X&) = default;
- X(X&& x) : moved(true) { x.moved_from = true; }
+ X(const X&) { copied = true; }
+ X(X&& x) { moved = true; }
+};
+
+struct X2
+{
+ X2() = default;
+ X2(const X2&) { copied = true; }
+ X2(X2&& x) noexcept { moved = true; }
};
void test01()
{
+ moved = false;
X x;
any a1(x);
- VERIFY(x.moved_from == false);
+ VERIFY(moved == false);
any a2(std::move(x));
- VERIFY(x.moved_from == true);
- VERIFY(any_cast<X&>(a2).moved == true );
+ VERIFY(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()
{
test01();
+ test02();
+ test03();
}
diff --git a/libstdc++-v3/testsuite/20_util/any/cons/explicit.cc b/libstdc++-v3/testsuite/20_util/any/cons/explicit.cc
new file mode 100644
index 0000000..61d5035
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/any/cons/explicit.cc
@@ -0,0 +1,30 @@
+// { 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" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
index 05fdeb7..8b30666 100644
--- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
@@ -26,5 +26,5 @@ void test01()
using std::any_cast;
const any y(1);
- any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 440 }
+ any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 432 }
}