public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Make std::function work better with -fno-rtti
@ 2020-10-29 14:49 Jonathan Wakely
  2020-10-29 15:57 ` Jonathan Wakely
  2020-11-09 14:30 ` Jonathan Wakely
  0 siblings, 2 replies; 4+ messages in thread
From: Jonathan Wakely @ 2020-10-29 14:49 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1901 bytes --]

This change allows std::function::target<F>() to work even without RTTI,
using the same approach as std::any. Because we know what the manager
function would be for a given type, we can check if the stored pointer
has the expected address. If it does, we don't need to use RTTI. If it
isn't equal, we still need to do the RTTI check (when RTTI is enabled)
to handle the case where the same function has different addresses in
different shared objects.

This also changes the implementation of the manager function to return a
null pointer result when asked for the type_info of the target object.
This not only avoids a warning with -Wswitch -Wsystem-headers, but also
avoids prevents std::function::target_type() from dereferencing an
uninitialized pointer when the linker keeps an instantiation of the
manager function that was compiled without RTTI.

Finally, this fixes a bug in the non-const overload of function::target
where calling it with a function type F was ill-formed, due to
attempting to use const_cast<F*>(ptr). The standard only allows
const_cast<T*> when T is an object type.  The solution is to use
*const_cast<F**>(&ptr) instead, because F* is an object type even if F
isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
it doesn't bother instantiating anything for types that can never be a
valid target.

libstdc++-v3/ChangeLog:

	* include/bits/std_function.h (_Function_handler<void, void>):
	Define explicit specialization used for invalid target types.
	(_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
	(function::target_type()): Check for null pointer.
	(function::target()): Define unconditionall. Fix bug with
	const_cast of function pointer type.
	(function::target() const): Define unconditionally, but
	only use RTTI if enabled.
	* testsuite/20_util/function/target_no_rtti.cc: New test.

Tested powerpc64le-linux. Committed to trunk.

2
1
0

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 8122 bytes --]

