aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-11-25 13:21:45 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-11-25 13:21:45 +0000
commit338d90b89f23deaa5ce2ae80b8adf9cb52808679 (patch)
tree0d461fab9e84fd53ebc0b813e9c60b27eb83f6e0
parent92fa4733ab20d5f4a8e9eb7c6f5c924427677549 (diff)
downloadgcc-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/ChangeLog43
-rw-r--r--gcc/cp/call.c24
-rw-r--r--gcc/cp/class.c270
-rw-r--r--gcc/cp/cp-tree.h28
-rw-r--r--gcc/cp/cvt.c207
-rw-r--r--gcc/cp/init.c46
-rw-r--r--gcc/cp/rtti.c25
-rw-r--r--gcc/cp/search.c264
-rw-r--r--gcc/cp/typeck.c42
-rw-r--r--gcc/cp/typeck2.c7
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/abi/vbase8-4.C78
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;
+}