diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h index fa65885d1de..054d9cbbf02 100644 --- a/libstdc++-v3/include/bits/std_function.h +++ b/libstdc++-v3/include/bits/std_function.h @@ -183,11 +183,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { switch (__op) { -#if __cpp_rtti case __get_type_info: +#if __cpp_rtti __dest._M_access() = &typeid(_Functor); - break; +#else + __dest._M_access() = nullptr; #endif + break; case __get_functor_ptr: __dest._M_access<_Functor*>() = _M_get_pointer(__source); break; @@ -293,6 +295,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + // Specialization for invalid types + template<> + class _Function_handler + { + public: + static bool + _M_manager(_Any_data&, const _Any_data&, _Manager_operation) + { return false; } + }; + + // Avoids instantiating ill-formed specializations of _Function_handler + // in std::function<_Signature>::target<_Functor>(). + // e.g. _Function_handler and _Function_handler + // would be ill-formed. + template::value> + struct _Target_handler + : _Function_handler<_Signature, typename remove_cv<_Functor>::type> + { }; + + template + struct _Target_handler<_Signature, _Functor, false> + : _Function_handler + { }; + /** * @brief Primary class template for std::function. * @ingroup functors @@ -553,17 +580,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _Any_data __typeinfo_result; _M_manager(__typeinfo_result, _M_functor, __get_type_info); - return *__typeinfo_result._M_access(); + if (auto __ti = __typeinfo_result._M_access()) + return *__ti; } - else - return typeid(void); + return typeid(void); } +#endif /** * @brief Access the stored target function object. * * @return Returns a pointer to the stored target function object, - * if @c typeid(_Functor).equals(target_type()); otherwise, a NULL + * if @c typeid(_Functor).equals(target_type()); otherwise, a null * pointer. * * This function does not throw exceptions. @@ -576,24 +604,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { const function* __const_this = this; const _Functor* __func = __const_this->template target<_Functor>(); - return const_cast<_Functor*>(__func); + // If is_function_v<_Functor> is true then const_cast<_Functor*> + // would be ill-formed, so use *const_cast<_Functor**> instead. + return *const_cast<_Functor**>(&__func); } template const _Functor* target() const noexcept { - if (typeid(_Functor) == target_type() && _M_manager) + if _GLIBCXX17_CONSTEXPR (is_object<_Functor>::value) { - _Any_data __ptr; - _M_manager(__ptr, _M_functor, __get_functor_ptr); - return __ptr._M_access(); + // For C++11 and C++14 if-constexpr is not used above, so + // _Target_handler avoids ill-formed _Function_handler types. + using _Handler = _Target_handler<_Res(_ArgTypes...), _Functor>; + + if (_M_manager == &_Handler::_M_manager +#if __cpp_rtti + || (_M_manager && typeid(_Functor) == target_type()) +#endif + ) + { + _Any_data __ptr; + _M_manager(__ptr, _M_functor, __get_functor_ptr); + return __ptr._M_access(); + } } - else - return nullptr; + return nullptr; } // @} -#endif private: using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...); diff --git a/libstdc++-v3/testsuite/20_util/function/target_no_rtti.cc b/libstdc++-v3/testsuite/20_util/function/target_no_rtti.cc new file mode 100644 index 00000000000..2215e1d9959 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function/target_no_rtti.cc @@ -0,0 +1,56 @@ +// { dg-options "-fno-rtti" } +// { dg-do run { target c++11 } } + +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include + +using std::function; + +long f() { return 1; } +struct F { long operator()() { return 2; } }; + +void test01() +{ + std::function fun = f; + long (**tgt1)() = fun.target(); + VERIFY( *tgt1 == f ); + VERIFY( (*tgt1)() == 1L ); + VERIFY( fun.target() == tgt1 ); + VERIFY( fun.target() == tgt1 ); + VERIFY( fun.target() == nullptr ); + VERIFY( fun.target() == nullptr ); + VERIFY( fun.target() == nullptr ); + VERIFY( fun.target() == nullptr ); + + const F ff; + fun = ff; + F* tgt2 = fun.target(); + VERIFY( tgt2 != nullptr ); + VERIFY( (*tgt2)() == 2L ); + VERIFY( fun.target() == tgt2 ); + VERIFY( fun.target() == nullptr ); + VERIFY( fun.target() == nullptr ); + VERIFY( fun.target() == nullptr ); +} + +int main() +{ + test01(); +}