From 92750002ef200965cb33aa5af68676b540564758 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 24 Apr 2019 16:17:43 +0100 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 6 +++++ libstdc++-v3/include/std/any | 22 +++++++++++++------ .../testsuite/20_util/any/misc/any_cast.cc | 17 ++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8be3dcc860b..2ab686ba3bb 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 792db27b061..29fe03e2b82 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 c9aeaae3366..b7fbbc5ee95 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(); }