From 2548a4d6ba4d54393ae7947a7a8c9070d9c7e113 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 14 Aug 2015 12:51:18 +0100 Subject: [PATCH] any (any::operator=(const any&)): Move check for self-assignment. * include/experimental/any (any::operator=(const any&)): Move check for self-assignment. (any::operator=(any&&)): Add check for self-assignment. (any::operator=(_ValueType&&)): Constrain template argument. (any::swap(any&)): Add check for self-swap. * testsuite/experimental/any/assign/self.cc: Test move and swap. * testsuite/experimental/any/misc/any_cast_neg.cc: Update dg-error. From-SVN: r226894 --- libstdc++-v3/ChangeLog | 10 ++++ libstdc++-v3/include/experimental/any | 59 ++++++++++--------- .../testsuite/experimental/any/assign/self.cc | 54 ++++++++++++++++- .../experimental/any/misc/any_cast_neg.cc | 2 +- 4 files changed, 94 insertions(+), 31 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 15fa9a2076f..0753951ef72 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2015-08-14 Jonathan Wakely + + * include/experimental/any (any::operator=(const any&)): Move check + for self-assignment. + (any::operator=(any&&)): Add check for self-assignment. + (any::operator=(_ValueType&&)): Constrain template argument. + (any::swap(any&)): Add check for self-swap. + * testsuite/experimental/any/assign/self.cc: Test move and swap. + * testsuite/experimental/any/misc/any_cast_neg.cc: Update dg-error. + 2015-08-14 Jonathan Wakely * include/experimental/array: Add feature-test macro. diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index fbb70a7ae55..dae82b56e2f 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -175,12 +175,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Copy the state of another object. any& operator=(const any& __rhs) { - if (this == &__rhs) - return *this; - if (__rhs.empty()) clear(); - else + else if (this != &__rhs) { if (!empty()) _M_manager(_Op_destroy, this, nullptr); @@ -200,7 +197,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (__rhs.empty()) clear(); - else + else if (this != &__rhs) { if (!empty()) _M_manager(_Op_destroy, this, nullptr); @@ -213,7 +210,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Store a copy of @p __rhs as the contained object. template - any& operator=(_ValueType&& __rhs) + enable_if_t>::value, any&> + operator=(_ValueType&& __rhs) { *this = any(std::forward<_ValueType>(__rhs)); return *this; @@ -233,30 +231,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Exchange state with another object. void swap(any& __rhs) noexcept - { - if (empty() && __rhs.empty()) - return; + { + 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); - } - } + if (!empty() && !__rhs.empty()) + { + if (this == &__rhs) + return; + + 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 diff --git a/libstdc++-v3/testsuite/experimental/any/assign/self.cc b/libstdc++-v3/testsuite/experimental/any/assign/self.cc index 0fb9566bde0..79c6f0f784d 100644 --- a/libstdc++-v3/testsuite/experimental/any/assign/self.cc +++ b/libstdc++-v3/testsuite/experimental/any/assign/self.cc @@ -18,8 +18,17 @@ // { dg-options "-std=gnu++14" } #include +#include #include +std::set live_objects; + +struct A { + A() { live_objects.insert(this); } + ~A() { live_objects.erase(this); } + A(const A& a) { VERIFY(live_objects.count(&a)); live_objects.insert(this); } +}; + void test01() { @@ -29,13 +38,56 @@ test01() a = a; VERIFY( a.empty() ); - a = 1; + a = A{}; a = a; VERIFY( !a.empty() ); + + a.clear(); + VERIFY( live_objects.empty() ); +} + +void +test02() +{ + using std::experimental::any; + + struct X { + any a; + }; + + X x; + std::swap(x, x); // results in "self-move-assignment" of X::a + VERIFY( x.a.empty() ); + + x.a = A{}; + std::swap(x, x); // results in "self-move-assignment" of X::a + VERIFY( !x.a.empty() ); + + x.a.clear(); + VERIFY( live_objects.empty() ); +} + +void +test03() +{ + using std::experimental::any; + + any a; + a.swap(a); + VERIFY( a.empty() ); + + a = A{}; + a.swap(a); + VERIFY( !a.empty() ); + + a.clear(); + VERIFY( live_objects.empty() ); } 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 b88592a108d..1d1180c36db 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 { *-*-* } } 359 } + any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 360 } } -- 2.30.2