[libcxx-commits] [libcxxabi] make strcmp static (PR #230762)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 10 01:51:00 PDT 2026


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/230762

- **[libc++abi] Return whether a dynamic_cast/catch search finished**
- **[libc++abi] Split strcmp and non-strcmp dynamic_casts**


>From 48b36e7cebe1f5b9761e5b1ca9f9cf84224b6774 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 16 Sep 2026 12:17:22 +0200
Subject: [PATCH 1/2] [libc++abi] Return whether a dynamic_cast/catch search
 finished

---
 libcxxabi/src/private_typeinfo.cpp | 436 +++++++++++++++--------------
 libcxxabi/src/private_typeinfo.h   |  42 ++-
 2 files changed, 240 insertions(+), 238 deletions(-)

diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 74d9a7b358352..98dcfd7e1275f 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -181,10 +181,9 @@ const void* dyn_cast_to_derived(
       0,
       1, // number_of_dst_type
       false,
-      false,
       false};
   // Do the  search
-  dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
+  (void)dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
 #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // The following if should always be false because we should
   //   definitely find (static_ptr, static_type), either on a public
@@ -254,9 +253,8 @@ const void* dyn_cast_try_downcast(
       0,
       1, // number_of_dst_type
       false,
-      false,
       false};
-  dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
+  (void)dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
   if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
     // We have found at least one path from dynamic_ptr to dst_ptr. The
     //   downcast can succeed.
@@ -276,9 +274,9 @@ const void* dyn_cast_slow(
   // Not using giant short cut.  Do the search
 
   // Initialize info struct for this search.
-  __dynamic_cast_info info = {dst_type, static_ptr, static_type, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false};
+  __dynamic_cast_info info = {dst_type, static_ptr, static_type, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false};
 
-  dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
+  (void)dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
 #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // The following if should always be false because we should
   //   definitely find (static_ptr, static_type), either on a public
@@ -444,8 +442,8 @@ bool __class_type_info::can_catch(const __shim_type_info* thrown_type, void*& ad
     return false;
   // bullet 2
   _LIBCXXABI_ASSERT(adjustedPtr, "catching a class without an object?");
-  catch_info info = {this, nullptr, nullptr, 0, 0, false, true, nullptr};
-  thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+  catch_info info = {this, nullptr, nullptr, 0, 0, true, nullptr};
+  (void)thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
   if (info.path_dst_ptr_to_static_ptr == public_path) {
     adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
     return true;
@@ -473,7 +471,7 @@ bool __class_type_info::can_catch(const __shim_type_info* thrown_type, void*& ad
 // different offset (adjustedPtr) from any previously recorded, this indicates
 // an ambiguous case within the virtual base.
 
-void __class_type_info::process_found_base_class(catch_info* info, void* adjustedPtr, int path_below) const {
+bool __class_type_info::process_found_base_class(catch_info* info, void* adjustedPtr, int path_below) const {
   if (info->number_to_static_ptr == 0) {
     // First time we found this base
     info->dst_ptr_leading_to_static_ptr = adjustedPtr;
@@ -491,23 +489,25 @@ void __class_type_info::process_found_base_class(catch_info* info, void* adjuste
     // to a static_type.
     info->number_to_static_ptr += 1;
     info->path_dst_ptr_to_static_ptr = not_public_path;
-    info->search_done                = true;
+    return true;
   }
+  return false;
 }
 
-void __class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
+bool __class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
   if (is_equal(this, info->static_type, false))
-    process_found_base_class(info, adjustedPtr, path_below);
+    return process_found_base_class(info, adjustedPtr, path_below);
+  return false;
 }
 
-void __si_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
+bool __si_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
   if (is_equal(this, info->static_type, false))
-    process_found_base_class(info, adjustedPtr, path_below);
+    return process_found_base_class(info, adjustedPtr, path_below);
   else
-    __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
+    return __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
 }
 
-void __base_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
+bool __base_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
   bool is_virtual          = __offset_flags & __virtual_mask;
   ptrdiff_t offset_to_base = 0;
   if (info->have_object) {
@@ -532,27 +532,28 @@ void __base_class_type_info::has_unambiguous_public_base(catch_info* info, void*
     // .. and reset the pointer.
     adjustedPtr = nullptr;
   }
-  __base_type->has_unambiguous_public_base(
+  return __base_type->has_unambiguous_public_base(
       info,
       reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(adjustedPtr) + offset_to_base),
       (__offset_flags & __public_mask) ? path_below : not_public_path);
 }
 
-void __vmi_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
+bool __vmi_class_type_info::has_unambiguous_public_base(catch_info* info, void* adjustedPtr, int path_below) const {
   if (is_equal(this, info->static_type, false))
-    process_found_base_class(info, adjustedPtr, path_below);
+    return process_found_base_class(info, adjustedPtr, path_below);
   else {
     typedef const __base_class_type_info* Iter;
     const Iter e = __base_info + __base_count;
     Iter p       = __base_info;
-    p->has_unambiguous_public_base(info, adjustedPtr, path_below);
+    if (p->has_unambiguous_public_base(info, adjustedPtr, path_below))
+      return true;
     if (++p < e) {
       do {
-        p->has_unambiguous_public_base(info, adjustedPtr, path_below);
-        if (info->search_done)
-          break;
+        if (p->has_unambiguous_public_base(info, adjustedPtr, path_below))
+          return true;
       } while (++p < e);
     }
+    return false;
   }
 }
 
@@ -635,8 +636,8 @@ bool __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*&
   if (thrown_class_type == 0)
     return false;
   bool have_object = adjustedPtr != nullptr;
-  catch_info info  = {catch_class_type, nullptr, nullptr, 0, 0, false, have_object, nullptr};
-  thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+  catch_info info  = {catch_class_type, nullptr, nullptr, 0, 0, have_object, nullptr};
+  (void)thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
   if (info.path_dst_ptr_to_static_ptr == public_path) {
     // In the case of a thrown null pointer, we have no object but we might
     // well have computed the offset to where a public sub-object would be.
@@ -861,36 +862,35 @@ __dynamic_cast(const void* static_ptr,
 //   Record the dst_ptr as pointing to (static_ptr, static_type).
 //   If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
 //   then mark this dyanmic_cast as ambiguous and stop the search.
-void __class_type_info::process_static_type_above_dst(
+bool __class_type_info::process_static_type_above_dst(
     __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
   // Record that we found a static_type
   info->found_any_static_type = true;
-  if (current_ptr == info->static_ptr) {
-    // Record that we found (static_ptr, static_type)
-    info->found_our_static_ptr = true;
-    if (info->dst_ptr_leading_to_static_ptr == 0) {
-      // First time here
-      info->dst_ptr_leading_to_static_ptr = dst_ptr;
-      info->path_dst_ptr_to_static_ptr    = path_below;
-      info->number_to_static_ptr          = 1;
-      // If there is only one dst_type in the entire tree and the path from
-      //    there to here is public then we are done!
-      if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
-        info->search_done = true;
-    } else if (info->dst_ptr_leading_to_static_ptr == dst_ptr) {
-      // We've been here before.  Update path to "most public"
-      if (info->path_dst_ptr_to_static_ptr == not_public_path)
-        info->path_dst_ptr_to_static_ptr = path_below;
-      // If there is only one dst_type in the entire tree and the path from
-      //    there to here is public then we are done!
-      if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
-        info->search_done = true;
-    } else {
-      // We've detected an ambiguous cast from (static_ptr, static_type)
-      //   to a dst_type
-      info->number_to_static_ptr += 1;
-      info->search_done = true;
-    }
+  if (current_ptr != info->static_ptr)
+    return false;
+
+  // Record that we found (static_ptr, static_type)
+  info->found_our_static_ptr = true;
+  if (info->dst_ptr_leading_to_static_ptr == 0) {
+    // First time here
+    info->dst_ptr_leading_to_static_ptr = dst_ptr;
+    info->path_dst_ptr_to_static_ptr    = path_below;
+    info->number_to_static_ptr          = 1;
+    // If there is only one dst_type in the entire tree and the path from
+    //    there to here is public then we are done!
+    return info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path;
+  } else if (info->dst_ptr_leading_to_static_ptr == dst_ptr) {
+    // We've been here before.  Update path to "most public"
+    if (info->path_dst_ptr_to_static_ptr == not_public_path)
+      info->path_dst_ptr_to_static_ptr = path_below;
+    // If there is only one dst_type in the entire tree and the path from
+    //    there to here is public then we are done!
+    return info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path;
+  } else {
+    // We've detected an ambiguous cast from (static_ptr, static_type)
+    //   to a dst_type
+    info->number_to_static_ptr += 1;
+    return true;
   }
 }
 
@@ -961,12 +961,13 @@ void __class_type_info::process_static_type_below_dst(
 //         }
 //     }
 // }
-void __vmi_class_type_info::search_below_dst(
+bool __vmi_class_type_info::search_below_dst(
     __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
   typedef const __base_class_type_info* Iter;
-  if (is_equal(this, info->static_type, use_strcmp))
+  if (is_equal(this, info->static_type, use_strcmp)) {
     process_static_type_below_dst(info, current_ptr, path_below);
-  else if (is_equal(this, info->dst_type, use_strcmp)) {
+    return false;
+  } else if (is_equal(this, info->dst_type, use_strcmp)) {
     // We've been here before if we've recorded current_ptr in one of these
     //   two places:
     if (current_ptr == info->dst_ptr_leading_to_static_ptr || current_ptr == info->dst_ptr_not_leading_to_static_ptr) {
@@ -1001,9 +1002,8 @@ void __vmi_class_type_info::search_below_dst(
           // Zero out found flags
           info->found_our_static_ptr  = false;
           info->found_any_static_type = false;
-          p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
-          if (info->search_done)
-            break;
+          if (p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp))
+            return true;
           if (info->found_any_static_type) {
             is_dst_type_derived_from_static_type = true;
             if (info->found_our_static_ptr) {
@@ -1044,15 +1044,15 @@ void __vmi_class_type_info::search_below_dst(
         //    (static_ptr, static_type), then the cast from
         //     (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
         //      so stop search.
-        if (info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path)
-          info->search_done = true;
+        return info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path;
       }
     }
   } else {
     // This is not a static_type and not a dst_type.
     const Iter e = __base_info + __base_count;
     Iter p       = __base_info;
-    p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+    if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+      return true;
     if (++p < e) {
       if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1) {
         // If there are multiple paths to a base above from here, or if
@@ -1060,32 +1060,28 @@ void __vmi_class_type_info::search_below_dst(
         //    then there is no way to break out of this loop early unless
         //    something below detects the search is done.
         do {
-          if (info->search_done)
-            break;
-          p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+            return true;
         } while (++p < e);
       } else if (__flags & __non_diamond_repeat_mask) {
         // There are not multiple paths to any base class from here and a
         //   dst_type pointing to (static_ptr, static_type) has not yet been
         //   found.
         do {
-          if (info->search_done)
-            break;
           // If we just found a dst_type with a public path to (static_ptr, static_type),
           //    then the only reason to continue the search is to make sure
           //    no other dst_type points to (static_ptr, static_type).
           //    If !diamond, then we don't need to search here.
           if (info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == public_path)
             break;
-          p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+            return true;
         } while (++p < e);
       } else {
         // There are no repeated types above this node.
         // There are no nodes with multiple parents above this node.
         // no dst_type has been found to (static_ptr, static_type)
         do {
-          if (info->search_done)
-            break;
           // If we just found a dst_type with a public path to (static_ptr, static_type),
           //    then the only reason to continue the search is to make sure
           //    no other dst_type points to (static_ptr, static_type).
@@ -1097,96 +1093,68 @@ void __vmi_class_type_info::search_below_dst(
           //    and not a dst_type under here.
           if (info->number_to_static_ptr == 1)
             break;
-          p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+            return true;
         } while (++p < e);
       }
     }
   }
+  return false;
 }
 
 // This is the same algorithm as __vmi_class_type_info::search_below_dst but
 //   simplified to the case that there is only a single base class.
-void __si_class_type_info::search_below_dst(
+bool __si_class_type_info::search_below_dst(
     __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
-  if (is_equal(this, info->static_type, use_strcmp))
+  if (is_equal(this, info->static_type, use_strcmp)) {
     process_static_type_below_dst(info, current_ptr, path_below);
-  else if (is_equal(this, info->dst_type, use_strcmp)) {
-    // We've been here before if we've recorded current_ptr in one of these
-    //   two places:
-    if (current_ptr == info->dst_ptr_leading_to_static_ptr || current_ptr == info->dst_ptr_not_leading_to_static_ptr) {
-      // We've seen this node before, and therefore have already searched
-      // its base classes above.
-      //  Update path to here that is "most public".
-      if (path_below == public_path)
-        info->path_dynamic_ptr_to_dst_ptr = public_path;
-    } else // We have haven't been here before
-    {
-      // Record the access path that got us here
-      //   If there is more than one dst_type this path doesn't matter.
-      info->path_dynamic_ptr_to_dst_ptr           = path_below;
-      bool does_dst_type_point_to_our_static_type = false;
-      // Only search above here if dst_type derives from static_type, or
-      //    if it is unknown if dst_type derives from static_type.
-      if (info->is_dst_type_derived_from_static_type != no) {
-        // Set up flags to record results from all base classes
-        bool is_dst_type_derived_from_static_type = false;
-        // Zero out found flags
-        info->found_our_static_ptr  = false;
-        info->found_any_static_type = false;
-        __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
-        if (info->found_any_static_type) {
-          is_dst_type_derived_from_static_type = true;
-          if (info->found_our_static_ptr)
-            does_dst_type_point_to_our_static_type = true;
-        }
-        // If we found no static_type,s then dst_type doesn't derive
-        //   from static_type, else it does.  Record this result so that
-        //   next time we hit a dst_type we will know not to search above
-        //   it if it doesn't derive from static_type.
-        if (is_dst_type_derived_from_static_type)
-          info->is_dst_type_derived_from_static_type = yes;
-        else
-          info->is_dst_type_derived_from_static_type = no;
-      }
-      if (!does_dst_type_point_to_our_static_type) {
-        // We found a dst_type that doesn't point to (static_ptr, static_type)
-        // So record the address of this dst_ptr and increment the
-        // count of the number of such dst_types found in the tree.
-        info->dst_ptr_not_leading_to_static_ptr = current_ptr;
-        info->number_to_dst_ptr += 1;
-        // If there exists another dst with a private path to
-        //    (static_ptr, static_type), then the cast from
-        //     (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
-        if (info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path)
-          info->search_done = true;
-      }
-    }
-  } else {
+    return false;
+  }
+
+  if (!is_equal(this, info->dst_type, use_strcmp)) {
     // This is not a static_type and not a dst_type
-    __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
+    return __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
   }
-}
 
-// This is the same algorithm as __vmi_class_type_info::search_below_dst but
-//   simplified to the case that there is no base class.
-void __class_type_info::search_below_dst(
-    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
-  if (is_equal(this, info->static_type, use_strcmp))
-    process_static_type_below_dst(info, current_ptr, path_below);
-  else if (is_equal(this, info->dst_type, use_strcmp)) {
-    // We've been here before if we've recorded current_ptr in one of these
-    //   two places:
-    if (current_ptr == info->dst_ptr_leading_to_static_ptr || current_ptr == info->dst_ptr_not_leading_to_static_ptr) {
-      // We've seen this node before, and therefore have already searched
-      // its base classes above.
-      //  Update path to here that is "most public".
-      if (path_below == public_path)
-        info->path_dynamic_ptr_to_dst_ptr = public_path;
-    } else // We have haven't been here before
-    {
-      // Record the access path that got us here
-      //   If there is more than one dst_type this path doesn't matter.
-      info->path_dynamic_ptr_to_dst_ptr = path_below;
+  // We've been here before if we've recorded current_ptr in one of these
+  //   two places:
+  if (current_ptr == info->dst_ptr_leading_to_static_ptr || current_ptr == info->dst_ptr_not_leading_to_static_ptr) {
+    // We've seen this node before, and therefore have already searched
+    // its base classes above.
+    //  Update path to here that is "most public".
+    if (path_below == public_path)
+      info->path_dynamic_ptr_to_dst_ptr = public_path;
+  } else // We have haven't been here before
+  {
+    // Record the access path that got us here
+    //   If there is more than one dst_type this path doesn't matter.
+    info->path_dynamic_ptr_to_dst_ptr           = path_below;
+    bool does_dst_type_point_to_our_static_type = false;
+    // Only search above here if dst_type derives from static_type, or
+    //    if it is unknown if dst_type derives from static_type.
+    if (info->is_dst_type_derived_from_static_type != no) {
+      // Set up flags to record results from all base classes
+      bool is_dst_type_derived_from_static_type = false;
+      // Zero out found flags
+      info->found_our_static_ptr  = false;
+      info->found_any_static_type = false;
+      if (__base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp))
+        return true;
+      if (info->found_any_static_type) {
+        is_dst_type_derived_from_static_type = true;
+        if (info->found_our_static_ptr)
+          does_dst_type_point_to_our_static_type = true;
+      }
+      // If we found no static_type,s then dst_type doesn't derive
+      //   from static_type, else it does.  Record this result so that
+      //   next time we hit a dst_type we will know not to search above
+      //   it if it doesn't derive from static_type.
+      if (is_dst_type_derived_from_static_type)
+        info->is_dst_type_derived_from_static_type = yes;
+      else
+        info->is_dst_type_derived_from_static_type = no;
+    }
+    if (!does_dst_type_point_to_our_static_type) {
       // We found a dst_type that doesn't point to (static_ptr, static_type)
       // So record the address of this dst_ptr and increment the
       // count of the number of such dst_types found in the tree.
@@ -1195,12 +1163,51 @@ void __class_type_info::search_below_dst(
       // If there exists another dst with a private path to
       //    (static_ptr, static_type), then the cast from
       //     (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
-      if (info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path)
-        info->search_done = true;
-      // We found that dst_type does not derive from static_type
-      info->is_dst_type_derived_from_static_type = no;
+      return info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path;
     }
   }
+  return false;
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_below_dst but
+//   simplified to the case that there is no base class.
+bool __class_type_info::search_below_dst(
+    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
+  if (is_equal(this, info->static_type, use_strcmp)) {
+    process_static_type_below_dst(info, current_ptr, path_below);
+    return false;
+  }
+
+  else if (!is_equal(this, info->dst_type, use_strcmp))
+    return false;
+
+  // We've been here before if we've recorded current_ptr in one of these
+  //   two places:
+  if (current_ptr == info->dst_ptr_leading_to_static_ptr || current_ptr == info->dst_ptr_not_leading_to_static_ptr) {
+    // We've seen this node before, and therefore have already searched
+    // its base classes above.
+    //  Update path to here that is "most public".
+    if (path_below == public_path)
+      info->path_dynamic_ptr_to_dst_ptr = public_path;
+    return false;
+  }
+
+  // We have haven't been here before
+
+  // Record the access path that got us here
+  //   If there is more than one dst_type this path doesn't matter.
+  info->path_dynamic_ptr_to_dst_ptr = path_below;
+  // We found a dst_type that doesn't point to (static_ptr, static_type)
+  // So record the address of this dst_ptr and increment the
+  // count of the number of such dst_types found in the tree.
+  info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+  info->number_to_dst_ptr += 1;
+  // If there exists another dst with a private path to
+  //    (static_ptr, static_type), then the cast from
+  //     (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
+  // We found that dst_type does not derive from static_type
+  info->is_dst_type_derived_from_static_type = no;
+  return info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path;
 }
 
 // Call this function when searching above a dst_type node.  This function searches
@@ -1229,97 +1236,98 @@ void __class_type_info::search_below_dst(
 //         }
 //     }
 // }
-void __vmi_class_type_info::search_above_dst(
+bool __vmi_class_type_info::search_above_dst(
     __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
   if (is_equal(this, info->static_type, use_strcmp))
-    process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
-  else {
-    typedef const __base_class_type_info* Iter;
-    // This is not a static_type and not a dst_type
-    // Save flags so they can be restored when returning to nodes below.
-    bool found_our_static_ptr  = info->found_our_static_ptr;
-    bool found_any_static_type = info->found_any_static_type;
-    // We've found a dst_type below with a path to here.  If the path
-    //    to here is not public, there may be another path to here that
-    //    is public.  So we have to assume that the path to here is public.
-    //  We can stop looking above if:
-    //    1.  We've found a public path to (static_ptr, static_type).
-    //    2.  We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
-    //        This is detected at the (static_ptr, static_type).
-    //    3.  We can prove that there is no public path to (static_ptr, static_type)
-    //        above here.
-    const Iter e = __base_info + __base_count;
-    Iter p       = __base_info;
-    // Zero out found flags
-    info->found_our_static_ptr  = false;
-    info->found_any_static_type = false;
-    p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
-    found_our_static_ptr |= info->found_our_static_ptr;
-    found_any_static_type |= info->found_any_static_type;
-    if (++p < e) {
-      do {
-        if (info->search_done)
+    return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+
+  typedef const __base_class_type_info* Iter;
+  // This is not a static_type and not a dst_type
+  // Save flags so they can be restored when returning to nodes below.
+  bool found_our_static_ptr  = info->found_our_static_ptr;
+  bool found_any_static_type = info->found_any_static_type;
+  // We've found a dst_type below with a path to here.  If the path
+  //    to here is not public, there may be another path to here that
+  //    is public.  So we have to assume that the path to here is public.
+  //  We can stop looking above if:
+  //    1.  We've found a public path to (static_ptr, static_type).
+  //    2.  We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
+  //        This is detected at the (static_ptr, static_type).
+  //    3.  We can prove that there is no public path to (static_ptr, static_type)
+  //        above here.
+  const Iter e = __base_info + __base_count;
+  Iter p       = __base_info;
+  // Zero out found flags
+  info->found_our_static_ptr  = false;
+  info->found_any_static_type = false;
+  if (p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp))
+    return true;
+  found_our_static_ptr |= info->found_our_static_ptr;
+  found_any_static_type |= info->found_any_static_type;
+  if (++p < e) {
+    do {
+      if (info->found_our_static_ptr) {
+        // If we found what we're looking for, stop looking above.
+        if (info->path_dst_ptr_to_static_ptr == public_path)
           break;
-        if (info->found_our_static_ptr) {
-          // If we found what we're looking for, stop looking above.
-          if (info->path_dst_ptr_to_static_ptr == public_path)
-            break;
-          // We found a private path to (static_ptr, static_type)
-          //   If there is no diamond then there is only one path
-          //   to (static_ptr, static_type) from here and we just found it.
-          if (!(__flags & __diamond_shaped_mask))
-            break;
-        } else if (info->found_any_static_type) {
-          // If we found a static_type that isn't the one we're looking
-          //    for, and if there are no repeated types above here,
-          //    then stop looking.
-          if (!(__flags & __non_diamond_repeat_mask))
-            break;
-        }
-        // Zero out found flags
-        info->found_our_static_ptr  = false;
-        info->found_any_static_type = false;
-        p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
-        found_our_static_ptr |= info->found_our_static_ptr;
-        found_any_static_type |= info->found_any_static_type;
-      } while (++p < e);
-    }
-    // Restore flags
-    info->found_our_static_ptr  = found_our_static_ptr;
-    info->found_any_static_type = found_any_static_type;
+        // We found a private path to (static_ptr, static_type)
+        //   If there is no diamond then there is only one path
+        //   to (static_ptr, static_type) from here and we just found it.
+        if (!(__flags & __diamond_shaped_mask))
+          break;
+      } else if (info->found_any_static_type) {
+        // If we found a static_type that isn't the one we're looking
+        //    for, and if there are no repeated types above here,
+        //    then stop looking.
+        if (!(__flags & __non_diamond_repeat_mask))
+          break;
+      }
+      // Zero out found flags
+      info->found_our_static_ptr  = false;
+      info->found_any_static_type = false;
+      if (p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp))
+        return true;
+      found_our_static_ptr |= info->found_our_static_ptr;
+      found_any_static_type |= info->found_any_static_type;
+    } while (++p < e);
   }
+  // Restore flags
+  info->found_our_static_ptr  = found_our_static_ptr;
+  info->found_any_static_type = found_any_static_type;
+  return false;
 }
 
 // This is the same algorithm as __vmi_class_type_info::search_above_dst but
 //   simplified to the case that there is only a single base class.
-void __si_class_type_info::search_above_dst(
+bool __si_class_type_info::search_above_dst(
     __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
   if (is_equal(this, info->static_type, use_strcmp))
-    process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+    return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
   else
-    __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+    return __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
 }
 
 // This is the same algorithm as __vmi_class_type_info::search_above_dst but
 //   simplified to the case that there is no base class.
-void __class_type_info::search_above_dst(
+bool __class_type_info::search_above_dst(
     __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
   if (is_equal(this, info->static_type, use_strcmp))
-    process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+    return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+  return false;
 }
 
 // The search functions for __base_class_type_info are simply convenience
 //   functions for adjusting the current_ptr and path_below as the search is
 //   passed up to the base class node.
 
-void __base_class_type_info::search_above_dst(
+bool __base_class_type_info::search_above_dst(
     __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
   ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
   if (__offset_flags & __virtual_mask) {
     const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));
     offset_to_base     = update_offset_to_base(vtable, offset_to_base);
   }
-  __base_type->search_above_dst(
+  return __base_type->search_above_dst(
       info,
       dst_ptr,
       static_cast<const char*>(current_ptr) + offset_to_base,
@@ -1327,14 +1335,14 @@ void __base_class_type_info::search_above_dst(
       use_strcmp);
 }
 
-void __base_class_type_info::search_below_dst(
+bool __base_class_type_info::search_below_dst(
     __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
   ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
   if (__offset_flags & __virtual_mask) {
     const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));
     offset_to_base     = update_offset_to_base(vtable, offset_to_base);
   }
-  __base_type->search_below_dst(
+  return __base_type->search_below_dst(
       info,
       static_cast<const char*>(current_ptr) + offset_to_base,
       (__offset_flags & __public_mask) ? path_below : not_public_path,
diff --git a/libcxxabi/src/private_typeinfo.h b/libcxxabi/src/private_typeinfo.h
index 62d0addb19eb7..2b5dfa42a6521 100644
--- a/libcxxabi/src/private_typeinfo.h
+++ b/libcxxabi/src/private_typeinfo.h
@@ -76,9 +76,6 @@ struct catch_info {
   // Number of dst_types below (static_ptr, static_type)
   int number_to_static_ptr;
 
-  // Set whenever a search can be stopped
-  bool search_done;
-
   // There is no object (seen when we throw a null pointer to object).
   bool have_object;
   // Virtual base
@@ -127,8 +124,6 @@ struct _LIBCXXABI_HIDDEN __dynamic_cast_info
     // communicates to a dst_type node that a static_type was found
     //    above it, but it wasn't (static_ptr, static_type)
     bool found_any_static_type;
-    // Set whenever a search can be stopped
-    bool search_done;
 };
 
 // Has no base class
@@ -136,19 +131,16 @@ class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
 public:
   _LIBCXXABI_HIDDEN ~__class_type_info() override;
 
-  _LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
-                                                       const void *,
-                                                       const void *, int) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool
+  process_static_type_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
   _LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
                                                        const void *, int) const;
-  _LIBCXXABI_HIDDEN void process_found_base_class(catch_info*, void*, int) const;
-  _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
-                                                  const void *, const void *,
-                                                  int, bool) const;
-  _LIBCXXABI_HIDDEN virtual void
-  search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool process_found_base_class(catch_info*, void*, int) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool
+  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
   _LIBCXXABI_HIDDEN bool can_catch(const __shim_type_info*, void*&) const final;
-  _LIBCXXABI_HIDDEN virtual void has_unambiguous_public_base(catch_info*, void*, int) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool has_unambiguous_public_base(catch_info*, void*, int) const;
 };
 
 // Has one non-virtual public base class at offset zero
@@ -158,9 +150,10 @@ class _LIBCXXABI_TYPE_VIS __si_class_type_info final : public __class_type_info
 
   _LIBCXXABI_HIDDEN ~__si_class_type_info() final;
 
-  _LIBCXXABI_HIDDEN void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN void has_unambiguous_public_base(catch_info*, void*, int) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool
+  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const final;
 };
 
 struct _LIBCXXABI_HIDDEN __base_class_type_info
@@ -176,9 +169,9 @@ struct _LIBCXXABI_HIDDEN __base_class_type_info
         __offset_shift = 8
     };
 
-    void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
-    void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
-    void has_unambiguous_public_base(catch_info*, void*, int) const;
+    [[nodiscard]] bool search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
+    [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
+    [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const;
 };
 
 // Has one or more base classes
@@ -197,9 +190,10 @@ class _LIBCXXABI_TYPE_VIS __vmi_class_type_info final : public __class_type_info
 
   _LIBCXXABI_HIDDEN ~__vmi_class_type_info() final;
 
-  _LIBCXXABI_HIDDEN void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN void has_unambiguous_public_base(catch_info*, void*, int) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool
+  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const final;
 };
 
 class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {

>From 5e95606d5fb88d09d7b673caaffd274a512c62ed Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sat, 10 Oct 2026 10:50:02 +0200
Subject: [PATCH 2/2] [libc++abi] Split strcmp and non-strcmp dynamic_casts

---
 libcxxabi/src/private_typeinfo.cpp |  84 ++++++++++++---------
 libcxxabi/src/private_typeinfo.h   | 117 +++++++++++++++++++++++++++--
 2 files changed, 157 insertions(+), 44 deletions(-)

diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 98dcfd7e1275f..0572aa171cb4c 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -183,7 +183,7 @@ const void* dyn_cast_to_derived(
       false,
       false};
   // Do the  search
-  (void)dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
+  (void)dst_type->search_above_dst<false>(&info, dynamic_ptr, dynamic_ptr, public_path);
 #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // The following if should always be false because we should
   //   definitely find (static_ptr, static_type), either on a public
@@ -204,7 +204,7 @@ const void* dyn_cast_to_derived(
     // Redo the search comparing type_info's using strcmp
     info                    = {dst_type, static_ptr, static_type, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false};
     info.number_of_dst_type = 1;
-    dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
+    dst_type->search_above_dst<true>(&info, dynamic_ptr, dynamic_ptr, public_path);
   }
 #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // Query the search.
@@ -254,7 +254,7 @@ const void* dyn_cast_try_downcast(
       1, // number_of_dst_type
       false,
       false};
-  (void)dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
+  (void)dynamic_type->search_above_dst<false>(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path);
   if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
     // We have found at least one path from dynamic_ptr to dst_ptr. The
     //   downcast can succeed.
@@ -276,7 +276,7 @@ const void* dyn_cast_slow(
   // Initialize info struct for this search.
   __dynamic_cast_info info = {dst_type, static_ptr, static_type, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false};
 
-  (void)dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
+  (void)dynamic_type->search_below_dst<false>(&info, dynamic_ptr, public_path);
 #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // The following if should always be false because we should
   //   definitely find (static_ptr, static_type), either on a public
@@ -296,7 +296,7 @@ const void* dyn_cast_slow(
              dst_type->name());
     // Redo the search comparing type_info's using strcmp
     info = {dst_type, static_ptr, static_type, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false};
-    dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
+    dynamic_type->search_below_dst<true>(&info, dynamic_ptr, public_path);
   }
 #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   // Query the search.
@@ -961,8 +961,9 @@ void __class_type_info::process_static_type_below_dst(
 //         }
 //     }
 // }
-bool __vmi_class_type_info::search_below_dst(
-    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __vmi_class_type_info::search_below_dst_impl(
+    __dynamic_cast_info* info, const void* current_ptr, int path_below) const {
   typedef const __base_class_type_info* Iter;
   if (is_equal(this, info->static_type, use_strcmp)) {
     process_static_type_below_dst(info, current_ptr, path_below);
@@ -1002,7 +1003,7 @@ bool __vmi_class_type_info::search_below_dst(
           // Zero out found flags
           info->found_our_static_ptr  = false;
           info->found_any_static_type = false;
-          if (p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp))
+          if (p->search_above_dst<use_strcmp>(info, current_ptr, current_ptr, public_path))
             return true;
           if (info->found_any_static_type) {
             is_dst_type_derived_from_static_type = true;
@@ -1051,7 +1052,7 @@ bool __vmi_class_type_info::search_below_dst(
     // This is not a static_type and not a dst_type.
     const Iter e = __base_info + __base_count;
     Iter p       = __base_info;
-    if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+    if (p->search_below_dst<use_strcmp>(info, current_ptr, path_below))
       return true;
     if (++p < e) {
       if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1) {
@@ -1060,7 +1061,7 @@ bool __vmi_class_type_info::search_below_dst(
         //    then there is no way to break out of this loop early unless
         //    something below detects the search is done.
         do {
-          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+          if (p->search_below_dst<use_strcmp>(info, current_ptr, path_below))
             return true;
         } while (++p < e);
       } else if (__flags & __non_diamond_repeat_mask) {
@@ -1074,7 +1075,7 @@ bool __vmi_class_type_info::search_below_dst(
           //    If !diamond, then we don't need to search here.
           if (info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == public_path)
             break;
-          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+          if (p->search_below_dst<use_strcmp>(info, current_ptr, path_below))
             return true;
         } while (++p < e);
       } else {
@@ -1093,7 +1094,7 @@ bool __vmi_class_type_info::search_below_dst(
           //    and not a dst_type under here.
           if (info->number_to_static_ptr == 1)
             break;
-          if (p->search_below_dst(info, current_ptr, path_below, use_strcmp))
+          if (p->search_below_dst<use_strcmp>(info, current_ptr, path_below))
             return true;
         } while (++p < e);
       }
@@ -1104,8 +1105,9 @@ bool __vmi_class_type_info::search_below_dst(
 
 // This is the same algorithm as __vmi_class_type_info::search_below_dst but
 //   simplified to the case that there is only a single base class.
-bool __si_class_type_info::search_below_dst(
-    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __si_class_type_info::search_below_dst_impl(
+    __dynamic_cast_info* info, const void* current_ptr, int path_below) const {
   if (is_equal(this, info->static_type, use_strcmp)) {
     process_static_type_below_dst(info, current_ptr, path_below);
     return false;
@@ -1113,7 +1115,7 @@ bool __si_class_type_info::search_below_dst(
 
   if (!is_equal(this, info->dst_type, use_strcmp)) {
     // This is not a static_type and not a dst_type
-    return __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
+    return __base_type->search_below_dst<use_strcmp>(info, current_ptr, path_below);
   }
 
   // We've been here before if we've recorded current_ptr in one of these
@@ -1138,7 +1140,7 @@ bool __si_class_type_info::search_below_dst(
       // Zero out found flags
       info->found_our_static_ptr  = false;
       info->found_any_static_type = false;
-      if (__base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp))
+      if (__base_type->search_above_dst<use_strcmp>(info, current_ptr, current_ptr, public_path))
         return true;
       if (info->found_any_static_type) {
         is_dst_type_derived_from_static_type = true;
@@ -1171,8 +1173,9 @@ bool __si_class_type_info::search_below_dst(
 
 // This is the same algorithm as __vmi_class_type_info::search_below_dst but
 //   simplified to the case that there is no base class.
-bool __class_type_info::search_below_dst(
-    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __class_type_info::search_below_dst_impl(
+    __dynamic_cast_info* info, const void* current_ptr, int path_below) const {
   if (is_equal(this, info->static_type, use_strcmp)) {
     process_static_type_below_dst(info, current_ptr, path_below);
     return false;
@@ -1210,6 +1213,13 @@ bool __class_type_info::search_below_dst(
   return info->number_to_static_ptr == 1 && info->path_dst_ptr_to_static_ptr == not_public_path;
 }
 
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+bool __class_type_info::search_below_dst_strcmp(
+    __dynamic_cast_info* info, const void* current_ptr, int path_below) const {
+  return search_below_dst_impl<true>(info, current_ptr, path_below);
+}
+#endif
+
 // Call this function when searching above a dst_type node.  This function searches
 // for a public path to (static_ptr, static_type).
 // This function is guaranteed not to find a node of type dst_type.
@@ -1236,8 +1246,9 @@ bool __class_type_info::search_below_dst(
 //         }
 //     }
 // }
-bool __vmi_class_type_info::search_above_dst(
-    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __vmi_class_type_info::search_above_dst_impl(
+    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
   if (is_equal(this, info->static_type, use_strcmp))
     return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
 
@@ -1260,7 +1271,7 @@ bool __vmi_class_type_info::search_above_dst(
   // Zero out found flags
   info->found_our_static_ptr  = false;
   info->found_any_static_type = false;
-  if (p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp))
+  if (p->search_above_dst<use_strcmp>(info, dst_ptr, current_ptr, path_below))
     return true;
   found_our_static_ptr |= info->found_our_static_ptr;
   found_any_static_type |= info->found_any_static_type;
@@ -1285,7 +1296,7 @@ bool __vmi_class_type_info::search_above_dst(
       // Zero out found flags
       info->found_our_static_ptr  = false;
       info->found_any_static_type = false;
-      if (p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp))
+      if (p->search_above_dst<use_strcmp>(info, dst_ptr, current_ptr, path_below))
         return true;
       found_our_static_ptr |= info->found_our_static_ptr;
       found_any_static_type |= info->found_any_static_type;
@@ -1299,18 +1310,20 @@ bool __vmi_class_type_info::search_above_dst(
 
 // This is the same algorithm as __vmi_class_type_info::search_above_dst but
 //   simplified to the case that there is only a single base class.
-bool __si_class_type_info::search_above_dst(
-    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __si_class_type_info::search_above_dst_impl(
+    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
   if (is_equal(this, info->static_type, use_strcmp))
     return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
   else
-    return __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+    return __base_type->search_above_dst<use_strcmp>(info, dst_ptr, current_ptr, path_below);
 }
 
 // This is the same algorithm as __vmi_class_type_info::search_above_dst but
 //   simplified to the case that there is no base class.
-bool __class_type_info::search_above_dst(
-    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
+template <bool use_strcmp>
+bool __class_type_info::search_above_dst_impl(
+    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
   if (is_equal(this, info->static_type, use_strcmp))
     return process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
   return false;
@@ -1319,34 +1332,33 @@ bool __class_type_info::search_above_dst(
 // The search functions for __base_class_type_info are simply convenience
 //   functions for adjusting the current_ptr and path_below as the search is
 //   passed up to the base class node.
-
+template <bool use_strcmp>
 bool __base_class_type_info::search_above_dst(
-    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const {
+    __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
   ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
   if (__offset_flags & __virtual_mask) {
     const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));
     offset_to_base     = update_offset_to_base(vtable, offset_to_base);
   }
-  return __base_type->search_above_dst(
+  return __base_type->search_above_dst<use_strcmp>(
       info,
       dst_ptr,
       static_cast<const char*>(current_ptr) + offset_to_base,
-      (__offset_flags & __public_mask) ? path_below : not_public_path,
-      use_strcmp);
+      (__offset_flags & __public_mask) ? path_below : not_public_path);
 }
 
+template <bool use_strcmp>
 bool __base_class_type_info::search_below_dst(
-    __dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const {
+    __dynamic_cast_info* info, const void* current_ptr, int path_below) const {
   ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
   if (__offset_flags & __virtual_mask) {
     const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));
     offset_to_base     = update_offset_to_base(vtable, offset_to_base);
   }
-  return __base_type->search_below_dst(
+  return __base_type->search_below_dst<use_strcmp>(
       info,
       static_cast<const char*>(current_ptr) + offset_to_base,
-      (__offset_flags & __public_mask) ? path_below : not_public_path,
-      use_strcmp);
+      (__offset_flags & __public_mask) ? path_below : not_public_path);
 }
 
 } // namespace __cxxabiv1
diff --git a/libcxxabi/src/private_typeinfo.h b/libcxxabi/src/private_typeinfo.h
index 2b5dfa42a6521..a4f5915c1f49b 100644
--- a/libcxxabi/src/private_typeinfo.h
+++ b/libcxxabi/src/private_typeinfo.h
@@ -136,9 +136,65 @@ class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
   _LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
                                                        const void *, int) const;
   _LIBCXXABI_HIDDEN [[nodiscard]] bool process_found_base_class(catch_info*, void*, int) const;
+
+  template <bool use_strcmp>
+  [[nodiscard]] bool
+  search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    if constexpr (use_strcmp)
+      return search_above_dst_strcmp(info, dst_ptr, current_ptr, path_below);
+    else
+      return search_above_dst(info, dst_ptr, current_ptr, path_below);
+#else
+    static_assert(!use_strcmp);
+    return search_above_dst(info, dst_ptr, current_ptr, path_below);
+#endif
+  }
+
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below) const {
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+    if constexpr (use_strcmp)
+      return search_below_dst_strcmp(info, current_ptr, path_below);
+    else
+      return search_below_dst(info, current_ptr, path_below);
+#else
+    static_assert(!use_strcmp);
+    return search_below_dst(info, current_ptr, path_below);
+#endif
+  }
+
+  template <bool use_strcmp>
+  bool
+  search_above_dst_impl(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const;
+
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool
+  search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
+    return search_above_dst_impl<false>(info, dst_ptr, current_ptr, path_below);
+  }
+
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool search_above_dst_strcmp(
+      __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const {
+    return search_above_dst_impl<true>(info, dst_ptr, current_ptr, path_below);
+  }
+#endif
+
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_below_dst_impl(__dynamic_cast_info* info, const void* current_ptr, int path_below) const;
+
+  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool
+  search_below_dst(__dynamic_cast_info* catch_info, const void* current_ptr, int path_below) const {
+    return search_below_dst_impl<false>(catch_info, current_ptr, path_below);
+  }
+
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool
-  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
-  _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
+  search_below_dst_strcmp(__dynamic_cast_info* info, const void* current_ptr, int path_below) const {
+    return search_below_dst_impl<true>(info, current_ptr, path_below);
+  }
+#endif
+
   _LIBCXXABI_HIDDEN bool can_catch(const __shim_type_info*, void*&) const final;
   _LIBCXXABI_HIDDEN [[nodiscard]] virtual bool has_unambiguous_public_base(catch_info*, void*, int) const;
 };
@@ -150,9 +206,29 @@ class _LIBCXXABI_TYPE_VIS __si_class_type_info final : public __class_type_info
 
   _LIBCXXABI_HIDDEN ~__si_class_type_info() final;
 
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_above_dst_impl(__dynamic_cast_info*, const void*, const void*, int) const;
+
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_above_dst(
+      __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const final {
+    return search_above_dst_impl<false>(info, dst_ptr, current_ptr, path_below);
+  }
+
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_above_dst_strcmp(
+      __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const final {
+    return search_above_dst_impl<true>(info, dst_ptr, current_ptr, path_below);
+  }
+#endif
+
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_below_dst_impl(__dynamic_cast_info*, const void*, int) const;
+
   _LIBCXXABI_HIDDEN [[nodiscard]] bool
-  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
+  search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below) const final {
+    return search_below_dst_impl<false>(info, current_ptr, path_below);
+  }
+
   _LIBCXXABI_HIDDEN [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const final;
 };
 
@@ -169,8 +245,10 @@ struct _LIBCXXABI_HIDDEN __base_class_type_info
         __offset_shift = 8
     };
 
-    [[nodiscard]] bool search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
-    [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
+    template <bool use_strcmp>
+    [[nodiscard]] bool search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+    template <bool use_strcmp>
+    [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int) const;
     [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const;
 };
 
@@ -190,9 +268,32 @@ class _LIBCXXABI_TYPE_VIS __vmi_class_type_info final : public __class_type_info
 
   _LIBCXXABI_HIDDEN ~__vmi_class_type_info() final;
 
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_above_dst_impl(__dynamic_cast_info*, const void*, const void*, int) const;
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_above_dst(
+      __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const final {
+    return search_above_dst_impl<false>(info, dst_ptr, current_ptr, path_below);
+  }
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_above_dst_strcmp(
+      __dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const final {
+    return search_above_dst_impl<true>(info, dst_ptr, current_ptr, path_below);
+  }
+#endif
+
+  template <bool use_strcmp>
+  [[nodiscard]] bool search_below_dst_impl(__dynamic_cast_info*, const void*, int) const;
+
+  _LIBCXXABI_HIDDEN [[nodiscard]] bool
+  search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below) const final {
+    return search_below_dst_impl<false>(info, current_ptr, path_below);
+  }
+#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
   _LIBCXXABI_HIDDEN [[nodiscard]] bool
-  search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const final;
-  _LIBCXXABI_HIDDEN [[nodiscard]] bool search_below_dst(__dynamic_cast_info*, const void*, int, bool) const final;
+  search_below_dst_strcmp(__dynamic_cast_info* info, const void* current_ptr, int path_below) const final {
+    return search_below_dst_impl<true>(info, current_ptr, path_below);
+  }
+#endif
   _LIBCXXABI_HIDDEN [[nodiscard]] bool has_unambiguous_public_base(catch_info*, void*, int) const final;
 };
 



More information about the libcxx-commits mailing list