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>
* cp-tree.h (CP_TYPE_QUALS): Removed.
......
......@@ -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));
......
......@@ -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));
......
......@@ -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
......
......@@ -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,
......
......@@ -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;
......
......@@ -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
......
......@@ -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
......
......@@ -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)");
}
......
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.
......
// { 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