any_cast must not trigger the instantiation of the manager function for types which don't meet the requirements for being stored in an any object.
PR libstdc++/69321 * include/experimental/any (__any_caster): Avoid instantiating manager function for types that can't be stored in any. * include/std/any (__any_caster): Likewise. * testsuite/20_util/any/misc/any_cast.cc: Test non-copyable type. * testsuite/experimental/any/misc/any_cast.cc: Likewise. Tested powerpc64le-linux, committed to trunk.
commit 55bf26e8ab076839ed9a45dbfe7ce20fd5290773 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Jan 20 00:47:35 2017 +0000 PR69321 fix any_cast<T>(any*) for non-copyable T PR libstdc++/69321 * include/experimental/any (__any_caster): Avoid instantiating manager function for types that can't be stored in any. * include/std/any (__any_caster): Likewise. * testsuite/20_util/any/misc/any_cast.cc: Test non-copyable type. * testsuite/experimental/any/misc/any_cast.cc: Likewise. diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index d9f06cd..36c0680 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -415,7 +415,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> void* __any_caster(const any* __any) { - if (__any->_M_manager != &any::_Manager<decay_t<_Tp>>::_S_manage) + struct _None { }; + using _Up = decay_t<_Tp>; + using _Vp = conditional_t<is_copy_constructible<_Up>::value, _Up, _None>; + if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) return nullptr; any::_Arg __arg; __any->_M_manager(any::_Op_access, __any, &__arg); diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index 8a60075..e807617 100644 --- a/libstdc++-v3/include/std/any +++ b/libstdc++-v3/include/std/any @@ -511,11 +511,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> void* __any_caster(const any* __any) { - if (__any->_M_manager != &any::_Manager<decay_t<_Tp>>::_S_manage) - return nullptr; - any::_Arg __arg; - __any->_M_manager(any::_Op_access, __any, &__arg); - return __arg._M_obj; + if constexpr (is_copy_constructible_v<decay_t<_Tp>>) + { + if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage) + { + any::_Arg __arg; + __any->_M_manager(any::_Op_access, __any, &__arg); + return __arg._M_obj; + } + } + return nullptr; } /** diff --git a/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc b/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc index 559e4e9..72581e6 100644 --- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc +++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc @@ -118,10 +118,23 @@ void test04() ExplicitCopy ec2{any_cast<ExplicitCopy>(std::move(x))}; } +void test05() +{ + // PR libstdc++/69321 + struct noncopyable { + noncopyable(noncopyable const&) = delete; + }; + + any a; + auto p = any_cast<noncopyable>(&a); + VERIFY( p == nullptr ); +} + int main() { test01(); test02(); test03(); test04(); + test05(); } diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc index b6cc114..62ab1b3 100644 --- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc @@ -105,9 +105,22 @@ void test03() MoveDeleted&& md3 = any_cast<MoveDeleted&&>(any(std::move(md))); } +void test04() +{ + // PR libstdc++/69321 + struct noncopyable { + noncopyable(noncopyable const&) = delete; + }; + + any a; + auto p = any_cast<noncopyable>(&a); + VERIFY( p == nullptr ); +} + int main() { test01(); test02(); test03(); + test04(); }