From: Jonathan Wakely Date: Wed, 24 Apr 2019 15:17:43 +0000 (+0100) Subject: PR libstdc++/90220 Fix std::any_cast for array types X-Git-Tag: basepoints/gcc-10~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92750002ef200965cb33aa5af68676b540564758;p=thirdparty%2Fgcc.git PR libstdc++/90220 Fix std::any_cast for array types Although the std::any constructors use decay_t to determine the type of the contained value, std::any_cast should use the un-decayed type (and so always fail for function and array types that decay to pointers). Using remove_cv_t is correct, because the condition for std::any_cast to return non-null is operand.type() == typeid(T) and typeid ignores top-level cv-qualifiers. PR libstdc++/90220 * include/std/any (__any_caster): Use remove_cv_t instead of decay_t. Avoid a runtime check for types that can never be stored in std::any. * testsuite/20_util/any/misc/any_cast.cc: Test std::any_cast with array types. From-SVN: r270547 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8be3dcc860b9..2ab686ba3bb3 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,11 @@ 2019-04-24 Jonathan Wakely + PR libstdc++/90220 + * include/std/any (__any_caster): Use remove_cv_t instead of decay_t. + Avoid a runtime check for types that can never be stored in std::any. + * testsuite/20_util/any/misc/any_cast.cc: Test std::any_cast with + array types. + PR libstdc++/90220 (partial) * include/std/any (any_cast(any*), any_cast(const any*)): Do not attempt ill-formed static_cast to pointers to non-object types. diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index 792db27b061e..29fe03e2b82a 100644 --- a/libstdc++-v3/include/std/any +++ b/libstdc++-v3/include/std/any @@ -506,14 +506,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template void* __any_caster(const any* __any) { - if constexpr (is_copy_constructible_v>) + // any_cast returns non-null if __any->type() == typeid(T) and + // typeid(T) ignores cv-qualifiers so remove them: + using _Up = remove_cv_t<_Tp>; + // The contained value has a decayed type, so if decay_t is not U, + // then it's not possible to have a contained value of type U: + if constexpr (!is_same_v, _Up>) + return nullptr; + // Only copy constructible types can be used for contained values: + else if constexpr (!is_copy_constructible_v<_Up>) + return nullptr; + // This check is equivalent to __any->type() == typeid(_Tp) + else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage) { - if (__any->_M_manager == &any::_Manager>::_S_manage) - { - any::_Arg __arg; - __any->_M_manager(any::_Op_access, __any, &__arg); - return __arg._M_obj; - } + 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 c9aeaae33668..b7fbbc5ee950 100644 --- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc +++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast.cc @@ -154,6 +154,22 @@ void test06() } } +void test07() +{ + int arr[3]; + any a(arr); + VERIFY( a.type() == typeid(int*) ); // contained value is decayed + + int (*p1)[3] = any_cast(&a); + VERIFY( a.type() != typeid(int[3]) ); // so any_cast should return nullptr + VERIFY( p1 == nullptr ); + int (*p2)[] = any_cast(&a); + VERIFY( a.type() != typeid(int[]) ); // so any_cast should return nullptr + VERIFY( p2 == nullptr ); + const int (*p3)[] = any_cast(&std::as_const(a)); + VERIFY( p3 == nullptr ); +} + int main() { test01(); @@ -162,4 +178,5 @@ int main() test04(); test05(); test06(); + test07(); }