diff options
Diffstat (limited to 'gcc/cp/class.c')
-rw-r--r-- | gcc/cp/class.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1853d4f..d58577f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -542,13 +542,15 @@ build_vtbl_ref (tree instance, tree idx) return aref; } -/* Given an object INSTANCE, return an expression which yields a - function pointer corresponding to vtable element INDEX. */ +/* Given a stable object pointer INSTANCE_PTR, return an expression which + yields a function pointer corresponding to vtable element INDEX. */ tree -build_vfn_ref (tree instance, tree idx) +build_vfn_ref (tree instance_ptr, tree idx) { - tree aref = build_vtbl_ref_1 (instance, idx); + tree aref; + + aref = build_vtbl_ref_1 (build_indirect_ref (instance_ptr, 0), idx); /* When using function descriptors, the address of the vtable entry is treated as a function pointer. */ @@ -556,6 +558,9 @@ build_vfn_ref (tree instance, tree idx) aref = build1 (NOP_EXPR, TREE_TYPE (aref), build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1)); + /* Remember this as a method reference, for later devirtualization. */ + aref = build (OBJ_TYPE_REF, TREE_TYPE (aref), aref, instance_ptr, idx); + return aref; } @@ -7912,3 +7917,31 @@ build_rtti_vtbl_entries (tree binfo, vtbl_init_data* vid) *vid->last_init = build_tree_list (NULL_TREE, init); vid->last_init = &TREE_CHAIN (*vid->last_init); } + +/* Fold a OBJ_TYPE_REF expression to the address of a function. + KNOWN_TYPE carries the true type of OBJ_TYPE_REF_OBJECT(REF). */ + +tree +cp_fold_obj_type_ref (tree ref, tree known_type) +{ + HOST_WIDE_INT index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1); + HOST_WIDE_INT i = 0; + tree v = TYPE_BINFO_VIRTUALS (known_type); + tree fndecl; + + while (i != index) + { + i += (TARGET_VTABLE_USES_DESCRIPTORS + ? TARGET_VTABLE_USES_DESCRIPTORS : 1); + v = TREE_CHAIN (v); + } + + fndecl = BV_FN (v); + +#ifdef ENABLE_CHECKING + if (!tree_int_cst_equal (OBJ_TYPE_REF_TOKEN (ref), DECL_VINDEX (fndecl))) + abort (); +#endif + + return build_address (fndecl); +} |