#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"
static int is_subobject_of_p (tree, tree);
static tree dfs_lookup_base (tree, void *);
static tree dfs_dcast_hint_pre (tree, void *);
static tree dfs_dcast_hint_post (tree, void *);
static tree dfs_debug_mark (tree, void *);
static tree dfs_walk_once_r (tree, tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data);
static void dfs_unmark_r (tree);
static int check_hidden_convs (tree, int, int, tree, tree, tree);
static tree split_conversions (tree, tree, tree, tree);
static int lookup_conversions_r (tree, int, int,
tree, tree, tree, tree, tree *, tree *);
static int look_for_overrides_r (tree, tree);
static tree lookup_field_r (tree, void *);
static tree dfs_accessible_post (tree, void *);
static tree dfs_walk_once_accessible_r (tree, bool, bool,
tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *),
void *data);
static tree dfs_walk_once_accessible (tree, bool,
tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *),
void *data);
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 int template_self_reference_p (tree, tree);
static tree dfs_get_pure_virtuals (tree, void *);
#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
struct lookup_base_data_s
{
tree t;
tree base;
tree binfo;
bool via_virtual;
bool ambiguous;
bool repeated_base;
bool want_any;
};
static tree
dfs_lookup_base (tree binfo, void *data_)
{
struct lookup_base_data_s *data = (struct lookup_base_data_s *) data_;
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), data->base))
{
if (!data->binfo)
{
data->binfo = binfo;
data->via_virtual
= binfo_via_virtual (data->binfo, data->t) != NULL_TREE;
if (!data->repeated_base)
return binfo;
if (data->want_any && !data->via_virtual)
return binfo;
return dfs_skip_bases;
}
else
{
gcc_assert (binfo != data->binfo);
if (!data->want_any)
{
data->binfo = NULL_TREE;
data->ambiguous = true;
return error_mark_node;
}
if (!binfo_via_virtual (binfo, data->t))
{
data->binfo = binfo;
data->via_virtual = false;
return binfo;
}
return dfs_skip_bases;
}
}
return NULL_TREE;
}
bool
accessible_base_p (tree t, tree base, bool consider_local_p)
{
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, consider_local_p);
}
tree
lookup_base (tree t, tree base, base_access access, base_kind *kind_ptr)
{
tree binfo;
tree t_binfo;
base_kind bk;
if (t == error_mark_node || base == error_mark_node)
{
if (kind_ptr)
*kind_ptr = bk_not_base;
return error_mark_node;
}
gcc_assert (TYPE_P (base));
if (!TYPE_P (t))
{
t_binfo = t;
t = BINFO_TYPE (t);
}
else
{
t = complete_type (TYPE_MAIN_VARIANT (t));
t_binfo = TYPE_BINFO (t);
}
base = complete_type (TYPE_MAIN_VARIANT (base));
if (t_binfo)
{
struct lookup_base_data_s data;
data.t = t;
data.base = base;
data.binfo = NULL_TREE;
data.ambiguous = data.via_virtual = false;
data.repeated_base = CLASSTYPE_REPEATED_BASE_P (t);
data.want_any = access == ba_any;
dfs_walk_once (t_binfo, dfs_lookup_base, NULL, &data);
binfo = data.binfo;
if (!binfo)
bk = data.ambiguous ? bk_ambig : bk_not_base;
else if (binfo == t_binfo)
bk = bk_same_type;
else if (data.via_virtual)
bk = bk_via_virtual;
else
bk = bk_proper_base;
}
else
{
binfo = NULL_TREE;
bk = bk_not_base;
}
if (access != ba_any)
switch (bk)
{
case bk_not_base:
break;
case bk_ambig:
if (!(access & ba_quiet))
{
error ("%qT is an ambiguous base of %qT", base, t);
binfo = error_mark_node;
}
break;
default:
if ((access & ba_check_bit)
&& COMPLETE_TYPE_P (base)
&& !accessible_base_p (t, base, !(access & ba_ignore_scope)))
{
if (!(access & ba_quiet))
{
error ("%qT is an inaccessible base of %qT", base, t);
binfo = error_mark_node;
}
else
binfo = NULL_TREE;
bk = bk_inaccessible;
}
break;
}
if (kind_ptr)
*kind_ptr = bk;
return binfo;
}
struct dcast_data_s
{
tree subtype;
int virt_depth;
tree offset;
bool repeated_base;
};
static tree
dfs_dcast_hint_pre (tree binfo, void *data_)
{
struct dcast_data_s *data = (struct dcast_data_s *) data_;
if (BINFO_VIRTUAL_P (binfo))
data->virt_depth++;
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), data->subtype))
{
if (data->virt_depth)
{
data->offset = ssize_int (-1);
return data->offset;
}
if (data->offset)
data->offset = ssize_int (-3);
else
data->offset = BINFO_OFFSET (binfo);
return data->repeated_base ? dfs_skip_bases : data->offset;
}
return NULL_TREE;
}
static tree
dfs_dcast_hint_post (tree binfo, void *data_)
{
struct dcast_data_s *data = (struct dcast_data_s *) data_;
if (BINFO_VIRTUAL_P (binfo))
data->virt_depth--;
return NULL_TREE;
}
tree
dcast_base_hint (tree subtype, tree target)
{
struct dcast_data_s data;
data.subtype = subtype;
data.virt_depth = 0;
data.offset = NULL_TREE;
data.repeated_base = CLASSTYPE_REPEATED_BASE_P (target);
dfs_walk_once_accessible (TYPE_BINFO (target), false,
dfs_dcast_hint_pre, dfs_dcast_hint_post, &data);
return data.offset ? data.offset : ssize_int (-2);
}
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
gcc_assert (DECL_P (field));
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)
{
if (!DECL_DEPENDENT_P (field))
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 && current_class_type
&& ((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;
if (current_class_type)
return current_class_type;
if (current_function_decl)
return current_function_decl;
return current_namespace;
}
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)
{
tree cs = current_scope ();
return cs && TREE_CODE (cs) == NAMESPACE_DECL;
}
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
gcc_unreachable ();
}
}
if (!access)
{
int i;
tree base_binfo;
VEC(tree,gc) *accesses;
accesses = BINFO_BASE_ACCESSES (binfo);
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
tree base_access = VEC_index (tree, 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);
return NULL_TREE;
}
static access_kind
access_in_type (tree type, tree decl)
{
tree binfo = TYPE_BINFO (type);
dfs_walk_once (binfo, NULL, dfs_access_in_type, decl);
return BINFO_ACCESS (binfo);
}
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 (scope)
&& friend_accessible_p (DECL_CONTEXT (scope), decl, binfo))
return 1;
if (DECL_TEMPLATE_INFO (scope))
{
int ret;
++processing_template_decl;
ret = friend_accessible_p (DECL_TI_TEMPLATE (scope), decl, binfo);
--processing_template_decl;
return ret;
}
}
return 0;
}
static tree
dfs_accessible_post (tree binfo, void *data ATTRIBUTE_UNUSED)
{
if (BINFO_ACCESS (binfo) != ak_none)
{
tree scope = current_scope ();
if (scope && TREE_CODE (scope) != NAMESPACE_DECL
&& is_friend (BINFO_TYPE (binfo), scope))
return binfo;
}
return NULL_TREE;
}
int
accessible_p (tree type, tree decl, bool consider_local_p)
{
tree binfo;
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
&& (!processing_template_parmlist || processing_template_decl > 1))
return 1;
if (!TYPE_P (type))
{
binfo = type;
type = BINFO_TYPE (type);
}
else
binfo = TYPE_BINFO (type);
if (consider_local_p)
{
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;
if (!consider_local_p)
return 0;
return dfs_walk_once_accessible (binfo, true,
NULL, dfs_accessible_post, NULL)
!= NULL_TREE;
}
struct lookup_field_info {
tree type;
tree name;
tree rval;
tree rval_binfo;
tree ambiguous;
int want_type;
const char *errstr;
};
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));
}
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 int
is_subobject_of_p (tree parent, tree binfo)
{
tree probe;
for (probe = parent; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
{
if (probe == binfo)
return 1;
if (BINFO_VIRTUAL_P (probe))
return (binfo_for_vbase (BINFO_TYPE (probe), BINFO_TYPE (binfo))
!= NULL_TREE);
}
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 (BINFO_DEPENDENT_BASE_P (binfo))
return NULL_TREE;
if (lfi->rval_binfo && BINFO_INHERITANCE_CHAIN (binfo) == lfi->rval_binfo
&& !BINFO_VIRTUAL_P (binfo))
return dfs_skip_bases;
if (!lfi->want_type)
{
int idx = lookup_fnfields_1 (type, lfi->name);
if (idx >= 0)
nval = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
}
if (!nval)
nval = lookup_field_1 (type, lfi->name, lfi->want_type);
if (!nval)
goto done;
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
goto done;
}
}
if (!same_type_p (type, lfi->type)
&& template_self_reference_p (type, nval))
goto done;
if (lfi->rval_binfo
&& !is_subobject_of_p (lfi->rval_binfo, binfo))
{
if (nval == lfi->rval && shared_member_p (nval))
;
else if (is_subobject_of_p (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 %qD is ambiguous";
}
}
else
{
lfi->rval = nval;
lfi->rval_binfo = binfo;
}
done:
if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))
return dfs_skip_bases;
return NULL_TREE;
}
tree
build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)
{
tree baselink;
gcc_assert (TREE_CODE (functions) == FUNCTION_DECL
|| TREE_CODE (functions) == TEMPLATE_DECL
|| TREE_CODE (functions) == TEMPLATE_ID_EXPR
|| TREE_CODE (functions) == OVERLOAD);
gcc_assert (!optype || TYPE_P (optype));
gcc_assert (TREE_TYPE (functions));
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;
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
if (TREE_CODE (xbasetype) == TREE_BINFO)
{
type = BINFO_TYPE (xbasetype);
basetype_path = xbasetype;
}
else
{
if (!IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
return NULL_TREE;
type = xbasetype;
xbasetype = NULL_TREE;
}
type = complete_type (type);
if (!basetype_path)
basetype_path = TYPE_BINFO (type);
if (!basetype_path)
return NULL_TREE;
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
#endif
memset (&lfi, 0, sizeof (lfi));
lfi.type = type;
lfi.name = name;
lfi.want_type = want_type;
dfs_walk_all (basetype_path, &lookup_field_r, NULL, &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
&& !really_overloaded_fn (rval)
&& !(TREE_CODE (rval) == FUNCTION_DECL
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (rval)))
perform_or_defer_access_check (basetype_path, rval, 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 (!error_operand_p (rval)
&& (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 (!error_operand_p (rval)
&& (rval && !BASELINK_P (rval)))
return NULL_TREE;
return rval;
}
static int
lookup_conversion_operator (tree class_type, tree type)
{
int tpl_slot = -1;
if (TYPE_HAS_CONVERSION (class_type))
{
int i;
tree fn;
VEC(tree,gc) *methods = CLASSTYPE_METHOD_VEC (class_type);
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
VEC_iterate (tree, methods, i, fn); ++i)
{
fn = OVL_CURRENT (fn);
if (!DECL_CONV_FN_P (fn))
break;
if (TREE_CODE (fn) == TEMPLATE_DECL)
tpl_slot = i;
else if (same_type_p (DECL_CONV_FN_TYPE (fn), type))
return i;
}
}
return tpl_slot;
}
int
lookup_fnfields_1 (tree type, tree name)
{
VEC(tree,gc) *method_vec;
tree fn;
tree tmp;
size_t i;
if (!CLASS_TYPE_P (type))
return -1;
if (COMPLETE_TYPE_P (type))
{
if ((name == ctor_identifier
|| name == base_ctor_identifier
|| name == complete_ctor_identifier))
{
if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
lazily_declare_fn (sfk_constructor, type);
if (CLASSTYPE_LAZY_COPY_CTOR (type))
lazily_declare_fn (sfk_copy_constructor, type);
}
else if (name == ansi_assopname(NOP_EXPR)
&& CLASSTYPE_LAZY_ASSIGNMENT_OP (type))
lazily_declare_fn (sfk_assignment_operator, type);
else if ((name == dtor_identifier
|| name == base_dtor_identifier
|| name == complete_dtor_identifier
|| name == deleting_dtor_identifier)
&& CLASSTYPE_LAZY_DESTRUCTOR (type))
lazily_declare_fn (sfk_destructor, type);
}
method_vec = CLASSTYPE_METHOD_VEC (type);
if (!method_vec)
return -1;
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
#endif
if (name == ctor_identifier)
{
fn = CLASSTYPE_CONSTRUCTORS (type);
return fn ? CLASSTYPE_CONSTRUCTOR_SLOT : -1;
}
if (name == dtor_identifier)
{
fn = CLASSTYPE_DESTRUCTORS (type);
return fn ? CLASSTYPE_DESTRUCTOR_SLOT : -1;
}
if (IDENTIFIER_TYPENAME_P (name))
return lookup_conversion_operator (type, TREE_TYPE (name));
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
VEC_iterate (tree, method_vec, i, fn);
++i)
if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
break;
if (COMPLETE_TYPE_P (type))
{
int lo;
int hi;
lo = i;
hi = VEC_length (tree, method_vec);
while (lo < hi)
{
i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
tmp = VEC_index (tree, method_vec, i);
tmp = DECL_NAME (OVL_CURRENT (tmp));
if (tmp > name)
hi = i;
else if (tmp < name)
lo = i + 1;
else
return i;
}
}
else
for (; VEC_iterate (tree, method_vec, i, fn); ++i)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
if (DECL_NAME (OVL_CURRENT (fn)) == name)
return i;
}
return -1;
}
int
class_method_index_for_fn (tree class_type, tree function)
{
gcc_assert (TREE_CODE (function) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (function));
return lookup_fnfields_1 (class_type,
DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
DECL_DESTRUCTOR_P (function) ? dtor_identifier :
DECL_NAME (function));
}
tree
adjust_result_of_qualified_name_lookup (tree decl,
tree qualifying_scope,
tree context_class)
{
if (context_class && context_class != error_mark_node
&& CLASS_TYPE_P (context_class)
&& CLASS_TYPE_P (qualifying_scope)
&& DERIVED_FROM_P (qualifying_scope, context_class)
&& BASELINK_P (decl))
{
tree base;
base = lookup_base (context_class, qualifying_scope,
ba_unique | ba_quiet, NULL);
if (base)
{
BASELINK_ACCESS_BINFO (decl) = base;
BASELINK_BINFO (decl)
= lookup_base (base, BINFO_TYPE (BASELINK_BINFO (decl)),
ba_unique | ba_quiet,
NULL);
}
}
return decl;
}
tree
dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
tree rval;
unsigned ix;
tree base_binfo;
if (pre_fn)
{
rval = pre_fn (binfo, data);
if (rval)
{
if (rval == dfs_skip_bases)
goto skip_bases;
return rval;
}
}
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
rval = dfs_walk_all (base_binfo, pre_fn, post_fn, data);
if (rval)
return rval;
}
skip_bases:
if (post_fn)
{
rval = post_fn (binfo, data);
gcc_assert (rval != dfs_skip_bases);
return rval;
}
return NULL_TREE;
}
static tree
dfs_walk_once_r (tree binfo, tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
tree rval;
unsigned ix;
tree base_binfo;
if (pre_fn)
{
rval = pre_fn (binfo, data);
if (rval)
{
if (rval == dfs_skip_bases)
goto skip_bases;
return rval;
}
}
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
if (BINFO_VIRTUAL_P (base_binfo))
{
if (BINFO_MARKED (base_binfo))
continue;
BINFO_MARKED (base_binfo) = 1;
}
rval = dfs_walk_once_r (base_binfo, pre_fn, post_fn, data);
if (rval)
return rval;
}
skip_bases:
if (post_fn)
{
rval = post_fn (binfo, data);
gcc_assert (rval != dfs_skip_bases);
return rval;
}
return NULL_TREE;
}
static void
dfs_unmark_r (tree binfo)
{
unsigned ix;
tree base_binfo;
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
if (BINFO_VIRTUAL_P (base_binfo))
{
if (!BINFO_MARKED (base_binfo))
continue;
BINFO_MARKED (base_binfo) = 0;
}
if (CLASSTYPE_VBASECLASSES (BINFO_TYPE (base_binfo)))
dfs_unmark_r (base_binfo);
}
}
tree
dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
static int active = 0;
tree rval;
gcc_assert (pre_fn || post_fn);
gcc_assert (!active);
active++;
if (!CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo)))
rval = dfs_walk_all (binfo, pre_fn, post_fn, data);
else
{
rval = dfs_walk_once_r (binfo, pre_fn, post_fn, data);
if (!BINFO_INHERITANCE_CHAIN (binfo))
{
VEC(tree,gc) *vbases;
unsigned ix;
tree base_binfo;
for (vbases = CLASSTYPE_VBASECLASSES (BINFO_TYPE (binfo)), ix = 0;
VEC_iterate (tree, vbases, ix, base_binfo); ix++)
BINFO_MARKED (base_binfo) = 0;
}
else
dfs_unmark_r (binfo);
}
active--;
return rval;
}
static tree
dfs_walk_once_accessible_r (tree binfo, bool friends_p, bool once,
tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
tree rval = NULL_TREE;
unsigned ix;
tree base_binfo;
if (pre_fn)
{
rval = pre_fn (binfo, data);
if (rval)
{
if (rval == dfs_skip_bases)
goto skip_bases;
return rval;
}
}
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
bool mark = once && BINFO_VIRTUAL_P (base_binfo);
if (mark && BINFO_MARKED (base_binfo))
continue;
if (BINFO_BASE_ACCESS (binfo, ix) != access_public_node)
{
tree scope;
if (!friends_p)
continue;
scope = current_scope ();
if (!scope
|| TREE_CODE (scope) == NAMESPACE_DECL
|| !is_friend (BINFO_TYPE (binfo), scope))
continue;
}
if (mark)
BINFO_MARKED (base_binfo) = 1;
rval = dfs_walk_once_accessible_r (base_binfo, friends_p, once,
pre_fn, post_fn, data);
if (rval)
return rval;
}
skip_bases:
if (post_fn)
{
rval = post_fn (binfo, data);
gcc_assert (rval != dfs_skip_bases);
return rval;
}
return NULL_TREE;
}
static tree
dfs_walk_once_accessible (tree binfo, bool friends_p,
tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
bool diamond_shaped = CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo));
tree rval = dfs_walk_once_accessible_r (binfo, friends_p, diamond_shaped,
pre_fn, post_fn, data);
if (diamond_shaped)
{
if (!BINFO_INHERITANCE_CHAIN (binfo))
{
VEC(tree,gc) *vbases;
unsigned ix;
tree base_binfo;
for (vbases = CLASSTYPE_VBASECLASSES (BINFO_TYPE (binfo)), ix = 0;
VEC_iterate (tree, vbases, ix, base_binfo); ix++)
BINFO_MARKED (base_binfo) = 0;
}
else
dfs_unmark_r (binfo);
}
return rval;
}
static 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
{
warning (0, "deprecated covariant return type for %q+#D",
overrider);
warning (0, " overriding %q+#D", basefn);
}
}
else
fail = 2;
}
else
fail = 2;
if (!fail)
;
else
{
if (fail == 1)
{
error ("invalid covariant return type for %q+#D", overrider);
error (" overriding %q+#D", basefn);
}
else
{
error ("conflicting return type specified for %q+#D", overrider);
error (" overriding %q+#D", basefn);
}
DECL_INVALID_OVERRIDER_P (overrider) = 1;
return 0;
}
if (!comp_except_specs (base_throw, over_throw, 0))
{
error ("looser throw specifier for %q+#F", overrider);
error (" overriding %q+#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 base_binfo;
int ix;
int found = 0;
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
tree basetype = BINFO_TYPE (base_binfo);
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 (!CLASSTYPE_METHOD_VEC (type))
return NULL_TREE;
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 = VEC_index (tree, 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))
{
error ("%q+#D cannot be declared", fndecl);
error (" since %q+#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)))
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (type),
BV_FN (virtuals));
}
return NULL_TREE;
}
void
get_pure_virtuals (tree type)
{
CLASSTYPE_PURE_VIRTUALS (type) = NULL;
dfs_walk_once (TYPE_BINFO (type), NULL, dfs_get_pure_virtuals, type);
}
void
maybe_suppress_debug_info (tree t)
{
if (write_symbols == NO_DEBUG)
return;
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
if (flag_emit_class_debug_always)
return;
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);
if (CLASSTYPE_DEBUG_REQUESTED (t))
return dfs_skip_bases;
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
return 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;
cp_set_decl_ignore_flag (type, 1);
rest_of_type_compilation (type, toplevel_bindings_p ());
cp_set_decl_ignore_flag (type, 0);
}
dfs_walk_all (TYPE_BINFO (type), dfs_debug_mark, NULL, 0);
}
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
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 int
check_hidden_convs (tree binfo, int virtual_depth, int virtualness,
tree to_type, tree parent_convs, tree other_convs)
{
tree level, probe;
for (level = parent_convs; level; level = TREE_CHAIN (level))
for (probe = TREE_VALUE (level); probe; probe = TREE_CHAIN (probe))
if (same_type_p (to_type, TREE_TYPE (probe)))
return 0;
if (virtual_depth || virtualness)
{
for (level = other_convs; level; level = TREE_CHAIN (level))
{
int we_hide_them;
int they_hide_us;
tree *prev, other;
if (!(virtual_depth || TREE_STATIC (level)))
continue;
if (!TREE_VALUE (level))
continue;
they_hide_us = (virtual_depth
&& original_binfo (binfo, TREE_PURPOSE (level)));
we_hide_them = (!they_hide_us && TREE_STATIC (level)
&& original_binfo (TREE_PURPOSE (level), binfo));
if (!(we_hide_them || they_hide_us))
continue;
for (prev = &TREE_VALUE (level), other = *prev; other;)
{
if (same_type_p (to_type, TREE_TYPE (other)))
{
if (they_hide_us)
return 0;
if (we_hide_them)
{
other = TREE_CHAIN (other);
*prev = other;
continue;
}
}
prev = &TREE_CHAIN (other);
other = *prev;
}
}
}
return 1;
}
static tree
split_conversions (tree my_convs, tree parent_convs,
tree child_convs, tree other_convs)
{
tree t;
tree prev;
for (prev = NULL, t = child_convs;
t != other_convs; prev = t, t = TREE_CHAIN (t))
continue;
if (prev)
TREE_CHAIN (prev) = NULL_TREE;
else
child_convs = NULL_TREE;
if (my_convs)
{
my_convs = parent_convs;
TREE_CHAIN (my_convs) = child_convs;
}
else
my_convs = child_convs;
return my_convs;
}
static int
lookup_conversions_r (tree binfo,
int virtual_depth, int virtualness,
tree parent_convs, tree parent_tpl_convs,
tree other_convs, tree other_tpl_convs,
tree *convs, tree *tpl_convs)
{
int my_virtualness = 0;
tree my_convs = NULL_TREE;
tree my_tpl_convs = NULL_TREE;
tree child_convs = NULL_TREE;
tree child_tpl_convs = NULL_TREE;
unsigned i;
tree base_binfo;
VEC(tree,gc) *method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
tree conv;
if (!TYPE_HAS_CONVERSION (BINFO_TYPE (binfo)))
{
*convs = *tpl_convs = NULL_TREE;
return 0;
}
if (BINFO_VIRTUAL_P (binfo))
virtual_depth++;
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
VEC_iterate (tree, method_vec, i, conv);
++i)
{
tree cur = OVL_CURRENT (conv);
if (!DECL_CONV_FN_P (cur))
break;
if (TREE_CODE (cur) == TEMPLATE_DECL)
{
tree tpls;
for (tpls = conv; tpls; tpls = OVL_NEXT (tpls))
{
tree tpl = OVL_CURRENT (tpls);
tree type = DECL_CONV_FN_TYPE (tpl);
if (check_hidden_convs (binfo, virtual_depth, virtualness,
type, parent_tpl_convs, other_tpl_convs))
{
my_tpl_convs = tree_cons (binfo, tpl, my_tpl_convs);
TREE_TYPE (my_tpl_convs) = type;
if (virtual_depth)
{
TREE_STATIC (my_tpl_convs) = 1;
my_virtualness = 1;
}
}
}
}
else
{
tree name = DECL_NAME (cur);
if (!IDENTIFIER_MARKED (name))
{
tree type = DECL_CONV_FN_TYPE (cur);
if (check_hidden_convs (binfo, virtual_depth, virtualness,
type, parent_convs, other_convs))
{
my_convs = tree_cons (binfo, conv, my_convs);
TREE_TYPE (my_convs) = type;
if (virtual_depth)
{
TREE_STATIC (my_convs) = 1;
my_virtualness = 1;
}
IDENTIFIER_MARKED (name) = 1;
}
}
}
}
if (my_convs)
{
parent_convs = tree_cons (binfo, my_convs, parent_convs);
if (virtual_depth)
TREE_STATIC (parent_convs) = 1;
}
if (my_tpl_convs)
{
parent_tpl_convs = tree_cons (binfo, my_tpl_convs, parent_tpl_convs);
if (virtual_depth)
TREE_STATIC (parent_tpl_convs) = 1;
}
child_convs = other_convs;
child_tpl_convs = other_tpl_convs;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
tree base_convs, base_tpl_convs;
unsigned base_virtualness;
base_virtualness = lookup_conversions_r (base_binfo,
virtual_depth, virtualness,
parent_convs, parent_tpl_convs,
child_convs, child_tpl_convs,
&base_convs, &base_tpl_convs);
if (base_virtualness)
my_virtualness = virtualness = 1;
child_convs = chainon (base_convs, child_convs);
child_tpl_convs = chainon (base_tpl_convs, child_tpl_convs);
}
for (conv = my_convs; conv; conv = TREE_CHAIN (conv))
IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (conv)))) = 0;
*convs = split_conversions (my_convs, parent_convs,
child_convs, other_convs);
*tpl_convs = split_conversions (my_tpl_convs, parent_tpl_convs,
child_tpl_convs, other_tpl_convs);
return my_virtualness;
}
tree
lookup_conversions (tree type)
{
tree convs, tpl_convs;
tree list = NULL_TREE;
complete_type (type);
if (!TYPE_BINFO (type))
return NULL_TREE;
lookup_conversions_r (TYPE_BINFO (type), 0, 0,
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
&convs, &tpl_convs);
for (; convs; convs = TREE_CHAIN (convs))
{
tree probe, next;
for (probe = TREE_VALUE (convs); probe; probe = next)
{
next = TREE_CHAIN (probe);
TREE_CHAIN (probe) = list;
list = probe;
}
}
for (; tpl_convs; tpl_convs = TREE_CHAIN (tpl_convs))
{
tree probe, next;
for (probe = TREE_VALUE (tpl_convs); probe; probe = next)
{
next = TREE_CHAIN (probe);
TREE_CHAIN (probe) = list;
list = probe;
}
}
return list;
}
tree
binfo_from_vbase (tree binfo)
{
for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (BINFO_VIRTUAL_P (binfo))
return binfo;
}
return NULL_TREE;
}
tree
binfo_via_virtual (tree binfo, tree limit)
{
if (limit && !CLASSTYPE_VBASECLASSES (limit))
return NULL_TREE;
for (; binfo && !SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), limit);
binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (BINFO_VIRTUAL_P (binfo))
return binfo;
}
return NULL_TREE;
}
tree
copied_binfo (tree binfo, tree here)
{
tree result = NULL_TREE;
if (BINFO_VIRTUAL_P (binfo))
{
tree t;
for (t = here; BINFO_INHERITANCE_CHAIN (t);
t = BINFO_INHERITANCE_CHAIN (t))
continue;
result = binfo_for_vbase (BINFO_TYPE (binfo), BINFO_TYPE (t));
}
else if (BINFO_INHERITANCE_CHAIN (binfo))
{
tree cbinfo;
tree base_binfo;
int ix;
cbinfo = copied_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
for (ix = 0; BINFO_BASE_ITERATE (cbinfo, ix, base_binfo); ix++)
if (SAME_BINFO_TYPE_P (BINFO_TYPE (base_binfo), BINFO_TYPE (binfo)))
{
result = base_binfo;
break;
}
}
else
{
gcc_assert (SAME_BINFO_TYPE_P (BINFO_TYPE (here), BINFO_TYPE (binfo)));
result = here;
}
gcc_assert (result);
return result;
}
tree
binfo_for_vbase (tree base, tree t)
{
unsigned ix;
tree binfo;
VEC(tree,gc) *vbases;
for (vbases = CLASSTYPE_VBASECLASSES (t), ix = 0;
VEC_iterate (tree, vbases, ix, binfo); ix++)
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), base))
return binfo;
return NULL;
}
tree
original_binfo (tree binfo, tree here)
{
tree result = NULL;
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), BINFO_TYPE (here)))
result = here;
else if (BINFO_VIRTUAL_P (binfo))
result = (CLASSTYPE_VBASECLASSES (BINFO_TYPE (here))
? binfo_for_vbase (BINFO_TYPE (binfo), BINFO_TYPE (here))
: NULL_TREE);
else if (BINFO_INHERITANCE_CHAIN (binfo))
{
tree base_binfos;
base_binfos = original_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
if (base_binfos)
{
int ix;
tree base_binfo;
for (ix = 0; (base_binfo = BINFO_BASE_BINFO (base_binfos, ix)); ix++)
if (SAME_BINFO_TYPE_P (BINFO_TYPE (base_binfo),
BINFO_TYPE (binfo)))
{
result = base_binfo;
break;
}
}
}
return result;
}