From a3f6007cbc84242c088097e46602a65f9654a349 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 24 Oct 2016 16:22:11 +0300 Subject: [PATCH] Cross-port exception-safety and move fixes of std::any to std::experimental::any. Cross-port exception-safety and move fixes of std::any to std::experimental::any. * include/experimental/any (operator=(const any&)): Make strongly exception-safe. (operator=(any&&)): clear() unconditionally in the case where rhs has a value. (_Manager_internal<_Tp>::_S_manage): Move in _Op_xfer, don't copy. * testsuite/experimental/any/assign/2.cc: Adjust. * testsuite/experimental/any/assign/exception.cc: New. * testsuite/experimental/any/cons/2.cc: Adjust. * testsuite/experimental/any/misc/any_cast_neg.cc: Ajust. From-SVN: r241479 --- libstdc++-v3/ChangeLog | 14 ++++ libstdc++-v3/include/experimental/any | 17 +--- .../testsuite/experimental/any/assign/2.cc | 56 ++++++++++++-- .../experimental/any/assign/exception.cc | 77 +++++++++++++++++++ .../testsuite/experimental/any/cons/2.cc | 47 +++++++++-- .../experimental/any/misc/any_cast_neg.cc | 2 +- 6 files changed, 185 insertions(+), 28 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/any/assign/exception.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1a18edeec77..5937af9daa5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2016-10-24 Ville Voutilainen + + Cross-port exception-safety and move fixes of std::any to + std::experimental::any. + * include/experimental/any (operator=(const any&)): + Make strongly exception-safe. + (operator=(any&&)): clear() unconditionally in the case where + rhs has a value. + (_Manager_internal<_Tp>::_S_manage): Move in _Op_xfer, don't copy. + * testsuite/experimental/any/assign/2.cc: Adjust. + * testsuite/experimental/any/assign/exception.cc: New. + * testsuite/experimental/any/cons/2.cc: Adjust. + * testsuite/experimental/any/misc/any_cast_neg.cc: Ajust. + 2016-10-24 Ville Voutilainen Cross-port the latest resolution of LWG2756 and some diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index 5e091a45dda..8fd66e29a52 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -191,16 +191,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Copy the state of another object. any& operator=(const any& __rhs) { - if (__rhs.empty()) - clear(); - else if (this != &__rhs) - { - if (!empty()) - _M_manager(_Op_destroy, this, nullptr); - _Arg __arg; - __arg._M_any = this; - __rhs._M_manager(_Op_clone, &__rhs, &__arg); - } + *this = any(__rhs); return *this; } @@ -215,8 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION clear(); else if (this != &__rhs) { - if (!empty()) - _M_manager(_Op_destroy, this, nullptr); + clear(); _Arg __arg; __arg._M_any = this; __rhs._M_manager(_Op_xfer, &__rhs, &__arg); @@ -485,7 +475,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)->_M_manager = nullptr; diff --git a/libstdc++-v3/testsuite/experimental/any/assign/2.cc b/libstdc++-v3/testsuite/experimental/any/assign/2.cc index 7022878f795..0232af6c6d2 100644 --- a/libstdc++-v3/testsuite/experimental/any/assign/2.cc +++ b/libstdc++-v3/testsuite/experimental/any/assign/2.cc @@ -23,28 +23,70 @@ using std::experimental::any; using std::experimental::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(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/experimental/any/assign/exception.cc b/libstdc++-v3/testsuite/experimental/any/assign/exception.cc new file mode 100644 index 00000000000..f125213ded1 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/assign/exception.cc @@ -0,0 +1,77 @@ +// { dg-do run { target c++14 } } + +// 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 +// . + +#include +#include + +using std::experimental::any; +using std::experimental::any_cast; + +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() +{ + any a1 = Good(); + del_count = 0; + try { + Bad b; + any a2 = b; + should_throw = true; + a1 = a2; + } catch (...) { + auto x = any_cast(a1); + VERIFY( del_count == 0 ); + VERIFY( !a1.empty() ); + any_cast(a1); + } + any a3 = Good(); + del_count = 0; + try { + Bad2 b; + any a4 = b; + should_throw = true; + a3 = a4; + } catch (...) { + auto x = any_cast(a1); + VERIFY( del_count == 0 ); + VERIFY( !a1.empty() ); + any_cast(a1); + } +} diff --git a/libstdc++-v3/testsuite/experimental/any/cons/2.cc b/libstdc++-v3/testsuite/experimental/any/cons/2.cc index fef713d99a5..c79573b3ea9 100644 --- a/libstdc++-v3/testsuite/experimental/any/cons/2.cc +++ b/libstdc++-v3/testsuite/experimental/any/cons/2.cc @@ -23,26 +23,59 @@ using std::experimental::any; using std::experimental::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(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/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc index 43105724938..924e798854e 100644 --- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc @@ -25,5 +25,5 @@ void test01() using std::experimental::any_cast; const any y(1); - any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 369 } + any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 359 } } -- 2.30.2