Commit 338d90b8 by Nathan Sidwell Committed by Nathan Sidwell

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
parent 92fa4733
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> 2001-11-22 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* cp-tree.h (CP_TYPE_QUALS): Removed. * cp-tree.h (CP_TYPE_QUALS): Removed.
......
...@@ -298,7 +298,7 @@ build_scoped_method_call (exp, basetype, name, parms) ...@@ -298,7 +298,7 @@ build_scoped_method_call (exp, basetype, name, parms)
if (! binfo) if (! binfo)
{ {
binfo = get_binfo (basetype, type, 1); binfo = lookup_base (type, basetype, ba_check, NULL);
if (binfo == error_mark_node) if (binfo == error_mark_node)
return error_mark_node; return error_mark_node;
if (! binfo) if (! binfo)
...@@ -308,9 +308,12 @@ build_scoped_method_call (exp, basetype, name, parms) ...@@ -308,9 +308,12 @@ build_scoped_method_call (exp, basetype, name, parms)
if (binfo) if (binfo)
{ {
if (TREE_CODE (exp) == INDIRECT_REF) if (TREE_CODE (exp) == INDIRECT_REF)
decl = build_indirect_ref {
(convert_pointer_to_real decl = build_base_path (PLUS_EXPR,
(binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL); build_unary_op (ADDR_EXPR, exp, 0),
binfo, 1);
decl = build_indirect_ref (decl, NULL);
}
else else
decl = build_scoped_ref (exp, basetype); decl = build_scoped_ref (exp, basetype);
...@@ -4157,7 +4160,9 @@ build_over_call (cand, args, flags) ...@@ -4157,7 +4160,9 @@ build_over_call (cand, args, flags)
So we can assume that anything passed as 'this' is non-null, and So we can assume that anything passed as 'this' is non-null, and
optimize accordingly. */ optimize accordingly. */
my_friendly_assert (TREE_CODE (parmtype) == POINTER_TYPE, 19990811); 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); converted_args = tree_cons (NULL_TREE, t, converted_args);
parm = TREE_CHAIN (parm); parm = TREE_CHAIN (parm);
arg = TREE_CHAIN (arg); arg = TREE_CHAIN (arg);
...@@ -4307,9 +4312,12 @@ build_over_call (cand, args, flags) ...@@ -4307,9 +4312,12 @@ build_over_call (cand, args, flags)
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0) if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
{ {
tree t, *p = &TREE_VALUE (converted_args); tree t, *p = &TREE_VALUE (converted_args);
tree binfo = get_binfo tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (*p)),
(DECL_VIRTUAL_CONTEXT (fn), TREE_TYPE (TREE_TYPE (*p)), 0); DECL_VIRTUAL_CONTEXT (fn),
*p = convert_pointer_to_real (binfo, *p); 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)) if (TREE_SIDE_EFFECTS (*p))
*p = save_expr (*p); *p = save_expr (*p);
t = build_pointer_type (TREE_TYPE (fn)); t = build_pointer_type (TREE_TYPE (fn));
......
...@@ -106,7 +106,6 @@ varray_type local_classes; ...@@ -106,7 +106,6 @@ varray_type local_classes;
static tree get_vfield_name PARAMS ((tree)); static tree get_vfield_name PARAMS ((tree));
static void finish_struct_anon 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 build_vtable_entry PARAMS ((tree, tree, tree));
static tree get_vtable_name PARAMS ((tree)); static tree get_vtable_name PARAMS ((tree));
static tree get_basefndecls PARAMS ((tree, tree)); static tree get_basefndecls PARAMS ((tree, tree));
...@@ -236,190 +235,122 @@ int n_build_method_call = 0; ...@@ -236,190 +235,122 @@ int n_build_method_call = 0;
int n_inner_fields_searched = 0; int n_inner_fields_searched = 0;
#endif #endif
/* Virtual base class layout. */ /* 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
/* Returns a pointer to the virtual base class of EXP that has the convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
indicated TYPE. EXP is of class type, not a pointer type. */ 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.
static tree In this latter case, A must not be a morally virtual base of B.
build_vbase_pointer (exp, type) NONNULL is true if EXPR is known to be non-NULL (this is only
tree exp, type; needed when EXPR is of pointer type). CV qualifiers are preserved
{ from EXPR. */
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. */
tree tree
build_vbase_path (code, type, expr, path, nonnull) build_base_path (code, expr, binfo, nonnull)
enum tree_code code; enum tree_code code;
tree type, expr, path; tree expr;
tree binfo;
int nonnull; int nonnull;
{ {
register int changed = 0; tree v_binfo = NULL_TREE;
tree last = NULL_TREE, last_virtual = NULL_TREE; tree t;
tree probe;
tree offset;
tree target_type;
tree null_test = NULL;
tree ptr_target_type;
int fixed_type_p; int fixed_type_p;
tree null_expr = 0, nonnull_expr; int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE;
tree basetype;
tree offset = integer_zero_node; 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;
if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE) probe = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
return build1 (NOP_EXPR, 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); fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
if (fixed_type_p < 0) if (fixed_type_p < 0)
/* Virtual base layout is not fixed, even in ctors and dtors. */ /* Virtual base layout is not fixed, even in ctors and dtors. */
fixed_type_p = 0; fixed_type_p = 0;
if (!fixed_type_p && TREE_SIDE_EFFECTS (expr)) if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr); expr = save_expr (expr);
nonnull_expr = expr;
path = reverse_path (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);
basetype = BINFO_TYPE (path); offset = BINFO_OFFSET (binfo);
while (path) if (v_binfo && !fixed_type_p)
{
if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
{ {
last_virtual = BINFO_TYPE (TREE_VALUE (path)); /* Going via virtual base V_BINFO. We need the static offset
if (code == PLUS_EXPR) from V_BINFO to BINFO, and the dynamic offset from T to
{ V_BINFO. That offset is an entry in T's vtable. */
changed = ! fixed_type_p; tree v_offset = build_vfield_ref (build_indirect_ref (expr, NULL),
TREE_TYPE (TREE_TYPE (expr)));
if (changed) v_binfo = binfo_for_vbase (BINFO_TYPE (v_binfo), BINFO_TYPE (t));
{
tree ind;
/* We already check for ambiguous things in the caller, just v_offset = build (PLUS_EXPR, TREE_TYPE (v_offset),
find a path. */ v_offset, BINFO_VPTR_FIELD (v_binfo));
if (last) v_offset = build1 (NOP_EXPR,
{ build_pointer_type (ptrdiff_type_node),
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0); v_offset);
nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr); v_offset = build_indirect_ref (v_offset, NULL);
}
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. */ offset = cp_convert (ptrdiff_type_node,
if (nonnull_expr == error_mark_node) size_diffop (offset, BINFO_OFFSET (v_binfo)));
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. */
/* A pointer to a virtual base member of a non-null object if (!integer_zerop (offset))
is non-null. Therefore, we only need to test for zeroness once. offset = build (code, ptrdiff_type_node, v_offset, offset);
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);
}
else else
expr = nonnull_expr; offset = v_offset;
}
/* If we go through any virtual base pointers, make sure that target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (t);
casts to BASETYPE from the last virtual base class use
the right value for BASETYPE. */
if (changed)
{
tree intype = TREE_TYPE (TREE_TYPE (expr));
if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last)) target_type = cp_build_qualified_type
offset (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
= BINFO_OFFSET (get_binfo (last, TYPE_MAIN_VARIANT (intype), 0)); ptr_target_type = build_pointer_type (target_type);
} if (want_pointer)
else target_type = ptr_target_type;
offset = BINFO_OFFSET (last);
if (! integer_zerop (offset)) expr = build1 (NOP_EXPR, ptr_target_type, expr);
{
/* Bash types to make the backend happy. */
offset = cp_convert (type, offset);
/* If expr might be 0, we need to preserve that zeroness. */ if (!integer_zerop (offset))
if (nonnull == 0) expr = build (code, ptr_target_type, expr, offset);
{
if (null_expr)
TREE_TYPE (null_expr) = type;
else else
null_expr = build1 (NOP_EXPR, type, integer_zero_node); null_test = NULL;
if (TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
return build (COND_EXPR, type, if (!want_pointer)
build (EQ_EXPR, boolean_type_node, expr, integer_zero_node), expr = build_indirect_ref (expr, NULL);
null_expr,
build (code, type, expr, offset)); if (null_test)
} expr = build (COND_EXPR, target_type, null_test,
else return build (code, type, expr, offset); build1 (NOP_EXPR, target_type, integer_zero_node),
} expr);
/* 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; return expr;
}
else
return build1 (NOP_EXPR, type, expr);
} }
...@@ -5468,11 +5399,12 @@ fixed_type_or_null (instance, nonnull, cdtorp) ...@@ -5468,11 +5399,12 @@ fixed_type_or_null (instance, nonnull, cdtorp)
} }
} }
/* Return non-zero if the dynamic type of INSTANCE is known, and equivalent /* Return non-zero if the dynamic type of INSTANCE is known, and
to the static type. We also handle the case where INSTANCE is really equivalent to the static type. We also handle the case where
a pointer. Return negative if this is a ctor/dtor. There the dynamic type INSTANCE is really a pointer. Return negative if this is a
is known, but this might not be the most derived base of the original object, ctor/dtor. There the dynamic type is known, but this might not be
and hence virtual bases may not be layed out according to this type. 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 Used to determine whether the virtual function table is needed
or not. or not.
......
...@@ -3018,6 +3018,29 @@ typedef enum instantiate_type_flags { ...@@ -3018,6 +3018,29 @@ typedef enum instantiate_type_flags {
itf_ptrmem_ok = 1 << 2, /* pointers to member ok (internal use) */ itf_ptrmem_ok = 1 << 2, /* pointers to member ok (internal use) */
} instantiate_type_flags; } 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. */ /* Nonzero means allow Microsoft extensions without a pedwarn. */
extern int flag_ms_extensions; extern int flag_ms_extensions;
...@@ -3508,6 +3531,7 @@ extern tree strip_top_quals PARAMS ((tree)); ...@@ -3508,6 +3531,7 @@ extern tree strip_top_quals PARAMS ((tree));
extern tree perform_implicit_conversion PARAMS ((tree, tree)); extern tree perform_implicit_conversion PARAMS ((tree, tree));
/* in class.c */ /* 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_vbase_path PARAMS ((enum tree_code, tree, tree, tree, int));
extern tree build_vtbl_ref PARAMS ((tree, tree)); extern tree build_vtbl_ref PARAMS ((tree, tree));
extern tree build_vfn_ref PARAMS ((tree, tree)); extern tree build_vfn_ref PARAMS ((tree, tree));
...@@ -3554,8 +3578,6 @@ extern tree get_primary_binfo PARAMS ((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_to_reference PARAMS ((tree, tree, int, int, tree));
extern tree convert_from_reference PARAMS ((tree)); extern tree convert_from_reference PARAMS ((tree));
extern tree convert_lvalue PARAMS ((tree, 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 ocp_convert PARAMS ((tree, tree, int, int));
extern tree cp_convert PARAMS ((tree, tree)); extern tree cp_convert PARAMS ((tree, tree));
extern tree convert_to_void PARAMS ((tree, const char */*implicit context*/)); extern tree convert_to_void PARAMS ((tree, const char */*implicit context*/));
...@@ -3980,6 +4002,7 @@ extern int tinfo_decl_p PARAMS((tree, void *)); ...@@ -3980,6 +4002,7 @@ extern int tinfo_decl_p PARAMS((tree, void *));
extern int emit_tinfo_decl PARAMS((tree *, void *)); extern int emit_tinfo_decl PARAMS((tree *, void *));
/* in search.c */ /* in search.c */
extern tree lookup_base PARAMS ((tree, tree, base_access, base_kind *));
extern int types_overlap_p PARAMS ((tree, tree)); extern int types_overlap_p PARAMS ((tree, tree));
extern tree get_vbase PARAMS ((tree, tree)); extern tree get_vbase PARAMS ((tree, tree));
extern tree get_binfo PARAMS ((tree, tree, int)); extern tree get_binfo PARAMS ((tree, tree, int));
...@@ -4030,7 +4053,6 @@ extern tree dfs_marked_real_bases_queue_p PARAMS ((tree, void *)); ...@@ -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 dfs_skip_vbases PARAMS ((tree, void *));
extern tree marked_vtable_pathp PARAMS ((tree, void *)); extern tree marked_vtable_pathp PARAMS ((tree, void *));
extern tree unmarked_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 find_vbase_instance PARAMS ((tree, tree));
extern tree binfo_for_vbase PARAMS ((tree, tree)); extern tree binfo_for_vbase PARAMS ((tree, tree));
extern tree binfo_via_virtual PARAMS ((tree, tree)); extern tree binfo_via_virtual PARAMS ((tree, tree));
......
...@@ -141,44 +141,35 @@ cp_convert_to_pointer (type, expr, force) ...@@ -141,44 +141,35 @@ cp_convert_to_pointer (type, expr, force)
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
&& IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (type))
&& IS_AGGR_TYPE (TREE_TYPE (intype)) && IS_AGGR_TYPE (TREE_TYPE (intype))
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE && 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))
{ {
enum tree_code code = PLUS_EXPR; enum tree_code code = PLUS_EXPR;
tree binfo = get_binfo (TREE_TYPE (type), TREE_TYPE (intype), 1); tree binfo;
if (binfo == error_mark_node)
return error_mark_node; /* Try derived to base conversion. */
if (binfo == NULL_TREE) binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
ba_check, NULL);
if (!binfo)
{ {
binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 1); /* Try base to derived conversion. */
if (binfo == error_mark_node) binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
return error_mark_node; ba_check, NULL);
code = MINUS_EXPR; code = MINUS_EXPR;
} }
if (binfo == error_mark_node)
return error_mark_node;
if (binfo) if (binfo)
{ {
if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type)) expr = build_base_path (code, expr, binfo, 0);
|| TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype)) /* Add any qualifier conversions. */
|| ! BINFO_OFFSET_ZEROP (binfo)) if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)),
TREE_TYPE (type)))
{ {
/* Need to get the path we took. */ expr = build1 (NOP_EXPR, type, expr);
tree path; TREE_CONSTANT (expr) =
TREE_CONSTANT (TREE_OPERAND (expr, 0));
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);
} }
return expr;
} }
} }
...@@ -187,36 +178,29 @@ cp_convert_to_pointer (type, expr, force) ...@@ -187,36 +178,29 @@ cp_convert_to_pointer (type, expr, force)
tree b1; tree b1;
tree b2; tree b2;
tree binfo; tree binfo;
tree virt_binfo; enum tree_code code = PLUS_EXPR;
enum tree_code code; base_kind bk;
b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type)); b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)); b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
binfo = get_binfo (b2, b1, 1); binfo = lookup_base (b1, b2, ba_check, &bk);
if (!binfo)
if (binfo == NULL_TREE)
{ {
binfo = get_binfo (b1, b2, 1); binfo = lookup_base (b2, b1, ba_check, &bk);
code = MINUS_EXPR; code = MINUS_EXPR;
} }
else
code = PLUS_EXPR;
if (binfo == error_mark_node) if (binfo == error_mark_node)
return error_mark_node; return error_mark_node;
virt_binfo = binfo_from_vbase (binfo); if (bk == bk_via_virtual)
if (virt_binfo)
{ {
if (force) if (force)
cp_warning ("pointer to member cast via virtual base `%T' of `%T'", cp_warning ("pointer to member cast from `%T' to `%T' is via virtual base",
BINFO_TYPE (virt_binfo), TREE_TYPE (intype), TREE_TYPE (type));
BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
else else
{ {
cp_error ("pointer to member cast via virtual base `%T' of `%T'", cp_error ("pointer to member cast from `%T' to `%T' is via virtual base",
BINFO_TYPE (virt_binfo), TREE_TYPE (intype), TREE_TYPE (type));
BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
return error_mark_node; return error_mark_node;
} }
/* This is a reinterpret cast, whose result is unspecified. /* This is a reinterpret cast, whose result is unspecified.
...@@ -319,34 +303,32 @@ convert_to_pointer_force (type, expr) ...@@ -319,34 +303,32 @@ convert_to_pointer_force (type, expr)
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
{ {
enum tree_code code = PLUS_EXPR; enum tree_code code = PLUS_EXPR;
tree path; tree binfo;
int distance = get_base_distance (TREE_TYPE (type),
TREE_TYPE (intype), 0, &path); binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
if (distance == -2) ba_ignore, NULL);
{ if (!binfo)
cp_error ("type `%T' is ambiguous base of `%T'", {
TREE_TYPE (type), binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
TREE_TYPE (intype)); ba_ignore, NULL);
return error_mark_node; code = MINUS_EXPR;
} }
if (distance == -1) if (binfo == error_mark_node)
return error_mark_node;
if (binfo)
{ {
distance = get_base_distance (TREE_TYPE (intype), expr = build_base_path (code, expr, binfo, 0);
TREE_TYPE (type), 0, &path); /* Add any qualifier conversions. */
if (distance == -2) if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)),
TREE_TYPE (type)))
{ {
cp_error ("type `%T' is ambiguous base of `%T'", expr = build1 (NOP_EXPR, type, expr);
TREE_TYPE (intype), TREE_CONSTANT (expr) =
TREE_TYPE (type)); TREE_CONSTANT (TREE_OPERAND (expr, 0));
return error_mark_node;
} }
if (distance < 0) return expr;
/* Doesn't need any special help from us. */
return build1 (NOP_EXPR, type, expr);
code = MINUS_EXPR;
} }
return build_vbase_path (code, type, expr, path, 0);
} }
} }
...@@ -420,12 +402,12 @@ build_up_reference (type, arg, flags, decl) ...@@ -420,12 +402,12 @@ build_up_reference (type, arg, flags, decl)
&& IS_AGGR_TYPE (target_type)) && IS_AGGR_TYPE (target_type))
{ {
/* We go through get_binfo for the access control. */ /* 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) if (binfo == error_mark_node)
return error_mark_node; return error_mark_node;
if (binfo == NULL_TREE) if (binfo == NULL_TREE)
return error_not_base_type (target_type, argtype); 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 else
rval rval
...@@ -626,87 +608,6 @@ convert_lvalue (totype, expr) ...@@ -626,87 +608,6 @@ convert_lvalue (totype, expr)
return convert_from_reference (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. */ /* C++ conversions, preference to static cast conversions. */
tree tree
......
...@@ -130,7 +130,9 @@ finish_init_stmts (stmt_expr, compound_stmt) ...@@ -130,7 +130,9 @@ finish_init_stmts (stmt_expr, compound_stmt)
/* Constructors */ /* 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 static tree
dfs_initialize_vtbl_ptrs (binfo, data) dfs_initialize_vtbl_ptrs (binfo, data)
...@@ -142,16 +144,7 @@ dfs_initialize_vtbl_ptrs (binfo, data) ...@@ -142,16 +144,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
{ {
tree base_ptr = TREE_VALUE ((tree) data); tree base_ptr = TREE_VALUE ((tree) data);
if (TREE_VIA_VIRTUAL (binfo)) base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1);
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);
expand_virtual_init (binfo, base_ptr); expand_virtual_init (binfo, base_ptr);
} }
...@@ -711,7 +704,8 @@ emit_base_init (mem_init_list, base_init_list) ...@@ -711,7 +704,8 @@ emit_base_init (mem_init_list, base_init_list)
if (init != void_list_node) 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, expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL), init, build_indirect_ref (member, NULL), init,
LOOKUP_NORMAL); LOOKUP_NORMAL);
...@@ -802,15 +796,9 @@ static void ...@@ -802,15 +796,9 @@ static void
expand_virtual_init (binfo, decl) expand_virtual_init (binfo, decl)
tree binfo, decl; tree binfo, decl;
{ {
tree type = BINFO_TYPE (binfo);
tree vtbl, vtbl_ptr; tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo;
tree vtt_index; 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. */ /* Compute the initializer for vptr. */
vtbl = build_vtbl_address (binfo); vtbl = build_vtbl_address (binfo);
...@@ -842,10 +830,9 @@ expand_virtual_init (binfo, decl) ...@@ -842,10 +830,9 @@ expand_virtual_init (binfo, decl)
} }
/* Compute the location of the vtpr. */ /* Compute the location of the vtpr. */
decl = convert_pointer_to_real (vtype_binfo, decl); vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL),
vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL), vtype); TREE_TYPE (binfo));
if (vtbl_ptr == error_mark_node) my_friendly_assert (vtbl_ptr != error_mark_node, 20010730);
return;
/* Assign the vtable to the vptr. */ /* Assign the vtable to the vptr. */
vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
...@@ -1842,14 +1829,14 @@ resolve_offset_ref (exp) ...@@ -1842,14 +1829,14 @@ resolve_offset_ref (exp)
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE) if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type)); base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
addr = build_unary_op (ADDR_EXPR, base, 0); basetype = lookup_base (TREE_TYPE (base), basetype, ba_check, NULL);
addr = convert_pointer_to (basetype, addr); expr = build_base_path (PLUS_EXPR, base, basetype, 1);
if (addr == error_mark_node) if (expr == error_mark_node)
return error_mark_node; return error_mark_node;
expr = build (COMPONENT_REF, TREE_TYPE (member), expr = build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (addr, NULL), member); expr, member);
return convert_from_reference (expr); return convert_from_reference (expr);
} }
...@@ -1872,7 +1859,10 @@ resolve_offset_ref (exp) ...@@ -1872,7 +1859,10 @@ resolve_offset_ref (exp)
} }
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member))); 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); member = cp_convert (ptrdiff_type_node, member);
return build1 (INDIRECT_REF, type, return build1 (INDIRECT_REF, type,
......
...@@ -472,28 +472,15 @@ build_dynamic_cast_1 (type, expr) ...@@ -472,28 +472,15 @@ build_dynamic_cast_1 (type, expr)
/* If *type is an unambiguous accessible base class of *exprtype, /* If *type is an unambiguous accessible base class of *exprtype,
convert statically. */ convert statically. */
{ {
int distance; tree binfo;
tree path;
distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
&path);
if (distance == -2) binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type),
{ ba_not_special, NULL);
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) if (binfo)
{ {
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) if (TREE_CODE (exprtype) == POINTER_TYPE)
expr = non_lvalue (expr); expr = non_lvalue (expr);
return expr; return expr;
......
...@@ -83,7 +83,6 @@ struct vbase_info ...@@ -83,7 +83,6 @@ struct vbase_info
tree inits; tree inits;
}; };
static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
static tree lookup_field_1 PARAMS ((tree, tree)); static tree lookup_field_1 PARAMS ((tree, tree));
static int is_subobject_of_p PARAMS ((tree, tree, tree)); static int is_subobject_of_p PARAMS ((tree, tree, tree));
static tree dfs_check_overlap PARAMS ((tree, void *)); static tree dfs_check_overlap PARAMS ((tree, void *));
...@@ -91,6 +90,9 @@ static tree dfs_no_overlap_yet PARAMS ((tree, void *)); ...@@ -91,6 +90,9 @@ static tree dfs_no_overlap_yet PARAMS ((tree, void *));
static int get_base_distance_recursive static int get_base_distance_recursive
PARAMS ((tree, int, int, int, int *, tree *, tree, PARAMS ((tree, int, int, int, int *, tree *, tree,
int, int *, int, int)); 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 int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
static tree marked_pushdecls_p PARAMS ((tree, void *)); static tree marked_pushdecls_p PARAMS ((tree, void *));
static tree unmarked_pushdecls_p PARAMS ((tree, void *)); static tree unmarked_pushdecls_p PARAMS ((tree, void *));
...@@ -169,76 +171,6 @@ static int n_contexts_saved; ...@@ -169,76 +171,6 @@ static int n_contexts_saved;
#endif /* GATHER_STATISTICS */ #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 /* 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 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. 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, ...@@ -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 If PROTECT is greater than 1, ignore any special access the current
scope might have when determining whether PARENT is inaccessible. 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. */ If BINFO is a binfo, its BINFO_INHERITANCE_CHAIN will be left alone. */
int int
...@@ -473,6 +402,193 @@ get_base_distance (parent, binfo, protect, path_ptr) ...@@ -473,6 +402,193 @@ get_base_distance (parent, binfo, protect, path_ptr)
return rval; 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. */ /* Worker function for get_dynamic_cast_base_type. */
static int static int
......
...@@ -116,8 +116,11 @@ require_complete_type (value) ...@@ -116,8 +116,11 @@ require_complete_type (value)
{ {
tree base, member = TREE_OPERAND (value, 1); tree base, member = TREE_OPERAND (value, 1);
tree basetype = TYPE_OFFSET_BASETYPE (type); tree basetype = TYPE_OFFSET_BASETYPE (type);
my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305); 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), value = build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (base, NULL), member); build_indirect_ref (base, NULL), member);
return require_complete_type (value); return require_complete_type (value);
...@@ -2208,14 +2211,15 @@ build_component_ref (datum, component, basetype_path, protect) ...@@ -2208,14 +2211,15 @@ build_component_ref (datum, component, basetype_path, protect)
/* Handle base classes here... */ /* Handle base classes here... */
if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype)) if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
{ {
tree addr = build_unary_op (ADDR_EXPR, datum, 0); tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, NULL);
if (integer_zerop (addr))
if (TREE_CODE (datum) == INDIRECT_REF
&& integer_zerop (TREE_OPERAND (datum, 0)))
{ {
error ("invalid reference to NULL ptr, use ptr-to-member instead"); error ("invalid reference to NULL ptr, use ptr-to-member instead");
return error_mark_node; return error_mark_node;
} }
addr = convert_pointer_to (base, addr); datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
datum = build_indirect_ref (addr, NULL);
if (datum == error_mark_node) if (datum == error_mark_node)
return error_mark_node; return error_mark_node;
} }
...@@ -2806,8 +2810,11 @@ build_x_function_call (function, params, decl) ...@@ -2806,8 +2810,11 @@ build_x_function_call (function, params, decl)
if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))) && ! 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 = 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 else
decl = build_c_cast (ctypeptr, decl); decl = build_c_cast (ctypeptr, decl);
...@@ -2826,9 +2833,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) ...@@ -2826,9 +2833,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
tree function; tree function;
{ {
if (TREE_CODE (function) == OFFSET_REF) if (TREE_CODE (function) == OFFSET_REF)
{
function = TREE_OPERAND (function, 1); function = TREE_OPERAND (function, 1);
}
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
{ {
...@@ -2858,13 +2863,17 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) ...@@ -2858,13 +2863,17 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)); basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
/* Convert down to the right base, before using the instance. */ /* Convert down to the right base, before using the instance. */
instance = convert_pointer_to_real (basetype, instance_ptr); 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) if (instance == error_mark_node && instance_ptr != error_mark_node)
return instance; return instance;
e3 = PFN_FROM_PTRMEMFUNC (function); 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, delta = cp_convert (ptrdiff_type_node,
build_component_ref (function, delta_identifier, build_component_ref (function, delta_identifier,
NULL_TREE, 0)); NULL_TREE, 0));
...@@ -4229,8 +4238,11 @@ build_component_addr (arg, argtype) ...@@ -4229,8 +4238,11 @@ build_component_addr (arg, argtype)
/* Can't convert directly to ARGTYPE, since that /* Can't convert directly to ARGTYPE, since that
may have the same pointer type as one of our may have the same pointer type as one of our
baseclasses. */ baseclasses. */
rval = build1 (NOP_EXPR, argtype, tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)), basetype,
convert_pointer_to (basetype, rval)); 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)); TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
} }
else else
......
...@@ -997,12 +997,17 @@ build_scoped_ref (datum, basetype) ...@@ -997,12 +997,17 @@ build_scoped_ref (datum, basetype)
tree basetype; tree basetype;
{ {
tree ref; tree ref;
tree binfo;
if (datum == error_mark_node) if (datum == error_mark_node)
return 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 = 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)"); return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
} }
......
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> 2001-11-24 Ian Lance Taylor <ian@airs.com>
* gcc.c-torture/execute/20011121-1.c: New test. * gcc.c-torture/execute/20011121-1.c: New test.
......
// { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment