On 24/04/19 10:46 +0100, Jonathan Wakely wrote:
PR libstdc++/90220 (partial)
* include/std/any (any_cast<T>(any*), any_cast<T>(const any*)): Do
not attempt ill-formed static_cast to pointers to non-object types.
* testsuite/20_util/any/misc/any_cast.cc: Test std::any_cast with
function types.
Tested powerpc64le-linux, committed to trunk.
The PR describes two bugs in any_cast, but I might leave the fix for
the other part until stage 1.
On second thoughts, the fix for the other part seems obviously safe to
commit now as well. I've attached what I've tested. I plan to commit
this later today.
I'm considering backporting these too.
commit a8c2cffdf4cf2dafd95d5648ce74cf2f754f8ef1
Author: Jonathan Wakely <jwak...@redhat.com>
Date: Wed Apr 24 11:17:19 2019 +0100
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.
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<typename _Tp>
void* __any_caster(const any* __any)
{
- if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
+ // any_cast<T> 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<U> is not U,
+ // then it's not possible to have a contained value of type U:
+ if constexpr (!is_same_v<decay_t<_Up>, _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<decay_t<_Tp>>::_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<int[3]>(&a);
+ VERIFY( a.type() != typeid(int[3]) ); // so any_cast should return nullptr
+ VERIFY( p1 == nullptr );
+ int (*p2)[] = any_cast<int[]>(&a);
+ VERIFY( a.type() != typeid(int[]) ); // so any_cast should return nullptr
+ VERIFY( p2 == nullptr );
+ const int (*p3)[] = any_cast<int[]>(&std::as_const(a));
+ VERIFY( p3 == nullptr );
+}
+
int main()
{
test01();
@@ -162,4 +178,5 @@ int main()
test04();
test05();
test06();
+ test07();
}