#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "obstack.h"
#include "flags.h"
#include "rtl.h"
#include "output.h"
#include "toplev.h"
#include "stack.h"
static struct obstack search_obstack;
struct stack_level *
push_stack_level (struct obstack *obstack, char *tp,
int size)
{
struct stack_level *stack;
obstack_grow (obstack, tp, size);
stack = (struct stack_level *) ((char*)obstack_next_free (obstack) - size);
obstack_finish (obstack);
stack->obstack = obstack;
stack->first = (tree *) obstack_base (obstack);
stack->limit = obstack_room (obstack) / sizeof (tree *);
return stack;
}
struct stack_level *
pop_stack_level (struct stack_level *stack)
{
struct stack_level *tem = stack;
struct obstack *obstack = tem->obstack;
stack = tem->prev;
obstack_free (obstack, tem);
return stack;
}
#define search_level stack_level
static struct search_level *search_stack;
struct vbase_info
{
tree type;
tree decl_ptr;
tree inits;
};
static tree dfs_check_overlap (tree, void *);
static tree dfs_no_overlap_yet (tree, int, void *);
static base_kind lookup_base_r (tree, tree, base_access, bool, tree *);
static int dynamic_cast_base_recurse (tree, tree, bool, tree *);
static tree marked_pushdecls_p (tree, int, void *);
static tree unmarked_pushdecls_p (tree, int, void *);
static tree dfs_debug_unmarkedp (tree, int, void *);
static tree dfs_debug_mark (tree, void *);
static tree dfs_push_type_decls (tree, void *);
static tree dfs_push_decls (tree, void *);
static tree dfs_unuse_fields (tree, void *);
static tree add_conversions (tree, void *);
static int look_for_overrides_r (tree, tree);
static struct search_level *push_search_level (struct stack_level *,
struct obstack *);
static struct search_level *pop_search_level (struct stack_level *);
static tree bfs_walk (tree, tree (*) (tree, void *),
tree (*) (tree, int, void *), void *);
static tree lookup_field_queue_p (tree, int, void *);
static int shared_member_p (tree);
static tree lookup_field_r (tree, void *);
static tree dfs_accessible_queue_p (tree, int, void *);
static tree dfs_accessible_p (tree, void *);
static tree dfs_access_in_type (tree, void *);
static access_kind access_in_type (tree, tree);
static int protected_accessible_p (tree, tree, tree);
static int friend_accessible_p (tree, tree, tree);
static void setup_class_bindings (tree, int);
static int template_self_reference_p (tree, tree);
static tree dfs_get_pure_virtuals (tree, void *);
static struct search_level *
push_search_level (struct stack_level *stack, struct obstack *obstack)
{
struct search_level tem;
tem.prev = stack;
return push_stack_level (obstack, (char *)&tem, sizeof (tem));
}
static struct search_level *
pop_search_level (struct stack_level *obstack)
{
struct search_level *stack = pop_stack_level (obstack);
return stack;
}
#ifdef GATHER_STATISTICS
static int n_fields_searched;
static int n_calls_lookup_field, n_calls_lookup_field_1;
static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1;
static int n_calls_get_base_type;
static int n_outer_fields_searched;
static int n_contexts_saved;
#endif
static base_kind
lookup_base_r (tree binfo, tree base, base_access access,
bool is_virtual,
tree *binfo_ptr)
{
int i;
tree bases, accesses;
base_kind found = bk_not_base;
if (same_type_p (BINFO_TYPE (binfo), base))
{
found = bk_same_type;
if (is_virtual)
found = bk_via_virtual;
if (!*binfo_ptr)
*binfo_ptr = binfo;
else if (binfo != *binfo_ptr)
{
if (access != ba_any)
*binfo_ptr = NULL;
else if (!is_virtual)
*binfo_ptr = binfo;
found = bk_ambig;
}
return found;
}
bases = BINFO_BASETYPES (binfo);
accesses = BINFO_BASEACCESSES (binfo);
if (!bases)
return bk_not_base;
for (i = TREE_VEC_LENGTH (bases); i--;)
{
tree base_binfo = TREE_VEC_ELT (bases, i);
base_kind bk;
bk = lookup_base_r (base_binfo, base,
access,
is_virtual || TREE_VIA_VIRTUAL (base_binfo),
binfo_ptr);
switch (bk)
{
case bk_ambig:
if (access != ba_any)
return bk;
found = bk;
break;
case bk_same_type:
bk = bk_proper_base;
case bk_proper_base:
my_friendly_assert (found == bk_not_base, 20010723);
found = bk;
break;
case bk_via_virtual:
if (found != bk_ambig)
found = bk;
break;
case bk_not_base:
break;
default:
abort ();
}
}
return found;
}
bool
accessible_base_p (tree t, tree base)
{
tree decl;
if (same_type_p (t, base))
return true;
decl = TYPE_FIELDS (base);
while (!DECL_SELF_REFERENCE_P (decl))
decl = TREE_CHAIN (decl);
while (ANON_AGGR_TYPE_P (t))
t = TYPE_CONTEXT (t);
return accessible_p (t, decl);
}
tree
lookup_base (tree t, tree base, base_access access, base_kind *kind_ptr)
{
tree binfo = NULL;
tree t_binfo = NULL;
base_kind bk;
if (t == error_mark_node || base == error_mark_node)
{
if (kind_ptr)
*kind_ptr = bk_not_base;
return error_mark_node;
}
my_friendly_assert (TYPE_P (base), 20011127);
if (!TYPE_P (t))
{
t_binfo = t;
t = BINFO_TYPE (t);
}
else
t_binfo = TYPE_BINFO (t);
t = complete_type (TYPE_MAIN_VARIANT (t));
base = complete_type (TYPE_MAIN_VARIANT (base));
bk = lookup_base_r (t_binfo, base, access, 0, &binfo);
if (access != ba_any)
switch (bk)
{
case bk_not_base:
break;
case bk_ambig:
binfo = NULL_TREE;
if (!(access & ba_quiet))
{
error ("`%T' is an ambiguous base of `%T'", base, t);
binfo = error_mark_node;
}
break;
default:
if ((access & ~ba_quiet) != ba_ignore
&& COMPLETE_TYPE_P (base)
&& !accessible_base_p (t, base))
{
if (!(access & ba_quiet))
{
error ("`%T' is an inaccessible base of `%T'", base, t);
binfo = error_mark_node;
}
else
binfo = NULL_TREE;
bk = bk_inaccessible;
}
break;
}
if (kind_ptr)
*kind_ptr = bk;
return binfo;
}
static int
dynamic_cast_base_recurse (tree subtype, tree binfo, bool is_via_virtual,
tree *offset_ptr)
{
tree binfos, accesses;
int i, n_baselinks;
int worst = -2;
if (BINFO_TYPE (binfo) == subtype)
{
if (is_via_virtual)
return -1;
else
{
*offset_ptr = BINFO_OFFSET (binfo);
return 0;
}
}
binfos = BINFO_BASETYPES (binfo);
accesses = BINFO_BASEACCESSES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree base_access = TREE_VEC_ELT (accesses, i);
int rval;
if (base_access != access_public_node)
continue;
rval = dynamic_cast_base_recurse
(subtype, base_binfo,
is_via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
if (worst == -2)
worst = rval;
else if (rval >= 0)
worst = worst >= 0 ? -3 : worst;
else if (rval == -1)
worst = -1;
else if (rval == -3 && worst != -1)
worst = -3;
}
return worst;
}
tree
get_dynamic_cast_base_type (tree subtype, tree target)
{
tree offset = NULL_TREE;
int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
false, &offset);
if (!boff)
return offset;
offset = build_int_2 (boff, -1);
TREE_TYPE (offset) = ssizetype;
return offset;
}
tree
lookup_field_1 (tree type, tree name, bool want_type)
{
tree field;
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
|| TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (type) == TYPENAME_TYPE)
return NULL_TREE;
if (TYPE_NAME (type)
&& DECL_LANG_SPECIFIC (TYPE_NAME (type))
&& DECL_SORTED_FIELDS (TYPE_NAME (type)))
{
tree *fields = &DECL_SORTED_FIELDS (TYPE_NAME (type))->elts[0];
int lo = 0, hi = DECL_SORTED_FIELDS (TYPE_NAME (type))->len;
int i;
while (lo < hi)
{
i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS
n_fields_searched++;
#endif
if (DECL_NAME (fields[i]) > name)
hi = i;
else if (DECL_NAME (fields[i]) < name)
lo = i + 1;
else
{
field = NULL_TREE;
if (want_type)
{
do
field = fields[i--];
while (i >= lo && DECL_NAME (fields[i]) == name);
if (TREE_CODE (field) != TYPE_DECL
&& !DECL_CLASS_TEMPLATE_P (field))
field = NULL_TREE;
}
else
{
do
field = fields[i++];
while (i < hi && DECL_NAME (fields[i]) == name);
}
return field;
}
}
return NULL_TREE;
}
field = TYPE_FIELDS (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field_1++;
#endif
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
#ifdef GATHER_STATISTICS
n_fields_searched++;
#endif
my_friendly_assert (DECL_P (field), 0);
if (DECL_NAME (field) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree temp = lookup_field_1 (TREE_TYPE (field), name, want_type);
if (temp)
return temp;
}
if (TREE_CODE (field) == USING_DECL)
continue;
if (DECL_NAME (field) == name
&& (!want_type
|| TREE_CODE (field) == TYPE_DECL
|| DECL_CLASS_TEMPLATE_P (field)))
return field;
}
if (name == vptr_identifier)
{
if (TYPE_POLYMORPHIC_P (type))
return TYPE_VFIELD (type);
}
return NULL_TREE;
}
tree
current_scope (void)
{
if (current_function_decl == NULL_TREE)
return current_class_type;
if (current_class_type == NULL_TREE)
return current_function_decl;
if ((DECL_FUNCTION_MEMBER_P (current_function_decl)
&& same_type_p (DECL_CONTEXT (current_function_decl),
current_class_type))
|| (DECL_FRIEND_CONTEXT (current_function_decl)
&& same_type_p (DECL_FRIEND_CONTEXT (current_function_decl),
current_class_type)))
return current_function_decl;
return current_class_type;
}
int
at_function_scope_p (void)
{
tree cs = current_scope ();
return cs && TREE_CODE (cs) == FUNCTION_DECL;
}
bool
at_class_scope_p (void)
{
tree cs = current_scope ();
return cs && TYPE_P (cs);
}
bool
at_namespace_scope_p (void)
{
return !current_scope();
}
tree
context_for_name_lookup (tree decl)
{
tree context = DECL_CONTEXT (decl);
while (context && TYPE_P (context) && ANON_AGGR_TYPE_P (context))
context = TYPE_CONTEXT (context);
if (!context)
context = global_namespace;
return context;
}
#define BINFO_ACCESS(NODE) \
((access_kind) ((TREE_PUBLIC (NODE) << 1) | TREE_PRIVATE (NODE)))
#define SET_BINFO_ACCESS(NODE, ACCESS) \
((TREE_PUBLIC (NODE) = ((ACCESS) & 2) != 0), \
(TREE_PRIVATE (NODE) = ((ACCESS) & 1) != 0))
static tree
dfs_access_in_type (tree binfo, void *data)
{
tree decl = (tree) data;
tree type = BINFO_TYPE (binfo);
access_kind access = ak_none;
if (context_for_name_lookup (decl) == type)
{
if (TREE_PRIVATE (decl))
access = ak_private;
else if (TREE_PROTECTED (decl))
access = ak_protected;
else
access = ak_public;
}
else
{
if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl))
{
tree decl_access = purpose_member (type, DECL_ACCESS (decl));
if (decl_access)
{
decl_access = TREE_VALUE (decl_access);
if (decl_access == access_public_node)
access = ak_public;
else if (decl_access == access_protected_node)
access = ak_protected;
else if (decl_access == access_private_node)
access = ak_private;
else
my_friendly_assert (false, 20030217);
}
}
if (!access)
{
int i;
int n_baselinks;
tree binfos, accesses;
binfos = BINFO_BASETYPES (binfo);
accesses = BINFO_BASEACCESSES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; ++i)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree base_access = TREE_VEC_ELT (accesses, i);
access_kind base_access_now = BINFO_ACCESS (base_binfo);
if (base_access_now == ak_none || base_access_now == ak_private)
base_access_now = ak_none;
else if (base_access == access_protected_node)
base_access_now = ak_protected;
else if (base_access == access_private_node)
base_access_now = ak_private;
if (base_access_now != ak_none
&& (access == ak_none || base_access_now < access))
{
access = base_access_now;
if (access == ak_public)
break;
}
}
}
}
SET_BINFO_ACCESS (binfo, access);
BINFO_MARKED (binfo) = 1;
return NULL_TREE;
}
static access_kind
access_in_type (tree type, tree decl)
{
tree binfo = TYPE_BINFO (type);
dfs_walk_real (binfo, 0, dfs_access_in_type, unmarkedp, decl);
dfs_walk (binfo, dfs_unmark, markedp, 0);
return BINFO_ACCESS (binfo);
}
static tree
dfs_accessible_queue_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
if (BINFO_MARKED (binfo))
return NULL_TREE;
if (BINFO_BASEACCESS (derived, ix) != access_public_node
&& !is_friend (BINFO_TYPE (derived), current_scope ()))
return NULL_TREE;
return binfo;
}
static tree
dfs_accessible_p (tree binfo, void *data ATTRIBUTE_UNUSED)
{
access_kind access;
BINFO_MARKED (binfo) = 1;
access = BINFO_ACCESS (binfo);
if (access != ak_none
&& is_friend (BINFO_TYPE (binfo), current_scope ()))
return binfo;
return NULL_TREE;
}
static int
protected_accessible_p (tree decl, tree derived, tree binfo)
{
access_kind access;
if (!DERIVED_FROM_P (context_for_name_lookup (decl), derived))
return 0;
access = access_in_type (derived, decl);
if (access == ak_none)
return 0;
if (DECL_NONSTATIC_MEMBER_P (decl))
{
tree t = binfo;
while (BINFO_INHERITANCE_CHAIN (t))
t = BINFO_INHERITANCE_CHAIN (t);
if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
return 0;
}
return 1;
}
static int
friend_accessible_p (tree scope, tree decl, tree binfo)
{
tree befriending_classes;
tree t;
if (!scope)
return 0;
if (TREE_CODE (scope) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (scope))
befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
else if (TYPE_P (scope))
befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
else
return 0;
for (t = befriending_classes; t; t = TREE_CHAIN (t))
if (protected_accessible_p (decl, TREE_VALUE (t), binfo))
return 1;
if (TYPE_P (scope))
for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
if (protected_accessible_p (decl, t, binfo))
return 1;
if (TREE_CODE (scope) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (scope))
{
if (DECL_CLASS_SCOPE_P (decl)
&& friend_accessible_p (DECL_CONTEXT (scope), decl, binfo))
return 1;
if (DECL_TEMPLATE_INFO (scope))
return friend_accessible_p (DECL_TI_TEMPLATE (scope), decl, binfo);
}
else if (CLASSTYPE_TEMPLATE_INFO (scope))
return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope), decl, binfo);
return 0;
}
int
accessible_p (tree type, tree decl)
{
tree binfo;
tree t;
tree scope;
access_kind access;
int protected_ok = 0;
if (!TYPE_P (context_for_name_lookup (decl)))
return 1;
scope = current_scope ();
if (scope && DECL_THUNK_P (scope))
return 1;
if (processing_template_decl)
return 1;
if (!TYPE_P (type))
{
binfo = type;
type = BINFO_TYPE (type);
}
else
binfo = TYPE_BINFO (type);
if (current_class_type)
protected_ok = protected_accessible_p (decl, current_class_type, binfo);
if (!protected_ok)
protected_ok = friend_accessible_p (scope, decl, binfo);
binfo = TYPE_BINFO (type);
access = access_in_type (type, decl);
if (access == ak_public
|| (access == ak_protected && protected_ok))
return 1;
else
{
t = dfs_walk (binfo, dfs_accessible_p, dfs_accessible_queue_p, 0);
dfs_walk (binfo, dfs_unmark, 0, 0);
return t != NULL_TREE;
}
}
struct lookup_field_info {
tree type;
tree name;
tree rval;
tree rval_binfo;
tree ambiguous;
int want_type;
const char *errstr;
};
static tree
lookup_field_queue_p (tree derived, int ix, void *data)
{
tree binfo = BINFO_BASETYPE (derived, ix);
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))
return NULL_TREE;
if (lfi->rval_binfo && original_binfo (binfo, lfi->rval_binfo))
return NULL_TREE;
if (BINFO_DEPENDENT_BASE_P (binfo))
return NULL_TREE;
return binfo;
}
static int
template_self_reference_p (tree type, tree decl)
{
return (CLASSTYPE_USE_TEMPLATE (type)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
&& TREE_CODE (decl) == TYPE_DECL
&& DECL_ARTIFICIAL (decl)
&& DECL_NAME (decl) == constructor_name (type));
}
static int
shared_member_p (tree t)
{
if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == TYPE_DECL \
|| TREE_CODE (t) == CONST_DECL)
return 1;
if (is_overloaded_fn (t))
{
for (; t; t = OVL_NEXT (t))
{
tree fn = OVL_CURRENT (t);
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
return 0;
}
return 1;
}
return 0;
}
static tree
lookup_field_r (tree binfo, void *data)
{
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
tree type = BINFO_TYPE (binfo);
tree nval = NULL_TREE;
if (!lfi->want_type)
{
int idx = lookup_fnfields_1 (type, lfi->name);
if (idx >= 0)
nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
}
if (!nval)
nval = lookup_field_1 (type, lfi->name, lfi->want_type);
if (!nval)
return NULL_TREE;
if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL
&& !DECL_CLASS_TEMPLATE_P (nval))
{
if (lfi->name == TYPE_IDENTIFIER (type))
{
for (nval = TREE_CHAIN (nval); nval; nval = TREE_CHAIN (nval))
if (DECL_NAME (nval) == lfi->name
&& TREE_CODE (nval) == TYPE_DECL)
break;
}
else
nval = NULL_TREE;
if (!nval && CLASSTYPE_NESTED_UTDS (type) != NULL)
{
binding_entry e = binding_table_find (CLASSTYPE_NESTED_UTDS (type),
lfi->name);
if (e != NULL)
nval = TYPE_MAIN_DECL (e->type);
else
return NULL_TREE;
}
}
if (!same_type_p (type, lfi->type)
&& template_self_reference_p (type, nval))
return NULL_TREE;
if (lfi->rval_binfo && !original_binfo (lfi->rval_binfo, binfo))
{
if (nval == lfi->rval && shared_member_p (nval))
;
else if (original_binfo (binfo, lfi->rval_binfo))
;
else
{
if (!lfi->ambiguous && lfi->rval)
{
lfi->ambiguous = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
}
lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
lfi->errstr = "request for member `%D' is ambiguous";
}
}
else
{
lfi->rval = nval;
lfi->rval_binfo = binfo;
}
return NULL_TREE;
}
tree
build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)
{
tree baselink;
my_friendly_assert (TREE_CODE (functions) == FUNCTION_DECL
|| TREE_CODE (functions) == TEMPLATE_DECL
|| TREE_CODE (functions) == TEMPLATE_ID_EXPR
|| TREE_CODE (functions) == OVERLOAD,
20020730);
my_friendly_assert (!optype || TYPE_P (optype), 20020730);
my_friendly_assert (TREE_TYPE (functions), 20020805);
baselink = make_node (BASELINK);
TREE_TYPE (baselink) = TREE_TYPE (functions);
BASELINK_BINFO (baselink) = binfo;
BASELINK_ACCESS_BINFO (baselink) = access_binfo;
BASELINK_FUNCTIONS (baselink) = functions;
BASELINK_OPTYPE (baselink) = optype;
return baselink;
}
tree
lookup_member (tree xbasetype, tree name, int protect, bool want_type)
{
tree rval, rval_binfo = NULL_TREE;
tree type = NULL_TREE, basetype_path = NULL_TREE;
struct lookup_field_info lfi;
const char *errstr = 0;
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030624);
if (TREE_CODE (xbasetype) == TREE_VEC)
{
type = BINFO_TYPE (xbasetype);
basetype_path = xbasetype;
}
else
{
my_friendly_assert (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)), 20030624);
type = xbasetype;
basetype_path = TYPE_BINFO (type);
my_friendly_assert (!BINFO_INHERITANCE_CHAIN (basetype_path), 980827);
}
if (type == current_class_type && TYPE_BEING_DEFINED (type)
&& IDENTIFIER_CLASS_VALUE (name))
{
tree field = IDENTIFIER_CLASS_VALUE (name);
if (! is_overloaded_fn (field)
&& ! (want_type && TREE_CODE (field) != TYPE_DECL))
return field;
}
complete_type (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
#endif
memset (&lfi, 0, sizeof (lfi));
lfi.type = type;
lfi.name = name;
lfi.want_type = want_type;
bfs_walk (basetype_path, &lookup_field_r, &lookup_field_queue_p, &lfi);
rval = lfi.rval;
rval_binfo = lfi.rval_binfo;
if (rval_binfo)
type = BINFO_TYPE (rval_binfo);
errstr = lfi.errstr;
if (!protect && lfi.ambiguous)
return NULL_TREE;
if (protect == 2)
{
if (lfi.ambiguous)
return lfi.ambiguous;
else
protect = 0;
}
if (rval && protect && !is_overloaded_fn (rval))
perform_or_defer_access_check (basetype_path, rval);
if (errstr && protect)
{
error (errstr, name, type);
if (lfi.ambiguous)
print_candidates (lfi.ambiguous);
rval = error_mark_node;
}
if (rval && is_overloaded_fn (rval))
rval = build_baselink (rval_binfo, basetype_path, rval,
(IDENTIFIER_TYPENAME_P (name)
? TREE_TYPE (name): NULL_TREE));
return rval;
}
tree
lookup_field (tree xbasetype, tree name, int protect, bool want_type)
{
tree rval = lookup_member (xbasetype, name, protect, want_type);
if (rval && BASELINK_P (rval))
return NULL_TREE;
return rval;
}
tree
lookup_fnfields (tree xbasetype, tree name, int protect)
{
tree rval = lookup_member (xbasetype, name, protect, false);
if (rval && !BASELINK_P (rval))
return NULL_TREE;
return rval;
}
static int
lookup_conversion_operator (tree class_type, tree type)
{
int pass;
int i;
tree methods = CLASSTYPE_METHOD_VEC (class_type);
for (pass = 0; pass < 2; ++pass)
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
i < TREE_VEC_LENGTH (methods);
++i)
{
tree fn = TREE_VEC_ELT (methods, i);
if (!fn)
break;
fn = OVL_CURRENT (fn);
if (!DECL_CONV_FN_P (fn))
break;
if (pass == 0)
{
if (TREE_CODE (fn) != TEMPLATE_DECL
&& same_type_p (DECL_CONV_FN_TYPE (fn), type))
return i;
}
else
{
if (TREE_CODE (fn) == TEMPLATE_DECL)
return i;
}
}
return -1;
}
int
lookup_fnfields_1 (tree type, tree name)
{
tree method_vec;
tree *methods;
tree tmp;
int i;
int len;
if (!CLASS_TYPE_P (type))
return -1;
method_vec = CLASSTYPE_METHOD_VEC (type);
if (!method_vec)
return -1;
methods = &TREE_VEC_ELT (method_vec, 0);
len = TREE_VEC_LENGTH (method_vec);
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
#endif
if (name == ctor_identifier)
return (methods[CLASSTYPE_CONSTRUCTOR_SLOT]
? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
if (name == dtor_identifier)
return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
? CLASSTYPE_DESTRUCTOR_SLOT : -1);
if (IDENTIFIER_TYPENAME_P (name))
return lookup_conversion_operator (type, TREE_TYPE (name));
i = CLASSTYPE_FIRST_CONVERSION_SLOT;
while (i < len && methods[i] && DECL_CONV_FN_P (OVL_CURRENT (methods[i])))
i++;
if (COMPLETE_TYPE_P (type))
{
int lo = i;
int hi = len;
while (lo < hi)
{
i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
tmp = methods[i];
if (tmp)
tmp = DECL_NAME (OVL_CURRENT (tmp));
if (!tmp || tmp > name)
hi = i;
else if (tmp < name)
lo = i + 1;
else
return i;
}
}
else
for (; i < len && methods[i]; ++i)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
tmp = OVL_CURRENT (methods[i]);
if (DECL_NAME (tmp) == name)
return i;
}
return -1;
}
tree
adjust_result_of_qualified_name_lookup (tree decl,
tree qualifying_scope,
tree context_class)
{
if (context_class && CLASS_TYPE_P (qualifying_scope)
&& DERIVED_FROM_P (qualifying_scope, context_class)
&& BASELINK_P (decl))
{
tree base;
my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
base = lookup_base (context_class, qualifying_scope,
ba_ignore | ba_quiet, NULL);
if (base)
{
BASELINK_ACCESS_BINFO (decl) = base;
BASELINK_BINFO (decl)
= lookup_base (base, BINFO_TYPE (BASELINK_BINFO (decl)),
ba_ignore | ba_quiet,
NULL);
}
}
return decl;
}
#define BFS_WALK_INITIAL_QUEUE_SIZE 10
static tree
bfs_walk (tree binfo,
tree (*fn) (tree, void *),
tree (*qfn) (tree, int, void *),
void *data)
{
tree rval = NULL_TREE;
tree bases_initial[BFS_WALK_INITIAL_QUEUE_SIZE];
size_t head, tail;
size_t base_buffer_size = BFS_WALK_INITIAL_QUEUE_SIZE;
tree *base_buffer = bases_initial;
head = tail = 0;
base_buffer[tail++] = binfo;
while (head != tail)
{
int n_bases, ix;
tree binfo = base_buffer[head++];
if (head == base_buffer_size)
head = 0;
rval = fn (binfo, data);
if (rval)
goto done;
n_bases = BINFO_N_BASETYPES (binfo);
for (ix = 0; ix != n_bases; ix++)
{
tree base_binfo;
if (qfn)
base_binfo = (*qfn) (binfo, ix, data);
else
base_binfo = BINFO_BASETYPE (binfo, ix);
if (base_binfo)
{
base_buffer[tail++] = base_binfo;
if (tail == base_buffer_size)
tail = 0;
if (tail == head)
{
tree *new_buffer = xmalloc (2 * base_buffer_size
* sizeof (tree));
memcpy (&new_buffer[0], &base_buffer[0],
tail * sizeof (tree));
memcpy (&new_buffer[head + base_buffer_size],
&base_buffer[head],
(base_buffer_size - head) * sizeof (tree));
if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)
free (base_buffer);
base_buffer = new_buffer;
head += base_buffer_size;
base_buffer_size *= 2;
}
}
}
}
done:
if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)
free (base_buffer);
return rval;
}
tree
dfs_walk_real (tree binfo,
tree (*prefn) (tree, void *),
tree (*postfn) (tree, void *),
tree (*qfn) (tree, int, void *),
void *data)
{
tree rval = NULL_TREE;
if (prefn)
{
rval = (*prefn) (binfo, data);
if (rval)
return rval;
}
if (BINFO_BASETYPES (binfo))
{
int i, n = TREE_VEC_LENGTH (BINFO_BASETYPES (binfo));
for (i = 0; i != n; i++)
{
tree base_binfo;
if (qfn)
base_binfo = (*qfn) (binfo, i, data);
else
base_binfo = BINFO_BASETYPE (binfo, i);
if (base_binfo)
{
rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
if (rval)
return rval;
}
}
}
if (postfn)
rval = (*postfn) (binfo, data);
return rval;
}
tree
dfs_walk (tree binfo,
tree (*fn) (tree, void *),
tree (*qfn) (tree, int, void *),
void *data)
{
return dfs_walk_real (binfo, 0, fn, qfn, data);
}
int
check_final_overrider (tree overrider, tree basefn)
{
tree over_type = TREE_TYPE (overrider);
tree base_type = TREE_TYPE (basefn);
tree over_return = TREE_TYPE (over_type);
tree base_return = TREE_TYPE (base_type);
tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
int fail = 0;
if (DECL_INVALID_OVERRIDER_P (overrider))
return 0;
if (same_type_p (base_return, over_return))
;
else if ((CLASS_TYPE_P (over_return) && CLASS_TYPE_P (base_return))
|| (TREE_CODE (base_return) == TREE_CODE (over_return)
&& POINTER_TYPE_P (base_return)))
{
unsigned base_quals, over_quals;
fail = !POINTER_TYPE_P (base_return);
if (!fail)
{
fail = cp_type_quals (base_return) != cp_type_quals (over_return);
base_return = TREE_TYPE (base_return);
over_return = TREE_TYPE (over_return);
}
base_quals = cp_type_quals (base_return);
over_quals = cp_type_quals (over_return);
if ((base_quals & over_quals) != over_quals)
fail = 1;
if (CLASS_TYPE_P (base_return) && CLASS_TYPE_P (over_return))
{
tree binfo = lookup_base (over_return, base_return,
ba_check | ba_quiet, NULL);
if (!binfo)
fail = 1;
}
else if (!pedantic
&& can_convert (TREE_TYPE (base_type), TREE_TYPE (over_type)))
{
over_return = non_reference (TREE_TYPE (over_type));
if (CLASS_TYPE_P (over_return))
fail = 2;
}
else
fail = 2;
}
else
fail = 2;
if (!fail)
;
else
{
if (fail == 1)
{
cp_error_at ("invalid covariant return type for `%#D'", overrider);
cp_error_at (" overriding `%#D'", basefn);
}
else
{
cp_error_at ("conflicting return type specified for `%#D'",
overrider);
cp_error_at (" overriding `%#D'", basefn);
}
DECL_INVALID_OVERRIDER_P (overrider) = 1;
return 0;
}
if (!comp_except_specs (base_throw, over_throw, 0))
{
cp_error_at ("looser throw specifier for `%#F'", overrider);
cp_error_at (" overriding `%#F'", basefn);
DECL_INVALID_OVERRIDER_P (overrider) = 1;
return 0;
}
return 1;
}
int
look_for_overrides (tree type, tree fndecl)
{
tree binfo = TYPE_BINFO (type);
tree basebinfos = BINFO_BASETYPES (binfo);
int nbasebinfos = basebinfos ? TREE_VEC_LENGTH (basebinfos) : 0;
int ix;
int found = 0;
for (ix = 0; ix != nbasebinfos; ix++)
{
tree basetype = BINFO_TYPE (TREE_VEC_ELT (basebinfos, ix));
if (TYPE_POLYMORPHIC_P (basetype))
found += look_for_overrides_r (basetype, fndecl);
}
return found;
}
tree
look_for_overrides_here (tree type, tree fndecl)
{
int ix;
if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fndecl))
ix = CLASSTYPE_DESTRUCTOR_SLOT;
else
ix = lookup_fnfields_1 (type, DECL_NAME (fndecl));
if (ix >= 0)
{
tree fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (!DECL_VIRTUAL_P (fn))
;
else if (DECL_CONTEXT (fn) != type)
;
else if (DECL_STATIC_FUNCTION_P (fndecl))
{
tree btypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (compparms (TREE_CHAIN (btypes), dtypes))
return fn;
}
else if (same_signature_p (fndecl, fn))
return fn;
}
}
return NULL_TREE;
}
static int
look_for_overrides_r (tree type, tree fndecl)
{
tree fn = look_for_overrides_here (type, fndecl);
if (fn)
{
if (DECL_STATIC_FUNCTION_P (fndecl))
{
cp_error_at ("`%#D' cannot be declared", fndecl);
cp_error_at (" since `%#D' declared in base class", fn);
}
else
{
DECL_VIRTUAL_P (fndecl) = 1;
check_final_overrider (fndecl, fn);
}
return 1;
}
return look_for_overrides (type, fndecl);
}
static tree
dfs_get_pure_virtuals (tree binfo, void *data)
{
tree type = (tree) data;
if (!BINFO_PRIMARY_P (binfo))
{
tree virtuals;
for (virtuals = BINFO_VIRTUALS (binfo);
virtuals;
virtuals = TREE_CHAIN (virtuals))
if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
CLASSTYPE_PURE_VIRTUALS (type)
= tree_cons (NULL_TREE, BV_FN (virtuals),
CLASSTYPE_PURE_VIRTUALS (type));
}
BINFO_MARKED (binfo) = 1;
return NULL_TREE;
}
void
get_pure_virtuals (tree type)
{
tree vbases;
CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;
dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals, unmarkedp, type);
dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, type);
CLASSTYPE_PURE_VIRTUALS (type) = nreverse (CLASSTYPE_PURE_VIRTUALS (type));
for (vbases = CLASSTYPE_VBASECLASSES (type);
vbases;
vbases = TREE_CHAIN (vbases))
{
tree virtuals;
for (virtuals = BINFO_VIRTUALS (TREE_VALUE (vbases));
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
tree base_fndecl = BV_FN (virtuals);
if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
error ("`%#D' needs a final overrider", base_fndecl);
}
}
}
tree
markedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
return BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
tree
unmarkedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
marked_pushdecls_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
return (!BINFO_DEPENDENT_BASE_P (binfo)
&& BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
static tree
unmarked_pushdecls_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
return (!BINFO_DEPENDENT_BASE_P (binfo)
&& !BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
tree
dfs_unmark (tree binfo, void *data ATTRIBUTE_UNUSED)
{
BINFO_MARKED (binfo) = 0;
return NULL_TREE;
}
void
maybe_suppress_debug_info (tree t)
{
if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
return;
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
if (CLASSTYPE_INTERFACE_KNOWN (t))
{
if (CLASSTYPE_INTERFACE_ONLY (t))
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
}
else if (TYPE_CONTAINS_VPTR_P (t))
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
}
static tree
dfs_debug_mark (tree binfo, void *data ATTRIBUTE_UNUSED)
{
tree t = BINFO_TYPE (binfo);
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
return NULL_TREE;
}
static tree
dfs_debug_unmarkedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
{
tree binfo = BINFO_BASETYPE (derived, ix);
return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo))
? binfo : NULL_TREE);
}
void
note_debug_info_needed (tree type)
{
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type)))
{
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type)) = 0;
rest_of_type_compilation (type, toplevel_bindings_p ());
}
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
}
static void
setup_class_bindings (tree name, int type_binding_p)
{
tree type_binding = NULL_TREE;
tree value_binding;
if (IDENTIFIER_CLASS_VALUE (name))
return;
if (type_binding_p)
{
type_binding = lookup_member (current_class_type, name,
2, true);
if (TREE_CODE (type_binding) == TREE_LIST
&& TREE_TYPE (type_binding) == error_mark_node)
push_class_level_binding (name, type_binding);
else
pushdecl_class_level (type_binding);
}
value_binding = lookup_member (current_class_type, name,
2, false);
if (type_binding_p
&& (TREE_CODE (value_binding) == TYPE_DECL
|| DECL_CLASS_TEMPLATE_P (value_binding)
|| (TREE_CODE (value_binding) == TREE_LIST
&& TREE_TYPE (value_binding) == error_mark_node
&& (TREE_CODE (TREE_VALUE (value_binding))
== TYPE_DECL))))
;
else if (value_binding)
{
if (TREE_CODE (value_binding) == TREE_LIST
&& TREE_TYPE (value_binding) == error_mark_node)
push_class_level_binding (name, value_binding);
else
{
if (BASELINK_P (value_binding))
value_binding = BASELINK_FUNCTIONS (value_binding);
if (IDENTIFIER_TYPENAME_P (name)
&& is_overloaded_fn (value_binding))
{
tree fns;
for (fns = value_binding; fns; fns = OVL_NEXT (fns))
if (IDENTIFIER_CLASS_VALUE (DECL_NAME (OVL_CURRENT (fns))))
return;
}
pushdecl_class_level (value_binding);
}
}
}
static tree
dfs_push_type_decls (tree binfo, void *data ATTRIBUTE_UNUSED)
{
tree type;
tree fields;
type = BINFO_TYPE (binfo);
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
if (DECL_NAME (fields) && TREE_CODE (fields) == TYPE_DECL
&& !(!same_type_p (type, current_class_type)
&& template_self_reference_p (type, fields)))
setup_class_bindings (DECL_NAME (fields), 1);
BINFO_PUSHDECLS_MARKED (binfo) = 1;
return NULL_TREE;
}
static tree
dfs_push_decls (tree binfo, void *data)
{
tree type = BINFO_TYPE (binfo);
tree method_vec;
tree fields;
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
if (DECL_NAME (fields)
&& TREE_CODE (fields) != TYPE_DECL
&& TREE_CODE (fields) != USING_DECL
&& !DECL_ARTIFICIAL (fields))
setup_class_bindings (DECL_NAME (fields), 0);
else if (TREE_CODE (fields) == FIELD_DECL
&& ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
method_vec = (CLASS_TYPE_P (type)
? CLASSTYPE_METHOD_VEC (type) : NULL_TREE);
if (method_vec && TREE_VEC_LENGTH (method_vec) >= 3)
{
tree *methods;
tree *end;
end = TREE_VEC_END (method_vec);
for (methods = &TREE_VEC_ELT (method_vec, 2);
methods < end && *methods;
methods++)
setup_class_bindings (DECL_NAME (OVL_CURRENT (*methods)),
0);
}
BINFO_PUSHDECLS_MARKED (binfo) = 0;
return NULL_TREE;
}
void
push_class_decls (tree type)
{
search_stack = push_search_level (search_stack, &search_obstack);
dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
}
static tree
dfs_unuse_fields (tree binfo, void *data ATTRIBUTE_UNUSED)
{
tree type = TREE_TYPE (binfo);
tree fields;
if (TREE_CODE (type) == TYPENAME_TYPE)
fields = TYPENAME_TYPE_FULLNAME (type);
else if (TREE_CODE (type) == TYPEOF_TYPE)
fields = TYPEOF_TYPE_EXPR (type);
else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
|| TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
fields = TEMPLATE_TYPE_PARM_INDEX (type);
else
fields = TYPE_FIELDS (type);
for (; fields; fields = TREE_CHAIN (fields))
{
if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
continue;
TREE_USED (fields) = 0;
if (DECL_NAME (fields) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
unuse_fields (TREE_TYPE (fields));
}
return NULL_TREE;
}
void
unuse_fields (tree type)
{
dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp, 0);
}
void
pop_class_decls (void)
{
if (search_stack)
search_stack = pop_search_level (search_stack);
}
void
print_search_statistics (void)
{
#ifdef GATHER_STATISTICS
fprintf (stderr, "%d fields searched in %d[%d] calls to lookup_field[_1]\n",
n_fields_searched, n_calls_lookup_field, n_calls_lookup_field_1);
fprintf (stderr, "%d fnfields searched in %d calls to lookup_fnfields\n",
n_outer_fields_searched, n_calls_lookup_fnfields);
fprintf (stderr, "%d calls to get_base_type\n", n_calls_get_base_type);
#else
fprintf (stderr, "no search statistics\n");
#endif
}
void
init_search_processing (void)
{
gcc_obstack_init (&search_obstack);
}
void
reinit_search_statistics (void)
{
#ifdef GATHER_STATISTICS
n_fields_searched = 0;
n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0;
n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0;
n_calls_get_base_type = 0;
n_outer_fields_searched = 0;
n_contexts_saved = 0;
#endif
}
static tree
add_conversions (tree binfo, void *data)
{
int i;
tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
tree *conversions = (tree *) data;
if (!method_vec)
return NULL_TREE;
for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
{
tree tmp = TREE_VEC_ELT (method_vec, i);
tree name;
if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
break;
name = DECL_NAME (OVL_CURRENT (tmp));
if (! IDENTIFIER_MARKED (name))
{
tree t;
for (t = *conversions; t; t = TREE_CHAIN (t))
{
tree fn;
for (fn = TREE_VALUE (t); fn; fn = OVL_NEXT (fn))
if (same_type_p (TREE_TYPE (name),
DECL_CONV_FN_TYPE (OVL_CURRENT (fn))))
break;
if (fn)
break;
}
if (!t)
{
*conversions = tree_cons (binfo, tmp, *conversions);
IDENTIFIER_MARKED (name) = 1;
}
}
}
return NULL_TREE;
}
tree
lookup_conversions (tree type)
{
tree t;
tree conversions = NULL_TREE;
complete_type (type);
bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
for (t = conversions; t; t = TREE_CHAIN (t))
IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;
return conversions;
}
struct overlap_info
{
tree compare_type;
int found_overlap;
};
static tree
dfs_check_overlap (tree empty_binfo, void *data)
{
struct overlap_info *oi = (struct overlap_info *) data;
tree binfo;
for (binfo = TYPE_BINFO (oi->compare_type);
;
binfo = BINFO_BASETYPE (binfo, 0))
{
if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
{
oi->found_overlap = 1;
break;
}
else if (BINFO_BASETYPES (binfo) == NULL_TREE)
break;
}
return NULL_TREE;
}
static tree
dfs_no_overlap_yet (tree derived, int ix, void *data)
{
tree binfo = BINFO_BASETYPE (derived, ix);
struct overlap_info *oi = (struct overlap_info *) data;
return !oi->found_overlap ? binfo : NULL_TREE;
}
int
types_overlap_p (tree empty_type, tree next_type)
{
struct overlap_info oi;
if (! IS_AGGR_TYPE (next_type))
return 0;
oi.compare_type = next_type;
oi.found_overlap = 0;
dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap,
dfs_no_overlap_yet, &oi);
return oi.found_overlap;
}
tree
binfo_for_vtable (tree var)
{
tree main_binfo = TYPE_BINFO (DECL_CONTEXT (var));
tree binfos = TYPE_BINFO_BASETYPES (BINFO_TYPE (main_binfo));
int n_baseclasses = CLASSTYPE_N_BASECLASSES (BINFO_TYPE (main_binfo));
int i;
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (base_binfo != NULL_TREE && BINFO_VTABLE (base_binfo) == var)
return base_binfo;
}
if (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (main_binfo)))
return get_primary_binfo (main_binfo);
return main_binfo;
}
tree
binfo_from_vbase (tree binfo)
{
for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (TREE_VIA_VIRTUAL (binfo))
return binfo;
}
return NULL_TREE;
}
tree
binfo_via_virtual (tree binfo, tree limit)
{
for (; binfo && (!limit || !same_type_p (BINFO_TYPE (binfo), limit));
binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (TREE_VIA_VIRTUAL (binfo))
return binfo;
}
return NULL_TREE;
}
tree
copied_binfo (tree binfo, tree here)
{
tree result = NULL_TREE;
if (TREE_VIA_VIRTUAL (binfo))
{
tree t;
for (t = here; BINFO_INHERITANCE_CHAIN (t);
t = BINFO_INHERITANCE_CHAIN (t))
continue;
result = purpose_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (BINFO_TYPE (t)));
result = TREE_VALUE (result);
}
else if (BINFO_INHERITANCE_CHAIN (binfo))
{
tree base_binfos;
int ix, n;
base_binfos = copied_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
base_binfos = BINFO_BASETYPES (base_binfos);
n = TREE_VEC_LENGTH (base_binfos);
for (ix = 0; ix != n; ix++)
{
tree base = TREE_VEC_ELT (base_binfos, ix);
if (BINFO_TYPE (base) == BINFO_TYPE (binfo))
{
result = base;
break;
}
}
}
else
{
my_friendly_assert (BINFO_TYPE (here) == BINFO_TYPE (binfo), 20030202);
result = here;
}
my_friendly_assert (result, 20030202);
return result;
}
tree
original_binfo (tree binfo, tree here)
{
tree result = NULL;
if (BINFO_TYPE (binfo) == BINFO_TYPE (here))
result = here;
else if (TREE_VIA_VIRTUAL (binfo))
{
result = purpose_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (BINFO_TYPE (here)));
if (result)
result = TREE_VALUE (result);
}
else if (BINFO_INHERITANCE_CHAIN (binfo))
{
tree base_binfos;
base_binfos = original_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
if (base_binfos)
{
int ix, n;
base_binfos = BINFO_BASETYPES (base_binfos);
n = TREE_VEC_LENGTH (base_binfos);
for (ix = 0; ix != n; ix++)
{
tree base = TREE_VEC_ELT (base_binfos, ix);
if (BINFO_TYPE (base) == BINFO_TYPE (binfo))
{
result = base;
break;
}
}
}
}
return result;
}