diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2001-11-25 13:21:45 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2001-11-25 13:21:45 +0000 |
commit | 338d90b89f23deaa5ce2ae80b8adf9cb52808679 (patch) | |
tree | 0d461fab9e84fd53ebc0b813e9c60b27eb83f6e0 | |
parent | 92fa4733ab20d5f4a8e9eb7c6f5c924427677549 (diff) | |
download | gcc-338d90b89f23deaa5ce2ae80b8adf9cb52808679.zip gcc-338d90b89f23deaa5ce2ae80b8adf9cb52808679.tar.gz gcc-338d90b89f23deaa5ce2ae80b8adf9cb52808679.tar.bz2 |
re PR c++/3145 (virtual inheritance still creates wrong code)
cp:
PR g++/3145
* class.c (build_vbase_pointer): Remove.
(build_vbase_path): Remove.
(build_base_path): New function.
* cp-tree.h (base_access, base_kind): New enumerations.
(build_base_path): Declare.
(convert_pointer_to_real): Remove.
(convert_pointer_to): Remove.
(lookup_base): Declare.
(convert_pointer_to_vbase): Remove.
* call.c (build_scoped_method_call): Use lookup_base &
build_base_path instead of convert_pointer_to_real,
get_base_distance & get_binfo.
(build_over_call): Likewise.
* cvt.c (cp_convert_to_pointer): Likewise.
(convert_to_pointer_force): Likewise.
(build_up_reference): Likewise.
(convert_pointer_to_real): Remove.
(convert_pointer_to): Remove.
* init.c (dfs_initialize_vtbl_ptrs): Use build_base_path
instead of convert_pointer_to_vbase & build_vbase_path.
(emit_base_init): Use build_base_path instead of
convert_pointer_to_real.
(expand_virtual_init): Lose unrequired conversions.
(resolve_offset_ref): Use lookup_base and build_base_path
instead of convert_pointer_to.
* rtti.c (build_dynamic_cast_1): Use lookup_base &
build_base_path instead of get_base_distance & build_vbase_path.
* search.c (get_vbase_1): Remove.
(get_vbase): Remove.
(convert_pointer_to_vbase): Remove.
(lookup_base_recursive): New function.
(lookup_base): New function.
* typeck.c (require_complete_type): Use lookup_base &
build_base_path instead of convert_pointer_to.
(build_component_ref): Likewise.
(build_x_function_call): Likewise.
(get_member_function_from_ptrfunc): Likewise.
(build_component_addr): Likewise.
* typeck2.c (build_scoped_ref): Likewise.
testsuite:
* g++.dg/abi/vbase8-4.C: New test.
From-SVN: r47316
-rw-r--r-- | gcc/cp/ChangeLog | 43 | ||||
-rw-r--r-- | gcc/cp/call.c | 24 | ||||
-rw-r--r-- | gcc/cp/class.c | 270 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 28 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 207 | ||||
-rw-r--r-- | gcc/cp/init.c | 46 | ||||
-rw-r--r-- | gcc/cp/rtti.c | 25 | ||||
-rw-r--r-- | gcc/cp/search.c | 264 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 42 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/vbase8-4.C | 78 |
12 files changed, 568 insertions, 470 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a3856da..3512f20 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,46 @@ +2001-11-25 Nathan Sidwell <nathan@codesourcery.com> + + PR g++/3145 + * class.c (build_vbase_pointer): Remove. + (build_vbase_path): Remove. + (build_base_path): New function. + * cp-tree.h (base_access, base_kind): New enumerations. + (build_base_path): Declare. + (convert_pointer_to_real): Remove. + (convert_pointer_to): Remove. + (lookup_base): Declare. + (convert_pointer_to_vbase): Remove. + * call.c (build_scoped_method_call): Use lookup_base & + build_base_path instead of convert_pointer_to_real, + get_base_distance & get_binfo. + (build_over_call): Likewise. + * cvt.c (cp_convert_to_pointer): Likewise. + (convert_to_pointer_force): Likewise. + (build_up_reference): Likewise. + (convert_pointer_to_real): Remove. + (convert_pointer_to): Remove. + * init.c (dfs_initialize_vtbl_ptrs): Use build_base_path + instead of convert_pointer_to_vbase & build_vbase_path. + (emit_base_init): Use build_base_path instead of + convert_pointer_to_real. + (expand_virtual_init): Lose unrequired conversions. + (resolve_offset_ref): Use lookup_base and build_base_path + instead of convert_pointer_to. + * rtti.c (build_dynamic_cast_1): Use lookup_base & + build_base_path instead of get_base_distance & build_vbase_path. + * search.c (get_vbase_1): Remove. + (get_vbase): Remove. + (convert_pointer_to_vbase): Remove. + (lookup_base_recursive): New function. + (lookup_base): New function. + * typeck.c (require_complete_type): Use lookup_base & + build_base_path instead of convert_pointer_to. + (build_component_ref): Likewise. + (build_x_function_call): Likewise. + (get_member_function_from_ptrfunc): Likewise. + (build_component_addr): Likewise. + * typeck2.c (build_scoped_ref): Likewise. + 2001-11-22 Bryce McKinlay <bryce@waitaki.otago.ac.nz> * cp-tree.h (CP_TYPE_QUALS): Removed. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 46aacca..c0ab2c2 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -298,7 +298,7 @@ build_scoped_method_call (exp, basetype, name, parms) if (! binfo) { - binfo = get_binfo (basetype, type, 1); + binfo = lookup_base (type, basetype, ba_check, NULL); if (binfo == error_mark_node) return error_mark_node; if (! binfo) @@ -308,9 +308,12 @@ build_scoped_method_call (exp, basetype, name, parms) if (binfo) { if (TREE_CODE (exp) == INDIRECT_REF) - decl = build_indirect_ref - (convert_pointer_to_real - (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL); + { + decl = build_base_path (PLUS_EXPR, + build_unary_op (ADDR_EXPR, exp, 0), + binfo, 1); + decl = build_indirect_ref (decl, NULL); + } else decl = build_scoped_ref (exp, basetype); @@ -4157,7 +4160,9 @@ build_over_call (cand, args, flags) So we can assume that anything passed as 'this' is non-null, and optimize accordingly. */ my_friendly_assert (TREE_CODE (parmtype) == POINTER_TYPE, 19990811); - t = convert_pointer_to_real (TREE_TYPE (parmtype), TREE_VALUE (arg)); + t = lookup_base (TREE_TYPE (TREE_TYPE (TREE_VALUE (arg))), + TREE_TYPE (parmtype), ba_ignore, NULL); + t = build_base_path (PLUS_EXPR, TREE_VALUE (arg), t, 1); converted_args = tree_cons (NULL_TREE, t, converted_args); parm = TREE_CHAIN (parm); arg = TREE_CHAIN (arg); @@ -4307,9 +4312,12 @@ build_over_call (cand, args, flags) if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0) { tree t, *p = &TREE_VALUE (converted_args); - tree binfo = get_binfo - (DECL_VIRTUAL_CONTEXT (fn), TREE_TYPE (TREE_TYPE (*p)), 0); - *p = convert_pointer_to_real (binfo, *p); + tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (*p)), + DECL_VIRTUAL_CONTEXT (fn), + ba_any, NULL); + my_friendly_assert (binfo && binfo != error_mark_node, 20010730); + + *p = build_base_path (PLUS_EXPR, *p, binfo, 1); if (TREE_SIDE_EFFECTS (*p)) *p = save_expr (*p); t = build_pointer_type (TREE_TYPE (fn)); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 68ab3a3..3afaf5d 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -106,7 +106,6 @@ varray_type local_classes; static tree get_vfield_name PARAMS ((tree)); static void finish_struct_anon PARAMS ((tree)); -static tree build_vbase_pointer PARAMS ((tree, tree)); static tree build_vtable_entry PARAMS ((tree, tree, tree)); static tree get_vtable_name PARAMS ((tree)); static tree get_basefndecls PARAMS ((tree, tree)); @@ -236,190 +235,122 @@ int n_build_method_call = 0; int n_inner_fields_searched = 0; #endif -/* Virtual base class layout. */ - -/* Returns a pointer to the virtual base class of EXP that has the - indicated TYPE. EXP is of class type, not a pointer type. */ - -static tree -build_vbase_pointer (exp, type) - tree exp, type; -{ - tree vbase; - tree vbase_ptr; - - /* Find the shared copy of TYPE; that's where the vtable offset is - recorded. */ - vbase = binfo_for_vbase (type, TREE_TYPE (exp)); - /* Find the virtual function table pointer. */ - vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp)); - /* Compute the location where the offset will lie. */ - vbase_ptr = build (PLUS_EXPR, - TREE_TYPE (vbase_ptr), - vbase_ptr, - BINFO_VPTR_FIELD (vbase)); - vbase_ptr = build1 (NOP_EXPR, - build_pointer_type (ptrdiff_type_node), - vbase_ptr); - /* Add the contents of this location to EXP. */ - return build (PLUS_EXPR, - build_pointer_type (type), - build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0), - build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr)); -} - -/* Build multi-level access to EXPR using hierarchy path PATH. - CODE is PLUS_EXPR if we are going with the grain, - and MINUS_EXPR if we are not (in which case, we cannot traverse - virtual baseclass links). - - TYPE is the type we want this path to have on exit. - - NONNULL is non-zero if we know (for any reason) that EXPR is - not, in fact, zero. */ +/* Convert to or from a base subobject. EXPR is an expression of type + `A' or `A*', an expression of type `B' or `B*' is returned. To + convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for + the B base instance within A. To convert base A to derived B, CODE + is MINUS_EXPR and BINFO is the binfo for the A instance within B. + In this latter case, A must not be a morally virtual base of B. + NONNULL is true if EXPR is known to be non-NULL (this is only + needed when EXPR is of pointer type). CV qualifiers are preserved + from EXPR. */ tree -build_vbase_path (code, type, expr, path, nonnull) +build_base_path (code, expr, binfo, nonnull) enum tree_code code; - tree type, expr, path; + tree expr; + tree binfo; int nonnull; { - register int changed = 0; - tree last = NULL_TREE, last_virtual = NULL_TREE; + tree v_binfo = NULL_TREE; + tree t; + tree probe; + tree offset; + tree target_type; + tree null_test = NULL; + tree ptr_target_type; int fixed_type_p; - tree null_expr = 0, nonnull_expr; - tree basetype; - tree offset = integer_zero_node; + int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE; - if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE) - return build1 (NOP_EXPR, type, expr); + if (expr == error_mark_node || binfo == error_mark_node || !binfo) + return error_mark_node; + + for (probe = binfo; probe; + t = probe, probe = BINFO_INHERITANCE_CHAIN (probe)) + if (!v_binfo && TREE_VIA_VIRTUAL (probe)) + v_binfo = probe; + + probe = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); + if (want_pointer) + probe = TYPE_MAIN_VARIANT (TREE_TYPE (probe)); + + my_friendly_assert (code == MINUS_EXPR + ? same_type_p (BINFO_TYPE (binfo), probe) + : code == PLUS_EXPR + ? same_type_p (BINFO_TYPE (t), probe) + : false, 20010723); + + if (code == MINUS_EXPR && v_binfo) + { + cp_error ("cannot convert from base `%T' to derived type `%T' via virtual base `%T'", + BINFO_TYPE (binfo), BINFO_TYPE (t), BINFO_TYPE (v_binfo)); + return error_mark_node; + } - /* We could do better if we had additional logic to convert back to the - unconverted type (the static type of the complete object), and then - convert back to the type we want. Until that is done, we only optimize - if the complete type is the same type as expr has. */ fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); if (fixed_type_p < 0) /* Virtual base layout is not fixed, even in ctors and dtors. */ fixed_type_p = 0; - if (!fixed_type_p && TREE_SIDE_EFFECTS (expr)) expr = save_expr (expr); - nonnull_expr = expr; - - path = reverse_path (path); - - basetype = BINFO_TYPE (path); - - while (path) + + if (!want_pointer) + expr = build_unary_op (ADDR_EXPR, expr, 0); + else if (!nonnull) + null_test = build (EQ_EXPR, boolean_type_node, expr, integer_zero_node); + + offset = BINFO_OFFSET (binfo); + + if (v_binfo && !fixed_type_p) { - if (TREE_VIA_VIRTUAL (TREE_VALUE (path))) - { - last_virtual = BINFO_TYPE (TREE_VALUE (path)); - if (code == PLUS_EXPR) - { - changed = ! fixed_type_p; - - if (changed) - { - tree ind; - - /* We already check for ambiguous things in the caller, just - find a path. */ - if (last) - { - tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0); - nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr); - } - ind = build_indirect_ref (nonnull_expr, NULL); - nonnull_expr = build_vbase_pointer (ind, last_virtual); - if (nonnull == 0 - && TREE_CODE (type) == POINTER_TYPE - && null_expr == NULL_TREE) - { - null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node); - expr = build (COND_EXPR, build_pointer_type (last_virtual), - build (EQ_EXPR, boolean_type_node, expr, - integer_zero_node), - null_expr, nonnull_expr); - } - } - /* else we'll figure out the offset below. */ - - /* Happens in the case of parse errors. */ - if (nonnull_expr == error_mark_node) - return error_mark_node; - } - else - { - cp_error ("cannot cast up from virtual baseclass `%T'", - last_virtual); - return error_mark_node; - } - } - last = TREE_VALUE (path); - path = TREE_CHAIN (path); - } - /* LAST is now the last basetype assoc on the path. */ + /* Going via virtual base V_BINFO. We need the static offset + from V_BINFO to BINFO, and the dynamic offset from T to + V_BINFO. That offset is an entry in T's vtable. */ + tree v_offset = build_vfield_ref (build_indirect_ref (expr, NULL), + TREE_TYPE (TREE_TYPE (expr))); + + v_binfo = binfo_for_vbase (BINFO_TYPE (v_binfo), BINFO_TYPE (t)); + + v_offset = build (PLUS_EXPR, TREE_TYPE (v_offset), + v_offset, BINFO_VPTR_FIELD (v_binfo)); + v_offset = build1 (NOP_EXPR, + build_pointer_type (ptrdiff_type_node), + v_offset); + v_offset = build_indirect_ref (v_offset, NULL); + + offset = cp_convert (ptrdiff_type_node, + size_diffop (offset, BINFO_OFFSET (v_binfo))); - /* A pointer to a virtual base member of a non-null object - is non-null. Therefore, we only need to test for zeroness once. - Make EXPR the canonical expression to deal with here. */ - if (null_expr) - { - TREE_OPERAND (expr, 2) = nonnull_expr; - TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1)) - = TREE_TYPE (nonnull_expr); + if (!integer_zerop (offset)) + offset = build (code, ptrdiff_type_node, v_offset, offset); + else + offset = v_offset; } - else - expr = nonnull_expr; - /* If we go through any virtual base pointers, make sure that - casts to BASETYPE from the last virtual base class use - the right value for BASETYPE. */ - if (changed) - { - tree intype = TREE_TYPE (TREE_TYPE (expr)); + target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (t); + + target_type = cp_build_qualified_type + (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr)))); + ptr_target_type = build_pointer_type (target_type); + if (want_pointer) + target_type = ptr_target_type; + + expr = build1 (NOP_EXPR, ptr_target_type, expr); - if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last)) - offset - = BINFO_OFFSET (get_binfo (last, TYPE_MAIN_VARIANT (intype), 0)); - } + if (!integer_zerop (offset)) + expr = build (code, ptr_target_type, expr, offset); else - offset = BINFO_OFFSET (last); - - if (! integer_zerop (offset)) - { - /* Bash types to make the backend happy. */ - offset = cp_convert (type, offset); - - /* If expr might be 0, we need to preserve that zeroness. */ - if (nonnull == 0) - { - if (null_expr) - TREE_TYPE (null_expr) = type; - else - null_expr = build1 (NOP_EXPR, type, integer_zero_node); - if (TREE_SIDE_EFFECTS (expr)) - expr = save_expr (expr); - - return build (COND_EXPR, type, - build (EQ_EXPR, boolean_type_node, expr, integer_zero_node), - null_expr, - build (code, type, expr, offset)); - } - else return build (code, type, expr, offset); - } + null_test = NULL; + + if (!want_pointer) + expr = build_indirect_ref (expr, NULL); - /* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may - be used multiple times in initialization of multiple inheritance. */ - if (null_expr) - { - TREE_TYPE (expr) = type; - return expr; - } - else - return build1 (NOP_EXPR, type, expr); + if (null_test) + expr = build (COND_EXPR, target_type, null_test, + build1 (NOP_EXPR, target_type, integer_zero_node), + expr); + + return expr; } @@ -5468,11 +5399,12 @@ fixed_type_or_null (instance, nonnull, cdtorp) } } -/* Return non-zero if the dynamic type of INSTANCE is known, and equivalent - to the static type. We also handle the case where INSTANCE is really - a pointer. Return negative if this is a ctor/dtor. There the dynamic type - is known, but this might not be the most derived base of the original object, - and hence virtual bases may not be layed out according to this type. +/* Return non-zero if the dynamic type of INSTANCE is known, and + equivalent to the static type. We also handle the case where + INSTANCE is really a pointer. Return negative if this is a + ctor/dtor. There the dynamic type is known, but this might not be + the most derived base of the original object, and hence virtual + bases may not be layed out according to this type. Used to determine whether the virtual function table is needed or not. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4b39e80..f82e4fe 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3018,6 +3018,29 @@ typedef enum instantiate_type_flags { itf_ptrmem_ok = 1 << 2, /* pointers to member ok (internal use) */ } instantiate_type_flags; +/* The kind of checking we can do looking in a class heirarchy. */ +typedef enum base_access { + ba_any = -2, /* Do not check access, allow an ambiguous base, + prefer a non-virtual base */ + ba_ignore = -1, /* Do not check access */ + ba_check = 0, /* Check access */ + ba_not_special /* Do not consider special privilege + current_class_type might give. */ +} base_access; + +/* The kind of base we can find, looking in a class heirarchy. + values <0 indicate we failed. */ +typedef enum base_kind { + bk_inaccessible = -3, /* The base is inaccessible */ + bk_ambig = -2, /* The base is ambiguous */ + bk_not_base = -1, /* It is not a base */ + bk_same_type = 0, /* It is the same type */ + bk_proper_base = 1, /* It is a proper base */ + bk_via_virtual = 2 /* It is a proper base, but via a virtual + path. This might not be the canonical + binfo. */ +} base_kind; + /* Nonzero means allow Microsoft extensions without a pedwarn. */ extern int flag_ms_extensions; @@ -3508,6 +3531,7 @@ extern tree strip_top_quals PARAMS ((tree)); extern tree perform_implicit_conversion PARAMS ((tree, tree)); /* in class.c */ +extern tree build_base_path PARAMS ((enum tree_code, tree, tree, int)); extern tree build_vbase_path PARAMS ((enum tree_code, tree, tree, tree, int)); extern tree build_vtbl_ref PARAMS ((tree, tree)); extern tree build_vfn_ref PARAMS ((tree, tree)); @@ -3554,8 +3578,6 @@ extern tree get_primary_binfo PARAMS ((tree)); extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree)); extern tree convert_from_reference PARAMS ((tree)); extern tree convert_lvalue PARAMS ((tree, tree)); -extern tree convert_pointer_to_real PARAMS ((tree, tree)); -extern tree convert_pointer_to PARAMS ((tree, tree)); extern tree ocp_convert PARAMS ((tree, tree, int, int)); extern tree cp_convert PARAMS ((tree, tree)); extern tree convert_to_void PARAMS ((tree, const char */*implicit context*/)); @@ -3980,6 +4002,7 @@ extern int tinfo_decl_p PARAMS((tree, void *)); extern int emit_tinfo_decl PARAMS((tree *, void *)); /* in search.c */ +extern tree lookup_base PARAMS ((tree, tree, base_access, base_kind *)); extern int types_overlap_p PARAMS ((tree, tree)); extern tree get_vbase PARAMS ((tree, tree)); extern tree get_binfo PARAMS ((tree, tree, int)); @@ -4030,7 +4053,6 @@ extern tree dfs_marked_real_bases_queue_p PARAMS ((tree, void *)); extern tree dfs_skip_vbases PARAMS ((tree, void *)); extern tree marked_vtable_pathp PARAMS ((tree, void *)); extern tree unmarked_vtable_pathp PARAMS ((tree, void *)); -extern tree convert_pointer_to_vbase PARAMS ((tree, tree)); extern tree find_vbase_instance PARAMS ((tree, tree)); extern tree binfo_for_vbase PARAMS ((tree, tree)); extern tree binfo_via_virtual PARAMS ((tree, tree)); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 3ab60b6..e2b9f39 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -141,44 +141,35 @@ cp_convert_to_pointer (type, expr, force) && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) - && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE - /* If EXPR is NULL, then we don't need to do any arithmetic - to convert it: - - [conv.ptr] - - The null pointer value is converted to the null pointer - value of the destination type. */ - && !integer_zerop (expr)) + && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; - tree binfo = get_binfo (TREE_TYPE (type), TREE_TYPE (intype), 1); - if (binfo == error_mark_node) - return error_mark_node; - if (binfo == NULL_TREE) + tree binfo; + + /* Try derived to base conversion. */ + binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type), + ba_check, NULL); + if (!binfo) { - binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 1); - if (binfo == error_mark_node) - return error_mark_node; + /* Try base to derived conversion. */ + binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), + ba_check, NULL); code = MINUS_EXPR; } + if (binfo == error_mark_node) + return error_mark_node; if (binfo) { - if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type)) - || TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype)) - || ! BINFO_OFFSET_ZEROP (binfo)) + expr = build_base_path (code, expr, binfo, 0); + /* Add any qualifier conversions. */ + if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)), + TREE_TYPE (type))) { - /* Need to get the path we took. */ - tree path; - - if (code == PLUS_EXPR) - get_base_distance (TREE_TYPE (type), TREE_TYPE (intype), - 0, &path); - else - get_base_distance (TREE_TYPE (intype), TREE_TYPE (type), - 0, &path); - return build_vbase_path (code, type, expr, path, 0); + expr = build1 (NOP_EXPR, type, expr); + TREE_CONSTANT (expr) = + TREE_CONSTANT (TREE_OPERAND (expr, 0)); } + return expr; } } @@ -187,36 +178,29 @@ cp_convert_to_pointer (type, expr, force) tree b1; tree b2; tree binfo; - tree virt_binfo; - enum tree_code code; + enum tree_code code = PLUS_EXPR; + base_kind bk; b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type)); b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)); - binfo = get_binfo (b2, b1, 1); - - if (binfo == NULL_TREE) + binfo = lookup_base (b1, b2, ba_check, &bk); + if (!binfo) { - binfo = get_binfo (b1, b2, 1); + binfo = lookup_base (b2, b1, ba_check, &bk); code = MINUS_EXPR; } - else - code = PLUS_EXPR; - if (binfo == error_mark_node) return error_mark_node; - virt_binfo = binfo_from_vbase (binfo); - if (virt_binfo) + if (bk == bk_via_virtual) { if (force) - cp_warning ("pointer to member cast via virtual base `%T' of `%T'", - BINFO_TYPE (virt_binfo), - BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo))); + cp_warning ("pointer to member cast from `%T' to `%T' is via virtual base", + TREE_TYPE (intype), TREE_TYPE (type)); else { - cp_error ("pointer to member cast via virtual base `%T' of `%T'", - BINFO_TYPE (virt_binfo), - BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo))); + cp_error ("pointer to member cast from `%T' to `%T' is via virtual base", + TREE_TYPE (intype), TREE_TYPE (type)); return error_mark_node; } /* This is a reinterpret cast, whose result is unspecified. @@ -319,34 +303,32 @@ convert_to_pointer_force (type, expr) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; - tree path; - int distance = get_base_distance (TREE_TYPE (type), - TREE_TYPE (intype), 0, &path); - if (distance == -2) + tree binfo; + + binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type), + ba_ignore, NULL); + if (!binfo) { - cp_error ("type `%T' is ambiguous base of `%T'", - TREE_TYPE (type), - TREE_TYPE (intype)); - return error_mark_node; + binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), + ba_ignore, NULL); + code = MINUS_EXPR; } - if (distance == -1) + if (binfo == error_mark_node) + return error_mark_node; + if (binfo) { - distance = get_base_distance (TREE_TYPE (intype), - TREE_TYPE (type), 0, &path); - if (distance == -2) - { - cp_error ("type `%T' is ambiguous base of `%T'", - TREE_TYPE (intype), - TREE_TYPE (type)); - return error_mark_node; - } - if (distance < 0) - /* Doesn't need any special help from us. */ - return build1 (NOP_EXPR, type, expr); - - code = MINUS_EXPR; + expr = build_base_path (code, expr, binfo, 0); + /* Add any qualifier conversions. */ + if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)), + TREE_TYPE (type))) + { + expr = build1 (NOP_EXPR, type, expr); + TREE_CONSTANT (expr) = + TREE_CONSTANT (TREE_OPERAND (expr, 0)); + } + return expr; } - return build_vbase_path (code, type, expr, path, 0); + } } @@ -420,12 +402,12 @@ build_up_reference (type, arg, flags, decl) && IS_AGGR_TYPE (target_type)) { /* We go through get_binfo for the access control. */ - tree binfo = get_binfo (target_type, argtype, 1); + tree binfo = lookup_base (argtype, target_type, ba_check, NULL); if (binfo == error_mark_node) return error_mark_node; if (binfo == NULL_TREE) return error_not_base_type (target_type, argtype); - rval = convert_pointer_to_real (binfo, rval); + rval = build_base_path (PLUS_EXPR, rval, binfo, 1); } else rval @@ -626,87 +608,6 @@ convert_lvalue (totype, expr) return convert_from_reference (expr); } -/* Call this when we know (for any reason) that expr is not, in fact, - zero. This routine is like convert_pointer_to, but it pays - attention to which specific instance of what type we want to - convert to. This routine should eventually become - convert_to_pointer after all references to convert_to_pointer - are removed. */ - -tree -convert_pointer_to_real (binfo, expr) - tree binfo, expr; -{ - register tree intype = TREE_TYPE (expr); - tree ptr_type; - tree type, rval; - - if (intype == error_mark_node) - return error_mark_node; - - if (TREE_CODE (binfo) == TREE_VEC) - type = BINFO_TYPE (binfo); - else if (IS_AGGR_TYPE (binfo)) - { - type = binfo; - } - else - { - type = binfo; - binfo = NULL_TREE; - } - - ptr_type = cp_build_qualified_type (type, - cp_type_quals (TREE_TYPE (intype))); - ptr_type = build_pointer_type (ptr_type); - if (same_type_p (ptr_type, TYPE_MAIN_VARIANT (intype))) - return expr; - - my_friendly_assert (!integer_zerop (expr), 191); - - intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype)); - if (TREE_CODE (type) == RECORD_TYPE - && TREE_CODE (intype) == RECORD_TYPE - && type != intype) - { - tree path; - int distance - = get_base_distance (binfo, intype, 0, &path); - - /* This function shouldn't be called with unqualified arguments - but if it is, give them an error message that they can read. */ - if (distance < 0) - { - cp_error ("cannot convert a pointer of type `%T' to a pointer of type `%T'", - intype, type); - - if (distance == -2) - cp_error ("because `%T' is an ambiguous base class", type); - return error_mark_node; - } - - return build_vbase_path (PLUS_EXPR, ptr_type, expr, path, 1); - } - rval = build1 (NOP_EXPR, ptr_type, - TREE_CODE (expr) == NOP_EXPR ? TREE_OPERAND (expr, 0) : expr); - TREE_CONSTANT (rval) = TREE_CONSTANT (expr); - return rval; -} - -/* Call this when we know (for any reason) that expr is - not, in fact, zero. This routine gets a type out of the first - argument and uses it to search for the type to convert to. If there - is more than one instance of that type in the expr, the conversion is - ambiguous. This routine should eventually go away, and all - callers should use convert_to_pointer_real. */ - -tree -convert_pointer_to (binfo, expr) - tree binfo, expr; -{ - return convert_pointer_to_real (binfo, expr); -} - /* C++ conversions, preference to static cast conversions. */ tree diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ffbe822..75ba05a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -130,7 +130,9 @@ finish_init_stmts (stmt_expr, compound_stmt) /* Constructors */ -/* Called from initialize_vtbl_ptrs via dfs_walk. */ +/* Called from initialize_vtbl_ptrs via dfs_walk. BINFO is the base + which we want to initialize the vtable pointer for, DATA is + TREE_LIST whose TREE_VALUE is the this ptr expression. */ static tree dfs_initialize_vtbl_ptrs (binfo, data) @@ -142,16 +144,7 @@ dfs_initialize_vtbl_ptrs (binfo, data) { tree base_ptr = TREE_VALUE ((tree) data); - if (TREE_VIA_VIRTUAL (binfo)) - base_ptr = convert_pointer_to_vbase (BINFO_TYPE (binfo), - base_ptr); - else - base_ptr - = build_vbase_path (PLUS_EXPR, - build_pointer_type (BINFO_TYPE (binfo)), - base_ptr, - binfo, - /*nonnull=*/1); + base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1); expand_virtual_init (binfo, base_ptr); } @@ -711,7 +704,8 @@ emit_base_init (mem_init_list, base_init_list) if (init != void_list_node) { - member = convert_pointer_to_real (base_binfo, current_class_ptr); + member = build_base_path (PLUS_EXPR, current_class_ptr, + base_binfo, 1); expand_aggr_init_1 (base_binfo, NULL_TREE, build_indirect_ref (member, NULL), init, LOOKUP_NORMAL); @@ -802,15 +796,9 @@ static void expand_virtual_init (binfo, decl) tree binfo, decl; { - tree type = BINFO_TYPE (binfo); tree vtbl, vtbl_ptr; - tree vtype, vtype_binfo; tree vtt_index; - /* Compute the location of the vtable. */ - vtype = DECL_CONTEXT (TYPE_VFIELD (type)); - vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); - /* Compute the initializer for vptr. */ vtbl = build_vtbl_address (binfo); @@ -842,10 +830,9 @@ expand_virtual_init (binfo, decl) } /* Compute the location of the vtpr. */ - decl = convert_pointer_to_real (vtype_binfo, decl); - vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL), vtype); - if (vtbl_ptr == error_mark_node) - return; + vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL), + TREE_TYPE (binfo)); + my_friendly_assert (vtbl_ptr != error_mark_node, 20010730); /* Assign the vtable to the vptr. */ vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); @@ -1842,14 +1829,14 @@ resolve_offset_ref (exp) if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE) base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type)); - addr = build_unary_op (ADDR_EXPR, base, 0); - addr = convert_pointer_to (basetype, addr); - - if (addr == error_mark_node) + basetype = lookup_base (TREE_TYPE (base), basetype, ba_check, NULL); + expr = build_base_path (PLUS_EXPR, base, basetype, 1); + + if (expr == error_mark_node) return error_mark_node; expr = build (COMPONENT_REF, TREE_TYPE (member), - build_indirect_ref (addr, NULL), member); + expr, member); return convert_from_reference (expr); } @@ -1872,7 +1859,10 @@ resolve_offset_ref (exp) } basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member))); - addr = convert_pointer_to (basetype, addr); + basetype = lookup_base (TREE_TYPE (TREE_TYPE (addr)), + basetype, ba_check, NULL); + addr = build_base_path (PLUS_EXPR, addr, basetype, 1); + member = cp_convert (ptrdiff_type_node, member); return build1 (INDIRECT_REF, type, diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index ae9600c..3510cc1 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -472,28 +472,15 @@ build_dynamic_cast_1 (type, expr) /* If *type is an unambiguous accessible base class of *exprtype, convert statically. */ { - int distance; - tree path; + tree binfo; - distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1, - &path); + binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type), + ba_not_special, NULL); - if (distance == -2) + if (binfo) { - cp_error ("dynamic_cast from `%T' to ambiguous base class `%T'", - TREE_TYPE (exprtype), TREE_TYPE (type)); - return error_mark_node; - } - if (distance == -3) - { - cp_error ("dynamic_cast from `%T' to private base class `%T'", - TREE_TYPE (exprtype), TREE_TYPE (type)); - return error_mark_node; - } - - if (distance >= 0) - { - expr = build_vbase_path (PLUS_EXPR, type, expr, path, 0); + expr = build_base_path (PLUS_EXPR, convert_from_reference (expr), + binfo, 0); if (TREE_CODE (exprtype) == POINTER_TYPE) expr = non_lvalue (expr); return expr; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index e09aa23..3bc6d9d 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -83,7 +83,6 @@ struct vbase_info tree inits; }; -static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *)); static tree lookup_field_1 PARAMS ((tree, tree)); static int is_subobject_of_p PARAMS ((tree, tree, tree)); static tree dfs_check_overlap PARAMS ((tree, void *)); @@ -91,6 +90,9 @@ static tree dfs_no_overlap_yet PARAMS ((tree, void *)); static int get_base_distance_recursive PARAMS ((tree, int, int, int, int *, tree *, tree, int, int *, int, int)); +static base_kind lookup_base_r + PARAMS ((tree, tree, base_access, + int, int, int, tree *)); static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *)); static tree marked_pushdecls_p PARAMS ((tree, void *)); static tree unmarked_pushdecls_p PARAMS ((tree, void *)); @@ -169,76 +171,6 @@ static int n_contexts_saved; #endif /* GATHER_STATISTICS */ -/* Get a virtual binfo that is found inside BINFO's hierarchy that is - the same type as the type given in PARENT. To be optimal, we want - the first one that is found by going through the least number of - virtual bases. - - This uses a clever algorithm that updates *depth when we find the vbase, - and cuts off other paths of search when they reach that depth. */ - -static tree -get_vbase_1 (parent, binfo, depth) - tree parent, binfo; - unsigned int *depth; -{ - tree binfos; - int i, n_baselinks; - tree rval = NULL_TREE; - int virtualp = TREE_VIA_VIRTUAL (binfo) != 0; - - *depth -= virtualp; - if (virtualp && BINFO_TYPE (binfo) == parent) - { - *depth = 0; - return binfo; - } - - binfos = BINFO_BASETYPES (binfo); - n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; - - /* Process base types. */ - for (i = 0; i < n_baselinks; i++) - { - tree base_binfo = TREE_VEC_ELT (binfos, i); - tree nrval; - - if (*depth == 0) - break; - - nrval = get_vbase_1 (parent, base_binfo, depth); - if (nrval) - rval = nrval; - } - *depth += virtualp; - return rval; -} - -/* Return the shortest path to vbase PARENT within BINFO, ignoring - access and ambiguity. */ - -tree -get_vbase (parent, binfo) - tree parent; - tree binfo; -{ - unsigned int d = (unsigned int)-1; - return get_vbase_1 (parent, binfo, &d); -} - -/* Convert EXPR to a virtual base class of type TYPE. We know that - EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that - the type of what expr points to has a virtual base of type TYPE. */ - -tree -convert_pointer_to_vbase (type, expr) - tree type; - tree expr; -{ - tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)))); - return convert_pointer_to_real (vb, expr); -} - /* Check whether the type given in BINFO is derived from PARENT. If it isn't, return 0. If it is, but the derivation is MI-ambiguous AND protect != 0, emit an error message and return error_mark_node. @@ -406,9 +338,6 @@ get_base_distance_recursive (binfo, depth, is_private, rval, If PROTECT is greater than 1, ignore any special access the current scope might have when determining whether PARENT is inaccessible. - PARENT can also be a binfo, in which case that exact parent is found - and no other. convert_pointer_to_real uses this functionality. - If BINFO is a binfo, its BINFO_INHERITANCE_CHAIN will be left alone. */ int @@ -473,6 +402,193 @@ get_base_distance (parent, binfo, protect, path_ptr) return rval; } +/* Worker for lookup_base. BINFO is the binfo we are searching at, + BASE is the RECORD_TYPE we are searching for. ACCESS is the + required access checks. WITHIN_CURRENT_SCOPE, IS_NON_PUBLIC and + IS_VIRTUAL indicate how BINFO was reached from the start of the + search. WITHIN_CURRENT_SCOPE is true if we met the current scope, + or friend thereof (this allows us to determine whether a protected + base is accessible or not). IS_NON_PUBLIC indicates whether BINFO + is accessible and IS_VIRTUAL indicates if it is morally virtual. + + If BINFO is of the required type, then *BINFO_PTR is examined to + compare with any other instance of BASE we might have already + discovered. *BINFO_PTR is initialized and a base_kind return value + indicates what kind of base was located. + + Otherwise BINFO's bases are searched. */ + +static base_kind +lookup_base_r (binfo, base, access, within_current_scope, + is_non_public, is_virtual, binfo_ptr) + tree binfo, base; + base_access access; + int within_current_scope; + int is_non_public; /* inside a non-public part */ + int is_virtual; /* inside a virtual part */ + tree *binfo_ptr; +{ + int i; + tree bases; + base_kind found = bk_not_base; + + if (access == ba_check + && !within_current_scope + && is_friend (BINFO_TYPE (binfo), current_scope ())) + { + within_current_scope = 1; + is_non_public = 0; + } + + if (same_type_p (BINFO_TYPE (binfo), base)) + { + /* We have found a base. Check against what we have found + already. */ + found = bk_same_type; + if (is_virtual) + found = bk_via_virtual; + if (is_non_public) + found = bk_inaccessible; + + if (!*binfo_ptr) + *binfo_ptr = binfo; + else if (!is_virtual || !tree_int_cst_equal (BINFO_OFFSET (binfo), + BINFO_OFFSET (*binfo_ptr))) + { + if (access != ba_any) + *binfo_ptr = NULL; + else if (found != is_virtual) + /* Prefer a non-virtual base. */ + *binfo_ptr = binfo; + found = bk_ambig; + } + else if (found == bk_via_virtual) + *binfo_ptr = binfo; + + return found; + } + + bases = BINFO_BASETYPES (binfo); + if (!bases) + return bk_not_base; + + for (i = TREE_VEC_LENGTH (bases); i--;) + { + tree base_binfo = TREE_VEC_ELT (bases, i); + int this_non_public = is_non_public; + int this_virtual = is_virtual; + + if (access <= ba_ignore) + ; /* no change */ + else if (TREE_VIA_PUBLIC (base_binfo)) + ; /* no change */ + else if (access == ba_not_special) + this_non_public = 1; + else if (TREE_VIA_PROTECTED (base_binfo) && within_current_scope) + ; /* no change */ + else if (is_friend (BINFO_TYPE (binfo), current_scope ())) + ; /* no change */ + else + this_non_public = 1; + + if (TREE_VIA_VIRTUAL (base_binfo)) + this_virtual = 1; + + base_kind bk = lookup_base_r (base_binfo, base, + access, within_current_scope, + this_non_public, this_virtual, + binfo_ptr); + + switch (bk) + { + case bk_ambig: + if (access != ba_any) + return bk; + found = bk; + break; + + case bk_inaccessible: + if (found == bk_not_base) + found = bk; + my_friendly_assert (found == bk_via_virtual + || found == bk_inaccessible, 20010723); + + break; + + case bk_same_type: + bk = bk_proper_base; + /* FALLTHROUGH */ + case bk_proper_base: + my_friendly_assert (found == bk_not_base, 20010723); + found = bk; + break; + + case bk_via_virtual: + my_friendly_assert (found == bk_not_base + || found == bk_via_virtual + || found == bk_inaccessible, 20010723); + found = bk; + break; + + case bk_not_base: + break; + } + } + return found; +} + +/* Lookup BASE in the hierarchy dominated by T. Do access checking as + ACCESS specifies. Return the binfo we discover (which might not be + canonical). If KIND_PTR is non-NULL, fill with information about + what kind of base we discoveded. + + Issue an error message if an inaccessible or ambiguous base is + discovered, and return error_mark_node. */ + +tree +lookup_base (t, base, access, kind_ptr) + tree t, base; + base_access access; + base_kind *kind_ptr; +{ + tree binfo = NULL; /* The binfo we've found so far. */ + base_kind bk; + + if (t == error_mark_node || base == error_mark_node) + { + if (kind_ptr) + *kind_ptr = bk_not_base; + return error_mark_node; + } + + t = TYPE_MAIN_VARIANT (t); + base = TYPE_MAIN_VARIANT (base); + + bk = lookup_base_r (TYPE_BINFO (t), base, access, 0, 0, 0, &binfo); + + switch (bk) + { + case bk_inaccessible: + cp_error ("`%T' is an inaccessible base of `%T'", base, t); + binfo = error_mark_node; + break; + case bk_ambig: + if (access != ba_any) + { + cp_error ("`%T' is an ambiguous base of `%T'", base, t); + binfo = error_mark_node; + } + break; + + default:; + } + + if (kind_ptr) + *kind_ptr = bk; + + return binfo; +} + /* Worker function for get_dynamic_cast_base_type. */ static int diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index c4c0e10..ddd4fc7 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -116,8 +116,11 @@ require_complete_type (value) { tree base, member = TREE_OPERAND (value, 1); tree basetype = TYPE_OFFSET_BASETYPE (type); + my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305); - base = convert_pointer_to (basetype, current_class_ptr); + basetype = lookup_base (current_class_type, basetype, ba_check, NULL); + base = build_base_path (PLUS_EXPR, current_class_ptr, basetype, 1); + value = build (COMPONENT_REF, TREE_TYPE (member), build_indirect_ref (base, NULL), member); return require_complete_type (value); @@ -2208,14 +2211,15 @@ build_component_ref (datum, component, basetype_path, protect) /* Handle base classes here... */ if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype)) { - tree addr = build_unary_op (ADDR_EXPR, datum, 0); - if (integer_zerop (addr)) + tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, NULL); + + if (TREE_CODE (datum) == INDIRECT_REF + && integer_zerop (TREE_OPERAND (datum, 0))) { error ("invalid reference to NULL ptr, use ptr-to-member instead"); return error_mark_node; } - addr = convert_pointer_to (base, addr); - datum = build_indirect_ref (addr, NULL); + datum = build_base_path (PLUS_EXPR, datum, binfo, 1); if (datum == error_mark_node) return error_mark_node; } @@ -2806,8 +2810,11 @@ build_x_function_call (function, params, decl) if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))) { + tree binfo = lookup_base (TREE_TYPE (decl), TREE_TYPE (ctypeptr), + ba_check, NULL); + decl = build_unary_op (ADDR_EXPR, decl, 0); - decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl); + decl = build_base_path (PLUS_EXPR, decl, binfo, 1); } else decl = build_c_cast (ctypeptr, decl); @@ -2826,9 +2833,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) tree function; { if (TREE_CODE (function) == OFFSET_REF) - { - function = TREE_OPERAND (function, 1); - } + function = TREE_OPERAND (function, 1); if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) { @@ -2857,14 +2862,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)); basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)); - /* Convert down to the right base, before using the instance. */ - instance = convert_pointer_to_real (basetype, instance_ptr); + /* Convert down to the right base, before using the instance. */ + instance = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)), basetype, + ba_check, NULL); + instance = build_base_path (PLUS_EXPR, instance_ptr, instance, 1); if (instance == error_mark_node && instance_ptr != error_mark_node) return instance; e3 = PFN_FROM_PTRMEMFUNC (function); - - vtbl = convert_pointer_to (ptr_type_node, instance); + + vtbl = build1 (NOP_EXPR, build_pointer_type (ptr_type_node), instance); + TREE_CONSTANT (vtbl) = TREE_CONSTANT (instance); + delta = cp_convert (ptrdiff_type_node, build_component_ref (function, delta_identifier, NULL_TREE, 0)); @@ -4229,8 +4238,11 @@ build_component_addr (arg, argtype) /* Can't convert directly to ARGTYPE, since that may have the same pointer type as one of our baseclasses. */ - rval = build1 (NOP_EXPR, argtype, - convert_pointer_to (basetype, rval)); + tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)), basetype, + ba_check, NULL); + + rval = build_base_path (PLUS_EXPR, rval, binfo, 1); + rval = build1 (NOP_EXPR, argtype, rval); TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0)); } else diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 8281b34..39e0479 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -997,12 +997,17 @@ build_scoped_ref (datum, basetype) tree basetype; { tree ref; + tree binfo; if (datum == error_mark_node) return error_mark_node; + binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, NULL); + if (!binfo) + return error_not_base_type (TREE_TYPE (datum), basetype); + ref = build_unary_op (ADDR_EXPR, datum, 0); - ref = convert_pointer_to (basetype, ref); + ref = build_base_path (PLUS_EXPR, ref, binfo, 1); return build_indirect_ref (ref, "(compiler error in build_scoped_ref)"); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 885d091..c1a7fde 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-11-25 Nathan Sidwell <nathan@codesourcery.com> + + * g++.dg/abi/vbase8-4.C: New test. + 2001-11-24 Ian Lance Taylor <ian@airs.com> * gcc.c-torture/execute/20011121-1.c: New test. diff --git a/gcc/testsuite/g++.dg/abi/vbase8-4.C b/gcc/testsuite/g++.dg/abi/vbase8-4.C new file mode 100644 index 0000000..2e816f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/vbase8-4.C @@ -0,0 +1,78 @@ +// { dg-options -w } +// { dg-do run } + +// Copyright (C) 2001 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 20 Nov 2001 <nathan@codesourcery.com> + +// Origin stefan@space.twc.de +// Bug 3145 case 4. Horribly complicated class hierarchy + +class C0 +{}; +class C1 + : virtual public C0 +{}; +class C2 + : public C0 + , public C1 +{}; +class C3 + : virtual public C0 + , public C1 + , public C2 +{}; +class C4 + : public C2 + , public C3 + , virtual public C1 + , virtual public C0 +{}; +class C5 + : virtual public C2 + , public C1 + , public C0 +{}; +class C6 + : virtual public C0 + , virtual public C5 + , public C1 + , public C3 + , public C4 +{}; +class C7 + : public C6 + , virtual public C0 + , public C1 + , public C2 + , virtual public C4 +{}; +class C8 + : public C2 + , virtual public C6 + , virtual public C7 + , public C5 + , public C3 + , virtual public C4 +{}; +class C9 + : public C5 + , virtual public C3 + , virtual public C8 + , public C0 + , public C2 + , public C7 + , public C6 + , public C4 +{}; +main() { + C0 c0; + C1 c1; + C2 c2; + C3 c3; + C4 c4; + C5 c5; + C6 c6; + C7 c7; + C8 c8; + C9 c9; +} |