commit 3c9b99ef7115fa88ef4d744cc2afc424bd5c3ef2
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 29 14:47:17 2020

    libstdc++: Make std::function work better with -fno-rtti
    
    This change allows std::function::target<F>() to work even without RTTI,
    using the same approach as std::any. Because we know what the manager
    function would be for a given type, we can check if the stored pointer
    has the expected address. If it does, we don't need to use RTTI. If it
    isn't equal, we still need to do the RTTI check (when RTTI is enabled)
    to handle the case where the same function has different addresses in
    different shared objects.
    
    This also changes the implementation of the manager function to return a
    null pointer result when asked for the type_info of the target object.
    This not only avoids a warning with -Wswitch -Wsystem-headers, but also
    avoids prevents std::function::target_type() from dereferencing an
    uninitialized pointer when the linker keeps an instantiation of the
    manager function that was compiled without RTTI.
    
    Finally, this fixes a bug in the non-const overload of function::target
    where calling it with a function type F was ill-formed, due to
    attempting to use const_cast<F*>(ptr). The standard only allows
    const_cast<T*> when T is an object type.  The solution is to use
    *const_cast<F**>(&ptr) instead, because F* is an object type even if F
    isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
    it doesn't bother instantiating anything for types that can never be a
    valid target.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/std_function.h (_Function_handler<void, void>):
            Define explicit specialization used for invalid target types.
            (_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
            (function::target_type()): Check for null pointer.
            (function::target()): Define unconditionall. Fix bug with
            const_cast of function pointer type.
            (function::target() const): Define unconditionally, but
            only use RTTI if enabled.
            * testsuite/20_util/function/target_no_rtti.cc: New test.

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<const type_info*>() = &typeid(_Functor);
-	      break;
+#else
+	      __dest._M_access<const type_info*>() = 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<void, void>
+    {
+    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<Sig, void()> and _Function_handler<Sig, void>
+  // would be ill-formed.
+  template<typename _Signature, typename _Functor,
+	   bool __valid = is_object<_Functor>::value>
+    struct _Target_handler
+    : _Function_handler<_Signature, typename remove_cv<_Functor>::type>
+    { };
+
+  template<typename _Signature, typename _Functor>
+    struct _Target_handler<_Signature, _Functor, false>
+    : _Function_handler<void, void>
+    { };
+
   /**
    *  @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<const type_info*>();
+	    if (auto __ti =  __typeinfo_result._M_access<const type_info*>())
+	      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<typename _Functor>
 	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<const _Functor*>();
+	      // 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<const _Functor*>();
+		}
 	    }
-	  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
+// <http://www.gnu.org/licenses/>.
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::function;
+
+long f() { return 1; }
+struct F { long operator()() {  return 2; } };
+
+void test01()
+{
+  std::function<int()> fun = f;
+  long (**tgt1)() = fun.target<long(*)()>();
+  VERIFY( *tgt1 == f );
+  VERIFY( (*tgt1)() == 1L );
+  VERIFY( fun.target<long(*)()>() == tgt1 );
+  VERIFY( fun.target<long(* const)()>() == tgt1 );
+  VERIFY( fun.target<F>() == nullptr );
+  VERIFY( fun.target<void>() == nullptr );
+  VERIFY( fun.target<int()>() == nullptr );
+  VERIFY( fun.target<long()>() == nullptr );
+
+  const F ff;
+  fun = ff;
+  F* tgt2 = fun.target<F>();
+  VERIFY( tgt2 != nullptr );
+  VERIFY( (*tgt2)() == 2L );
+  VERIFY( fun.target<const F>() == tgt2 );
+  VERIFY( fun.target<int(*)()>() == nullptr );
+  VERIFY( fun.target<void()>() == nullptr );
+  VERIFY( fun.target<void(*)()>() == nullptr );
+}
+
+int main()
+{
+  test01();
+}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [committed] libstdc++: Make std::function work better with -fno-rtti
  2020-10-29 14:49 [committed] libstdc++: Make std::function work better with -fno-rtti Jonathan Wakely
@ 2020-10-29 15:57 ` Jonathan Wakely
  2020-11-09 14:30 ` Jonathan Wakely
  1 sibling, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2020-10-29 15:57 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 29/10/20 14:49 +0000, Jonathan Wakely wrote:
>This change allows std::function::target<F>() to work even without RTTI,
>using the same approach as std::any. Because we know what the manager
>function would be for a given type, we can check if the stored pointer
>has the expected address. If it does, we don't need to use RTTI. If it
>isn't equal, we still need to do the RTTI check (when RTTI is enabled)
>to handle the case where the same function has different addresses in
>different shared objects.
>
>This also changes the implementation of the manager function to return a
>null pointer result when asked for the type_info of the target object.
>This not only avoids a warning with -Wswitch -Wsystem-headers, but also
>avoids prevents std::function::target_type() from dereferencing an
>uninitialized pointer when the linker keeps an instantiation of the
>manager function that was compiled without RTTI.
>
>Finally, this fixes a bug in the non-const overload of function::target
>where calling it with a function type F was ill-formed, due to
>attempting to use const_cast<F*>(ptr). The standard only allows
>const_cast<T*> when T is an object type.  The solution is to use
>*const_cast<F**>(&ptr) instead, because F* is an object type even if F
>isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
>it doesn't bother instantiating anything for types that can never be a
>valid target.
>
>libstdc++-v3/ChangeLog:
>
>	* include/bits/std_function.h (_Function_handler<void, void>):
>	Define explicit specialization used for invalid target types.
>	(_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
>	(function::target_type()): Check for null pointer.
>	(function::target()): Define unconditionall. Fix bug with
>	const_cast of function pointer type.
>	(function::target() const): Define unconditionally, but
>	only use RTTI if enabled.
>	* testsuite/20_util/function/target_no_rtti.cc: New test.
>
>Tested powerpc64le-linux. Committed to trunk.
>
>2
>1
>0

Oops, sorry for the duplicate mail about this. My mailer ate my
attempt to script something.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [committed] libstdc++: Make std::function work better with -fno-rtti
  2020-10-29 14:49 [committed] libstdc++: Make std::function work better with -fno-rtti Jonathan Wakely
  2020-10-29 15:57 ` Jonathan Wakely
@ 2020-11-09 14:30 ` Jonathan Wakely
  1 sibling, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2020-11-09 14:30 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2022 bytes --]

On 29/10/20 14:49 +0000, Jonathan Wakely wrote:
>This change allows std::function::target<F>() to work even without RTTI,
>using the same approach as std::any. Because we know what the manager
>function would be for a given type, we can check if the stored pointer
>has the expected address. If it does, we don't need to use RTTI. If it
>isn't equal, we still need to do the RTTI check (when RTTI is enabled)
>to handle the case where the same function has different addresses in
>different shared objects.
>
>This also changes the implementation of the manager function to return a
>null pointer result when asked for the type_info of the target object.
>This not only avoids a warning with -Wswitch -Wsystem-headers, but also
>avoids prevents std::function::target_type() from dereferencing an
>uninitialized pointer when the linker keeps an instantiation of the
>manager function that was compiled without RTTI.
>
>Finally, this fixes a bug in the non-const overload of function::target
>where calling it with a function type F was ill-formed, due to
>attempting to use const_cast<F*>(ptr). The standard only allows
>const_cast<T*> when T is an object type.  The solution is to use
>*const_cast<F**>(&ptr) instead, because F* is an object type even if F
>isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
>it doesn't bother instantiating anything for types that can never be a
>valid target.
>
>libstdc++-v3/ChangeLog:
>
>	* include/bits/std_function.h (_Function_handler<void, void>):
>	Define explicit specialization used for invalid target types.
>	(_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
>	(function::target_type()): Check for null pointer.
>	(function::target()): Define unconditionall. Fix bug with
>	const_cast of function pointer type.
>	(function::target() const): Define unconditionally, but
>	only use RTTI if enabled.
>	* testsuite/20_util/function/target_no_rtti.cc: New test.

This fixes a problem with that previous patch.

Tested x86_64-linux. Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1077 bytes --]

commit 99bf3a817b9d31905dd12448e853ad2685635250
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Nov 9 10:09:51 2020

    libstdc++: Include <typeinfo> even for -fno-rtti [PR 97758]
    
    The std::function code now uses std::type_info* even when RTTI is
    disabled, so it should include <typeinfo> unconditionally. Without this,
    Clang can't compile <functional> with -fno-rtti (it works with GCC
    because std::type_info gets declared automatically by the compiler).
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97758
            * include/bits/std_function.h [!__cpp_rtti]: Include <typeinfo>.

diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h
index 054d9cbbf02b..1788b882a8aa 100644
--- a/libstdc++-v3/include/bits/std_function.h
+++ b/libstdc++-v3/include/bits/std_function.h
@@ -36,9 +36,7 @@
 # include <bits/c++0x_warning.h>
 #else
 
-#if __cpp_rtti
-# include <typeinfo>
-#endif
+#include <typeinfo>
 #include <bits/stl_function.h>
 #include <bits/invoke.h>
 #include <bits/refwrap.h>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [committed] libstdc++: Make std::function work better with -fno-rtti
@ 2020-10-29 14:49 Jonathan Wakely
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2020-10-29 14:49 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1890 bytes --]

This change allows std::function::target<F>() to work even without RTTI,
using the same approach as std::any. Because we know what the manager
function would be for a given type, we can check if the stored pointer
has the expected address. If it does, we don't need to use RTTI. If it
isn't equal, we still need to do the RTTI check (when RTTI is enabled)
to handle the case where the same function has different addresses in
different shared objects.

This also changes the implementation of the manager function to return a
null pointer result when asked for the type_info of the target object.
This not only avoids a warning with -Wswitch -Wsystem-headers, but also
avoids prevents std::function::target_type() from dereferencing an
uninitialized pointer when the linker keeps an instantiation of the
manager function that was compiled without RTTI.

Finally, this fixes a bug in the non-const overload of function::target
where calling it with a function type F was ill-formed, due to
attempting to use const_cast<F*>(ptr). The standard only allows
const_cast<T*> when T is an object type.  The solution is to use
*const_cast<F**>(&ptr) instead, because F* is an object type even if F
isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
it doesn't bother instantiating anything for types that can never be a
valid target.

libstdc++-v3/ChangeLog:

	* include/bits/std_function.h (_Function_handler<void, void>):
	Define explicit specialization used for invalid target types.
	(_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
	(function::target_type()): Check for null pointer.
	(function::target()): Define unconditionall. Fix bug with
	const_cast of function pointer type.
	(function::target() const): Define unconditionally, but
	only use RTTI if enabled.
	* testsuite/20_util/function/target_no_rtti.cc: New test.

Tested x86_64-linux. Committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 8122 bytes --]

commit 3c9b99ef7115fa88ef4d744cc2afc424bd5c3ef2
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 29 14:47:17 2020

    libstdc++: Make std::function work better with -fno-rtti
    
    This change allows std::function::target<F>() to work even without RTTI,
    using the same approach as std::any. Because we know what the manager
    function would be for a given type, we can check if the stored pointer
    has the expected address. If it does, we don't need to use RTTI. If it
    isn't equal, we still need to do the RTTI check (when RTTI is enabled)
    to handle the case where the same function has different addresses in
    different shared objects.
    
    This also changes the implementation of the manager function to return a
    null pointer result when asked for the type_info of the target object.
    This not only avoids a warning with -Wswitch -Wsystem-headers, but also
    avoids prevents std::function::target_type() from dereferencing an
    uninitialized pointer when the linker keeps an instantiation of the
    manager function that was compiled without RTTI.
    
    Finally, this fixes a bug in the non-const overload of function::target
    where calling it with a function type F was ill-formed, due to
    attempting to use const_cast<F*>(ptr). The standard only allows
    const_cast<T*> when T is an object type.  The solution is to use
    *const_cast<F**>(&ptr) instead, because F* is an object type even if F
    isn't. I've also used _GLIBCXX17_CONSTEXPR in function::target so that
    it doesn't bother instantiating anything for types that can never be a
    valid target.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/std_function.h (_Function_handler<void, void>):
            Define explicit specialization used for invalid target types.
            (_Base_manager::_M_manager) [!__cpp_rtti]: Return null.
            (function::target_type()): Check for null pointer.
            (function::target()): Define unconditionall. Fix bug with
            const_cast of function pointer type.
            (function::target() const): Define unconditionally, but
            only use RTTI if enabled.
            * testsuite/20_util/function/target_no_rtti.cc: New test.

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<const type_info*>() = &typeid(_Functor);
-	      break;
+#else
+	      __dest._M_access<const type_info*>() = 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<void, void>
+    {
+    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<Sig, void()> and _Function_handler<Sig, void>
+  // would be ill-formed.
+  template<typename _Signature, typename _Functor,
+	   bool __valid = is_object<_Functor>::value>
+    struct _Target_handler
+    : _Function_handler<_Signature, typename remove_cv<_Functor>::type>
+    { };
+
+  template<typename _Signature, typename _Functor>
+    struct _Target_handler<_Signature, _Functor, false>
+    : _Function_handler<void, void>
+    { };
+
   /**
    *  @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<const type_info*>();
+	    if (auto __ti =  __typeinfo_result._M_access<const type_info*>())
+	      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<typename _Functor>
 	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<const _Functor*>();
+	      // 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<const _Functor*>();
+		}
 	    }
-	  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
+// <http://www.gnu.org/licenses/>.
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::function;
+
+long f() { return 1; }
+struct F { long operator()() {  return 2; } };
+
+void test01()
+{
+  std::function<int()> fun = f;
+  long (**tgt1)() = fun.target<long(*)()>();
+  VERIFY( *tgt1 == f );
+  VERIFY( (*tgt1)() == 1L );
+  VERIFY( fun.target<long(*)()>() == tgt1 );
+  VERIFY( fun.target<long(* const)()>() == tgt1 );
+  VERIFY( fun.target<F>() == nullptr );
+  VERIFY( fun.target<void>() == nullptr );
+  VERIFY( fun.target<int()>() == nullptr );
+  VERIFY( fun.target<long()>() == nullptr );
+
+  const F ff;
+  fun = ff;
+  F* tgt2 = fun.target<F>();
+  VERIFY( tgt2 != nullptr );
+  VERIFY( (*tgt2)() == 2L );
+  VERIFY( fun.target<const F>() == tgt2 );
+  VERIFY( fun.target<int(*)()>() == nullptr );
+  VERIFY( fun.target<void()>() == nullptr );
+  VERIFY( fun.target<void(*)()>() == nullptr );
+}
+
+int main()
+{
+  test01();
+}

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-11-09 14:30 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-29 14:49 [committed] libstdc++: Make std::function work better with -fno-rtti Jonathan Wakely
2020-10-29 15:57 ` Jonathan Wakely
2020-11-09 14:30 ` Jonathan Wakely
2020-10-29 14:49 Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).