This patch optimizes out calls to __dynamic_cast when the type being cast to is final (or its destructor), replacing them with a simple comparison of the types' vtable addresses. This is already implemented and done by default in clang (https://reviews.llvm.org/D154658), but can be turned off with -fno-assume-unique-vtables, due to the problems it can cause with unmerged vtables when using shared libraries. With the optimization not really fitting well under any existing flag (that I know of), I believe an -fassume-unique-vtables flag (or something similar) would be appropriate to add to gcc, which besides enabling this optimization, should probably also define __GXX_MERGED_TYPEINFO_NAMES as 1.
diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc index c06a18b3ff1..a4259253f8d 100644 --- a/gcc/cp/rtti.cc +++ b/gcc/cp/rtti.cc @@ -761,6 +761,51 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr, if (tc == REFERENCE_TYPE) expr1 = cp_build_addr_expr (expr1, complain); + + + /* If type is final, don't call dynamic_cast. + * Instead just check vtable equivalence at runtime. + * TYPE_FINAL_P does not return true for non-final class with + * final destructor overriding virtual though, + * so look through virtual functions for final destructor */ + + bool can_inherit = !TYPE_FINAL_P (target_type); + tree vchain; + for (vchain = BINFO_VIRTUALS (TYPE_BINFO (target_type)); + vchain && can_inherit; + vchain = TREE_CHAIN (vchain)) + { + if (!DECL_DESTRUCTOR_P (BV_FN (vchain))) + continue; + if (!DECL_FINAL_P (BV_FN (vchain))) + continue; + can_inherit = false; + } + + if (!can_inherit) + { + /* Retrieve vtable declaration and address. */ + tree trgt_vtbl_addr = build_address (get_vtable_decl (target_type, 0)); + /* The offset-to-top field is at index -2 from the vptr. + * Offsetting -2 on build_vtbl_ref (at low optimization) results in register being + * subtracted from at runtime, done on vtbl address to prevent */ + tree trgt_vptr_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE(trgt_vtbl_addr), + trgt_vtbl_addr, size_int(2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE * + tree_to_shwi (TYPE_SIZE(ptr_type_node))/8)); + + tree src_obj = cp_build_fold_indirect_ref (expr); + tree src_vptr = build_address (build_vtbl_ref (src_obj, size_int(0))); + + /* Check vtable equivalence by vptr address */ + tree cond = build2 (NE_EXPR, boolean_type_node, trgt_vptr_addr, src_vptr); + tree result = build3 (COND_EXPR, type, cond, nullptr_node, + build_static_cast (loc, type, expr, complain)); + SET_EXPR_LOCATION (result, loc); + result = cp_convert (type, result, complain); + + return build_if_nonnull (expr, result, complain); + } + elems[0] = expr1; elems[1] = td3; elems[2] = td2; This e-mail and any attachments may contain information that is confidential and proprietary and otherwise protected from disclosure. If you are not the intended recipient of this e-mail, do not read, duplicate or redistribute it by any means. Please immediately delete it and any attachments and notify the sender that you have received it by mistake. Unintended recipients are prohibited from taking action on the basis of information in this e-mail or any attachments. The DRW Companies make no representations that this e-mail or any attachments are free of computer viruses or other defects.