commit 1b8ce184914caa968a75ed50fe29bdbb40969ab9 Author: Jonathan Wakely Date: Mon Jan 29 12:00:21 2018 +0000 PR libstdc++/83658 fix exception-safety in std::any::emplace PR libstdc++/83658 * include/std/any (any::__do_emplace): Only set _M_manager after constructing the contained object. * testsuite/20_util/any/misc/any_cast_neg.cc: Adjust dg-error line. * testsuite/20_util/any/modifiers/83658.cc: New test. diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index 5fb8df755ef..466b7cac129 100644 --- a/libstdc++-v3/include/std/any +++ b/libstdc++-v3/include/std/any @@ -70,7 +70,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** * @brief A type-safe container of any type. - * + * * An @c any object's state is either empty or it stores a contained object * of CopyConstructible type. */ @@ -114,8 +114,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __do_emplace(_Args&&... __args) { reset(); - _M_manager = &_Mgr::_S_manage; _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...); + _M_manager = &_Mgr::_S_manage; } /// Emplace with an object created from @p __il and @p __args as @@ -125,8 +125,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __do_emplace(initializer_list<_Up> __il, _Args&&... __args) { reset(); - _M_manager = &_Mgr::_S_manage; _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...); + _M_manager = &_Mgr::_S_manage; } public: @@ -272,8 +272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Decay<_ValueType>, _Args&&...>::type emplace(_Args&&... __args) { - __do_emplace<_Decay<_ValueType>> - (std::forward<_Args>(__args)...); + __do_emplace<_Decay<_ValueType>>(std::forward<_Args>(__args)...); any::_Arg __arg; this->_M_manager(any::_Op_access, this, &__arg); return *static_cast<_Decay<_ValueType>*>(__arg._M_obj); @@ -288,8 +287,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Args&&...>::type emplace(initializer_list<_Up> __il, _Args&&... __args) { - __do_emplace<_Decay<_ValueType>, _Up> - (__il, std::forward<_Args>(__args)...); + __do_emplace<_Decay<_ValueType>, _Up>(__il, + std::forward<_Args>(__args)...); any::_Arg __arg; this->_M_manager(any::_Op_access, this, &__arg); return *static_cast<_Decay<_ValueType>*>(__arg._M_obj); @@ -624,7 +623,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// @} - + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std 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 21f145eb022..50a9a674c78 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(y); // { dg-error "invalid static_cast" "" { target { *-*-* } } 461 } + any_cast(y); // { dg-error "invalid static_cast" "" { target { *-*-* } } 460 } } diff --git a/libstdc++-v3/testsuite/20_util/any/modifiers/83658.cc b/libstdc++-v3/testsuite/20_util/any/modifiers/83658.cc new file mode 100644 index 00000000000..7c5acc636c8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/any/modifiers/83658.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2018 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 +// . + +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +#include +#include +#include + +struct E : std::bad_alloc { }; + +struct X +{ + X() = default; + X(std::initializer_list) { } + + // Prevents small-object optimization: + X(const X&) noexcept(false) { } + + static void* operator new(std::size_t) { throw E{}; } + static void operator delete(void*, std::size_t) noexcept { } +}; + +void +test01() +{ + std::any a; + try + { + a.emplace(); + VERIFY(false); + } + catch (const E&) + { + VERIFY( !a.has_value() ); + } +} + +void +test02() +{ + std::any a; + try + { + a.emplace(std::initializer_list{}); + VERIFY(false); + } + catch (const E&) + { + VERIFY( !a.has_value() ); + } +} + +int +main() +{ + test01(); + test02(); +}