Commit aa573a6a by Jonathan Wakely Committed by Jonathan Wakely

Make any_cast compare typeinfo as well as function pointers

It's possible for the function pointer comparison to fail even though
the type is correct, because the function could be defined multiple
times with different addresses when shared libraries are in use.

Retain the function pointer check for the common case where the check
succeeds, but compare typeinfo (if RTTI is enabled) if the first check
fails.

	* include/experimental/any (__any_caster): Use RTTI if comparing
	addresses fails, to support non-unique addresses in shared libraries.
	* include/std/any (__any_caster): Likewise.

From-SVN: r271557
parent 7dbab5dc
2019-05-23 Jonathan Wakely <jwakely@redhat.com> 2019-05-23 Jonathan Wakely <jwakely@redhat.com>
* include/experimental/any (__any_caster): Use RTTI if comparing
addresses fails, to support non-unique addresses in shared libraries.
* include/std/any (__any_caster): Likewise.
PR libstdc++/90220 PR libstdc++/90220
* include/experimental/any (__any_caster): Constrain to only be * include/experimental/any (__any_caster): Constrain to only be
callable for object types. Use remove_cv_t instead of decay_t. callable for object types. Use remove_cv_t instead of decay_t.
......
...@@ -432,11 +432,18 @@ inline namespace fundamentals_v1 ...@@ -432,11 +432,18 @@ inline namespace fundamentals_v1
// is explicitly specialized and has a no-op _S_manage function. // is explicitly specialized and has a no-op _S_manage function.
using _Vp = conditional_t<__and_<__does_not_decay, __is_copyable>::value, using _Vp = conditional_t<__and_<__does_not_decay, __is_copyable>::value,
_Up, any::_Op>; _Up, any::_Op>;
if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) // First try comparing function addresses, which works without RTTI
return nullptr; if (__any->_M_manager == &any::_Manager<_Vp>::_S_manage
any::_Arg __arg; #if __cpp_rtti
__any->_M_manager(any::_Op_access, __any, &__arg); || __any->type() == typeid(_Tp)
return __arg._M_obj; #endif
)
{
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
return nullptr;
} }
// This overload exists so that std::any_cast<void(*)()>(a) is well-formed. // This overload exists so that std::any_cast<void(*)()>(a) is well-formed.
......
...@@ -503,6 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -503,6 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
// @} // @}
/// @cond undocumented
template<typename _Tp> template<typename _Tp>
void* __any_caster(const any* __any) void* __any_caster(const any* __any)
{ {
...@@ -516,8 +517,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -516,8 +517,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Only copy constructible types can be used for contained values: // Only copy constructible types can be used for contained values:
else if constexpr (!is_copy_constructible_v<_Up>) else if constexpr (!is_copy_constructible_v<_Up>)
return nullptr; return nullptr;
// This check is equivalent to __any->type() == typeid(_Tp) // First try comparing function addresses, which works without RTTI
else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage) else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
#if __cpp_rtti
|| __any->type() == typeid(_Tp)
#endif
)
{ {
any::_Arg __arg; any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg); __any->_M_manager(any::_Op_access, __any, &__arg);
...@@ -525,6 +530,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -525,6 +530,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
return nullptr; return nullptr;
} }
/// @endcond
/** /**
* @brief Access the contained object. * @brief Access the contained object.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment