[libcxx-commits] [libcxx] c14ba73 - [libc++] Define behaviour for calling target() and target_type() on -fno-rtti std::functions (#209471)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 17 05:44:14 PDT 2026


Author: Nikolas Klauser
Date: 2026-08-17T14:44:09+02:00
New Revision: c14ba73a927211a10ce66ac44df5403c53199206

URL: https://github.com/llvm/llvm-project/commit/c14ba73a927211a10ce66ac44df5403c53199206
DIFF: https://github.com/llvm/llvm-project/commit/c14ba73a927211a10ce66ac44df5403c53199206.diff

LOG: [libc++] Define behaviour for calling target() and target_type() on -fno-rtti std::functions (#209471)

The main aim of this change is to have the same vtable between
`-fno-rtti` and `-frtti`. Since it's very cheap to do, this also asserts
if the `function` object was created in `-fno-rtti` mode.

The vtable can be extended, since the members are either never accessed
in `-fno-rtti` mode, or are already expected to exist in `-frtti` mode.
This means that we either define behaviour that wasn't before, or we add
some extra bytes that are never accessed.

Added: 
    libcxx/test/extensions/libcxx/utilities/function.objects/func.wrap/func.wrap.func/rtti_mixing.assert.sh.cpp

Modified: 
    libcxx/include/__functional/function.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index 0adc336424e2e..58dfed2421222 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -28,6 +28,7 @@
 #include <__utility/forward.h>
 #include <__utility/move.h>
 #include <__utility/swap.h>
+#include <__utility/unreachable.h>
 #include <tuple>
 #include <typeinfo>
 
@@ -145,10 +146,14 @@ class __base<_Rp(_ArgTypes...)> {
   virtual void destroy() _NOEXCEPT            = 0;
   virtual void destroy_deallocate() _NOEXCEPT = 0;
   virtual _Rp operator()(_ArgTypes&&...)      = 0;
-#  if _LIBCPP_HAS_RTTI
-  virtual const void* target(const type_info&) const _NOEXCEPT = 0;
-  virtual const std::type_info& target_type() const _NOEXCEPT  = 0;
-#  endif // _LIBCPP_HAS_RTTI
+  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const void* target(const type_info&) const _NOEXCEPT {
+    _LIBCPP_ASSERT_NON_NULL(false, "Trying to access type_info of std::function created in -fno-rtti mode!");
+    std::__libcpp_unreachable();
+  }
+  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const std::type_info& target_type() const _NOEXCEPT {
+    _LIBCPP_ASSERT_NON_NULL(false, "Trying to access type_info of std::function created in -fno-rtti mode!");
+    std::__libcpp_unreachable();
+  }
 };
 _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
 
@@ -516,11 +521,19 @@ class __policy_func<_Rp(_ArgTypes...)> {
   _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return !__policy_->__is_null; }
 
 #  if _LIBCPP_HAS_RTTI
-  _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT { return *__policy_->__type_info; }
+  _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT {
+    _LIBCPP_ASSERT_NON_NULL(
+        __policy_->__type_info, "Trying to access type_info of std::functions created in -fno-rtti mode!");
+    return *__policy_->__type_info;
+  }
 
   template <typename _Tp>
   _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT {
-    if (__policy_->__is_null || typeid(_Tp) != *__policy_->__type_info)
+    if (__policy_->__is_null)
+      return nullptr;
+    _LIBCPP_ASSERT_NON_NULL(
+        __policy_->__type_info, "Trying to access type_info of std::function created in -fno-rtti mode!");
+    if (typeid(_Tp) != *__policy_->__type_info)
       return nullptr;
     if (__policy_->__clone) // Out of line storage.
       return reinterpret_cast<const _Tp*>(__buf_.__large);

diff  --git a/libcxx/test/extensions/libcxx/utilities/function.objects/func.wrap/func.wrap.func/rtti_mixing.assert.sh.cpp b/libcxx/test/extensions/libcxx/utilities/function.objects/func.wrap/func.wrap.func/rtti_mixing.assert.sh.cpp
new file mode 100644
index 0000000000000..72d6fc4d5cfa5
--- /dev/null
+++ b/libcxx/test/extensions/libcxx/utilities/function.objects/func.wrap/func.wrap.func/rtti_mixing.assert.sh.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+// REQUIRES: can-test-hardening-assertions-extensive
+
+// Ensure that passing std::functions across -fno-rtti/-frtti boundaries is asserted on.
+
+#include <cassert>
+#include <functional>
+#include <typeinfo>
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -frtti -o %t.tu1.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DNO_RTTI -fno-rtti -o %t.tu2.o
+// RUN: %{cxx} %t.tu1.o %t.tu2.o %{flags} %{link_flags} -o %t.exe
+// RUN: %{exec} %t.exe
+
+std::function<void()> get_func();
+
+#ifdef NO_RTTI
+std::function<void()> get_func() { return get_func; }
+#else
+
+// This can only be included once.
+#  include "check_assertion.h"
+
+int main(int, char**) {
+  TEST_LIBCPP_ASSERT_FAILURE(
+      get_func().target<int>(), "Trying to access type_info of std::function created in -fno-rtti mode!");
+  TEST_LIBCPP_ASSERT_FAILURE(
+      get_func().target_type(), "Trying to access type_info of std::function created in -fno-rtti mode!");
+
+  return 0;
+}
+#endif


        


More information about the libcxx-commits mailing list