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
This commit is contained in:
parent
292af53796
commit
a3f6007cbc
|
@ -1,3 +1,17 @@
|
||||||
|
2016-10-24 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||||
|
|
||||||
|
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 <ville.voutilainen@gmail.com>
|
2016-10-24 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||||
|
|
||||||
Cross-port the latest resolution of LWG2756 and some
|
Cross-port the latest resolution of LWG2756 and some
|
||||||
|
|
|
@ -191,16 +191,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.empty())
|
*this = any(__rhs);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
clear();
|
clear();
|
||||||
else if (this != &__rhs)
|
else if (this != &__rhs)
|
||||||
{
|
{
|
||||||
if (!empty())
|
clear();
|
||||||
_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);
|
||||||
|
@ -485,7 +475,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;
|
||||||
|
|
|
@ -23,28 +23,70 @@
|
||||||
using std::experimental::any;
|
using std::experimental::any;
|
||||||
using std::experimental::any_cast;
|
using std::experimental::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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <experimental/any>
|
||||||
|
#include <testsuite_hooks.h>
|
||||||
|
|
||||||
|
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<Good>(a1);
|
||||||
|
VERIFY( del_count == 0 );
|
||||||
|
VERIFY( !a1.empty() );
|
||||||
|
any_cast<Good>(a1);
|
||||||
|
}
|
||||||
|
any a3 = Good();
|
||||||
|
del_count = 0;
|
||||||
|
try {
|
||||||
|
Bad2 b;
|
||||||
|
any a4 = b;
|
||||||
|
should_throw = true;
|
||||||
|
a3 = a4;
|
||||||
|
} catch (...) {
|
||||||
|
auto x = any_cast<Good>(a1);
|
||||||
|
VERIFY( del_count == 0 );
|
||||||
|
VERIFY( !a1.empty() );
|
||||||
|
any_cast<Good>(a1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,26 +23,59 @@
|
||||||
using std::experimental::any;
|
using std::experimental::any;
|
||||||
using std::experimental::any_cast;
|
using std::experimental::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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,5 +25,5 @@ void test01()
|
||||||
using std::experimental::any_cast;
|
using std::experimental::any_cast;
|
||||||
|
|
||||||
const any y(1);
|
const any y(1);
|
||||||
any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 369 }
|
any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 359 }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue