diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-05-23 14:39:06 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-05-23 14:39:06 +0100 |
commit | 7dbab5dc84e3782fe6f366a985e507e2ea2726d2 (patch) | |
tree | 379706dbe804d09b85f9a9d365338c25b800ec30 /libstdc++-v3/include | |
parent | 56a4e074ee8bcf4c3627fb595c31bd833d5a6532 (diff) | |
download | gcc-7dbab5dc84e3782fe6f366a985e507e2ea2726d2.zip gcc-7dbab5dc84e3782fe6f366a985e507e2ea2726d2.tar.gz gcc-7dbab5dc84e3782fe6f366a985e507e2ea2726d2.tar.bz2 |
PR libstdc++/90220 fix experimental::any_cast for non-object types
This corresponds to the fixes done for std::any_cast, but has to be done
without if-constexpr. The dummy specialization of _Manager_internal<_Op>
is used to avoid instantiating the real _Manager_internal<T>::_S_manage
function just to compare its address.
PR libstdc++/90220
* include/experimental/any (__any_caster): Constrain to only be
callable for object types. Use remove_cv_t instead of decay_t.
If the type decays or isn't copy constructible, compare the manager
function to a dummy specialization.
(__any_caster): Add overload constrained for non-object types.
(any::_Manager_internal<_Op>): Add dummy specialization.
* testsuite/experimental/any/misc/any_cast.cc: Test function types
and array types.
From-SVN: r271556
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r-- | libstdc++-v3/include/experimental/any | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index a6e0fc6..f1d4bbf 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -303,7 +303,8 @@ inline namespace fundamentals_v1 _Storage _M_storage; template<typename _Tp> - friend void* __any_caster(const any* __any); + friend enable_if_t<is_object<_Tp>::value, void*> + __any_caster(const any* __any); // Manage in-place contained object. template<typename _Tp> @@ -415,17 +416,34 @@ inline namespace fundamentals_v1 /// @cond undocumented template<typename _Tp> - void* __any_caster(const any* __any) + enable_if_t<is_object<_Tp>::value, void*> + __any_caster(const any* __any) { - struct _None { }; - using _Up = decay_t<_Tp>; - using _Vp = conditional_t<is_copy_constructible<_Up>::value, _Up, _None>; + // 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. + using __does_not_decay = is_same<decay_t<_Up>, _Up>; + // Only copy constructible types can be used for contained values. + using __is_copyable = is_copy_constructible<_Up>; + // If the type _Tp could never be stored in an any we don't want to + // instantiate _Manager<_Tp>, so use _Manager<any::_Op> instead, which + // is explicitly specialized and has a no-op _S_manage function. + using _Vp = conditional_t<__and_<__does_not_decay, __is_copyable>::value, + _Up, any::_Op>; if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) return nullptr; any::_Arg __arg; __any->_M_manager(any::_Op_access, __any, &__arg); return __arg._M_obj; } + + // This overload exists so that std::any_cast<void(*)()>(a) is well-formed. + template<typename _Tp> + enable_if_t<!is_object<_Tp>::value, _Tp*> + __any_caster(const any*) noexcept + { return nullptr; } /// @endcond /** @@ -522,6 +540,14 @@ inline namespace fundamentals_v1 } } + // Dummy specialization used by __any_caster. + template<> + struct any::_Manager_internal<any::_Op> + { + static void + _S_manage(_Op, const any*, _Arg*) { } + }; + // @} group any } // namespace fundamentals_v1 } // namespace experimental |