#include "config.h"
#include "system.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 (obstack, tp, size)
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 (stack)
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 lookup_field_1 PARAMS ((tree, tree));
static int is_subobject_of_p PARAMS ((tree, tree, tree));
static int is_subobject_of_p_1 PARAMS ((tree, tree, tree));
static tree dfs_check_overlap PARAMS ((tree, void *));
static tree dfs_no_overlap_yet PARAMS ((tree, void *));
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 *));
static tree dfs_debug_unmarkedp PARAMS ((tree, void *));
static tree dfs_debug_mark PARAMS ((tree, void *));
static tree dfs_get_vbase_types PARAMS ((tree, void *));
static tree dfs_push_type_decls PARAMS ((tree, void *));
static tree dfs_push_decls PARAMS ((tree, void *));
static tree dfs_unuse_fields PARAMS ((tree, void *));
static tree add_conversions PARAMS ((tree, void *));
static int covariant_return_p PARAMS ((tree, tree));
static int look_for_overrides_r PARAMS ((tree, tree));
static struct search_level *push_search_level
PARAMS ((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level
PARAMS ((struct stack_level *));
static tree bfs_walk
PARAMS ((tree, tree (*) (tree, void *), tree (*) (tree, void *),
void *));
static tree lookup_field_queue_p PARAMS ((tree, void *));
static int shared_member_p PARAMS ((tree));
static tree lookup_field_r PARAMS ((tree, void *));
static tree canonical_binfo PARAMS ((tree));
static tree shared_marked_p PARAMS ((tree, void *));
static tree shared_unmarked_p PARAMS ((tree, void *));
static int dependent_base_p PARAMS ((tree));
static tree dfs_accessible_queue_p PARAMS ((tree, void *));
static tree dfs_accessible_p PARAMS ((tree, void *));
static tree dfs_access_in_type PARAMS ((tree, void *));
static access_kind access_in_type PARAMS ((tree, tree));
static tree dfs_canonical_queue PARAMS ((tree, void *));
static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
static void assert_canonical_unmarked PARAMS ((tree));
static int protected_accessible_p PARAMS ((tree, tree, tree));
static int friend_accessible_p PARAMS ((tree, tree, tree));
static void setup_class_bindings PARAMS ((tree, int));
static int template_self_reference_p PARAMS ((tree, tree));
static tree dfs_find_vbase_instance PARAMS ((tree, void *));
static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
static tree dfs_build_inheritance_graph_order PARAMS ((tree, void *));
static struct search_level *
push_search_level (stack, obstack)
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 (obstack)
struct stack_level *obstack;
{
register 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 (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;
int is_virtual;
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;
}
if (same_type_p (BINFO_TYPE (binfo), base))
{
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 (!is_virtual)
*binfo_ptr = binfo;
found = bk_ambig;
}
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;
base_kind bk;
if (access <= ba_ignore)
;
else if (TREE_VIA_PUBLIC (base_binfo))
;
else if (access == ba_not_special)
this_non_public = 1;
else if (TREE_VIA_PROTECTED (base_binfo) && within_current_scope)
;
else if (is_friend (BINFO_TYPE (binfo), current_scope ()))
;
else
this_non_public = 1;
if (TREE_VIA_VIRTUAL (base_binfo))
this_virtual = 1;
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;
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;
}
}
return found;
}
tree
lookup_base (t, base, access, kind_ptr)
tree t, 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 & ~ba_quiet,
0, 0, 0, &binfo);
switch (bk)
{
case bk_inaccessible:
binfo = NULL_TREE;
if (!(access & ba_quiet))
{
error ("`%T' is an inaccessible base of `%T'", base, t);
binfo = error_mark_node;
}
break;
case bk_ambig:
if (access != ba_any)
{
binfo = NULL_TREE;
if (!(access & ba_quiet))
{
error ("`%T' is an ambiguous base of `%T'", base, t);
binfo = error_mark_node;
}
}
break;
default:;
}
if (kind_ptr)
*kind_ptr = bk;
return binfo;
}
static int
dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
tree subtype;
tree binfo;
int via_virtual;
tree *offset_ptr;
{
tree binfos;
int i, n_baselinks;
int worst = -2;
if (BINFO_TYPE (binfo) == subtype)
{
if (via_virtual)
return -1;
else
{
*offset_ptr = BINFO_OFFSET (binfo);
return 0;
}
}
binfos = BINFO_BASETYPES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int rval;
if (!TREE_VIA_PUBLIC (base_binfo))
continue;
rval = dynamic_cast_base_recurse
(subtype, base_binfo,
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 (subtype, target)
tree subtype;
tree target;
{
tree offset = NULL_TREE;
int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
0, &offset);
if (!boff)
return offset;
offset = build_int_2 (boff, -1);
TREE_TYPE (offset) = ssizetype;
return offset;
}
static tree
lookup_field_1 (type, name)
tree type, name;
{
register 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 = &TREE_VEC_ELT (DECL_SORTED_FIELDS (TYPE_NAME (type)), 0);
int lo = 0, hi = TREE_VEC_LENGTH (DECL_SORTED_FIELDS (TYPE_NAME (type)));
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
{
while (i + 1 < hi
&& DECL_NAME (fields[i+1]) == name)
++i;
return fields[i];
}
}
return NULL_TREE;
}
field = TYPE_FIELDS (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field_1++;
#endif
while (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);
if (temp)
return temp;
}
if (TREE_CODE (field) == USING_DECL)
;
else if (DECL_NAME (field) == name)
return field;
field = TREE_CHAIN (field);
}
if (name == vptr_identifier)
{
if (TYPE_POLYMORPHIC_P (type))
return TYPE_VFIELD (type);
}
return NULL_TREE;
}
tree
current_scope ()
{
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 ()
{
tree cs = current_scope ();
return cs && TREE_CODE (cs) == FUNCTION_DECL;
}
bool
at_class_scope_p ()
{
tree cs = current_scope ();
return cs && TYPE_P (cs);
}
tree
context_for_name_lookup (decl)
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;
}
static tree
canonical_binfo (binfo)
tree binfo;
{
return (TREE_VIA_VIRTUAL (binfo)
? TYPE_BINFO (BINFO_TYPE (binfo)) : binfo);
}
static tree
dfs_canonical_queue (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return canonical_binfo (binfo);
}
static tree
dfs_assert_unmarked_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
my_friendly_assert (!BINFO_MARKED (binfo), 0);
return NULL_TREE;
}
static void
assert_canonical_unmarked (binfo)
tree binfo;
{
dfs_walk (binfo, dfs_assert_unmarked_p, dfs_canonical_queue, 0);
}
static tree
shared_marked_p (binfo, data)
tree binfo;
void *data;
{
binfo = canonical_binfo (binfo);
return markedp (binfo, data);
}
static tree
shared_unmarked_p (binfo, data)
tree binfo;
void *data;
{
binfo = canonical_binfo (binfo);
return unmarkedp (binfo, data);
}
#define BINFO_ACCESS(NODE) \
((access_kind) ((TREE_LANG_FLAG_1 (NODE) << 1) | TREE_LANG_FLAG_6 (NODE)))
#define SET_BINFO_ACCESS(NODE, ACCESS) \
((TREE_LANG_FLAG_1 (NODE) = ((ACCESS) & 2) != 0), \
(TREE_LANG_FLAG_6 (NODE) = ((ACCESS) & 1) != 0))
static tree
dfs_access_in_type (binfo, data)
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)
access = ((access_kind)
TREE_INT_CST_LOW (TREE_VALUE (decl_access)));
}
if (!access)
{
int i;
int n_baselinks;
tree binfos;
binfos = BINFO_BASETYPES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; ++i)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
access_kind base_access
= BINFO_ACCESS (canonical_binfo (base_binfo));
if (base_access == ak_none || base_access == ak_private)
base_access = ak_none;
else if (TREE_VIA_PROTECTED (base_binfo))
base_access = ak_protected;
else if (!TREE_VIA_PUBLIC (base_binfo))
base_access = ak_private;
if (base_access != ak_none
&& (base_access == ak_public
|| (base_access == ak_protected
&& access != ak_public)
|| (base_access == ak_private
&& access == ak_none)))
{
access = base_access;
if (access == ak_public)
break;
}
}
}
}
SET_BINFO_ACCESS (binfo, access);
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
static access_kind
access_in_type (type, decl)
tree type;
tree decl;
{
tree binfo = TYPE_BINFO (type);
dfs_walk_real (binfo, 0, dfs_access_in_type, shared_unmarked_p, decl);
dfs_walk (binfo, dfs_unmark, shared_marked_p, 0);
assert_canonical_unmarked (binfo);
return BINFO_ACCESS (binfo);
}
static tree
dfs_accessible_queue_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
if (BINFO_MARKED (binfo))
return NULL_TREE;
if (!TREE_VIA_PUBLIC (binfo)
&& !is_friend (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
current_scope ()))
return NULL_TREE;
return canonical_binfo (binfo);
}
static tree
dfs_accessible_p (binfo, data)
tree binfo;
void *data;
{
int protected_ok = data != 0;
access_kind access;
SET_BINFO_MARKED (binfo);
access = BINFO_ACCESS (binfo);
if (access == ak_public || (access == ak_protected && protected_ok))
return binfo;
else if (access != ak_none
&& is_friend (BINFO_TYPE (binfo), current_scope ()))
return binfo;
return NULL_TREE;
}
static int
protected_accessible_p (decl, derived, binfo)
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 (scope, decl, binfo)
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;
}
void
type_access_control (type, val)
tree type, val;
{
if (val == NULL_TREE
|| (TREE_CODE (val) != TEMPLATE_DECL && TREE_CODE (val) != TYPE_DECL)
|| ! DECL_CLASS_SCOPE_P (val)
|| processing_specialization)
return;
if (type_lookups == error_mark_node)
enforce_access (type, val);
else if (! accessible_p (type, val))
type_lookups = tree_cons (type, val, type_lookups);
}
int
accessible_p (type, decl)
tree type;
tree decl;
{
tree binfo;
tree t;
int protected_ok = 0;
if (!flag_access_control)
return 1;
if (!TYPE_P (context_for_name_lookup (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 (current_scope (), decl, binfo);
binfo = TYPE_BINFO (type);
access_in_type (type, decl);
t = dfs_walk (binfo, dfs_accessible_p,
dfs_accessible_queue_p,
protected_ok ? &protected_ok : 0);
dfs_walk (binfo, dfs_unmark, dfs_canonical_queue, 0);
assert_canonical_unmarked (binfo);
return t != NULL_TREE;
}
static int
is_subobject_of_p_1 (parent, binfo, most_derived)
tree parent, binfo, most_derived;
{
tree binfos;
int i, n_baselinks;
if (parent == binfo)
return 1;
binfos = BINFO_BASETYPES (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_type;
base_type = TREE_TYPE (base_binfo);
if (!CLASS_TYPE_P (base_type))
continue;
if (TREE_VIA_VIRTUAL (base_binfo))
{
if (CLASSTYPE_MARKED4 (base_type))
continue;
SET_CLASSTYPE_MARKED4 (base_type);
base_binfo = binfo_for_vbase (base_type, most_derived);
}
if (is_subobject_of_p_1 (parent, base_binfo, most_derived))
return 1;
}
return 0;
}
static int
is_subobject_of_p (tree parent, tree binfo, tree most_derived)
{
int result;
tree vbase;
result = is_subobject_of_p_1 (parent, binfo, most_derived);
for (vbase = CLASSTYPE_VBASECLASSES (most_derived);
vbase;
vbase = TREE_CHAIN (vbase))
CLEAR_CLASSTYPE_MARKED4 (TREE_TYPE (TREE_VALUE (vbase)));
return result;
}
struct lookup_field_info {
tree type;
tree name;
tree rval;
tree rval_binfo;
tree ambiguous;
int want_type;
int from_dep_base_p;
const char *errstr;
};
static tree
lookup_field_queue_p (binfo, data)
tree binfo;
void *data;
{
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))
return NULL_TREE;
binfo = CANONICAL_BINFO (binfo, lfi->type);
if (!lfi->from_dep_base_p && lfi->rval_binfo
&& is_subobject_of_p (binfo, lfi->rval_binfo, lfi->type))
return NULL_TREE;
return binfo;
}
static int
template_self_reference_p (type, decl)
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 (t)
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 (binfo, data)
tree binfo;
void *data;
{
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
tree type = BINFO_TYPE (binfo);
tree nval = NULL_TREE;
int from_dep_base_p;
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);
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)
{
nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
if (nval)
nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
else
return NULL_TREE;
}
}
if (!same_type_p (type, lfi->type)
&& template_self_reference_p (type, nval))
return NULL_TREE;
from_dep_base_p = dependent_base_p (binfo);
if (lfi->from_dep_base_p && !from_dep_base_p)
{
lfi->from_dep_base_p = 0;
lfi->rval = NULL_TREE;
lfi->rval_binfo = NULL_TREE;
lfi->ambiguous = NULL_TREE;
lfi->errstr = 0;
}
else if (lfi->rval_binfo && !lfi->from_dep_base_p && from_dep_base_p)
return NULL_TREE;
if (lfi->rval_binfo && !is_subobject_of_p (lfi->rval_binfo, binfo, lfi->type))
{
if (nval == lfi->rval && shared_member_p (nval))
;
else if (is_subobject_of_p (binfo, lfi->rval_binfo, lfi->type))
;
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
{
if (from_dep_base_p && TREE_CODE (nval) != TYPE_DECL
&& !DECL_CLASS_TEMPLATE_P (nval))
return NULL_TREE;
lfi->rval = nval;
lfi->from_dep_base_p = from_dep_base_p;
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 = build (BASELINK, TREE_TYPE (functions), NULL_TREE,
NULL_TREE, NULL_TREE);
BASELINK_BINFO (baselink) = binfo;
BASELINK_ACCESS_BINFO (baselink) = access_binfo;
BASELINK_FUNCTIONS (baselink) = functions;
BASELINK_OPTYPE (baselink) = optype;
return baselink;
}
tree
lookup_member (xbasetype, name, protect, want_type)
register tree xbasetype, name;
int protect, 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;
if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
&& IDENTIFIER_CLASS_VALUE (name))
{
tree field = IDENTIFIER_CLASS_VALUE (name);
if (TREE_CODE (field) != FUNCTION_DECL
&& ! (want_type && TREE_CODE (field) != TYPE_DECL))
return field;
}
if (TREE_CODE (xbasetype) == TREE_VEC)
{
type = BINFO_TYPE (xbasetype);
basetype_path = xbasetype;
}
else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
{
type = xbasetype;
basetype_path = TYPE_BINFO (type);
my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
980827);
}
else
abort ();
complete_type (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
#endif
memset ((PTR) &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)
&& !enforce_access (xbasetype, rval))
return error_mark_node;
if (errstr && protect)
{
error (errstr, name, type);
if (lfi.ambiguous)
print_candidates (lfi.ambiguous);
rval = error_mark_node;
}
if (rval && lfi.from_dep_base_p && !DECL_CLASS_TEMPLATE_P (rval))
rval = TYPE_STUB_DECL (build_typename_type (BINFO_TYPE (basetype_path),
name, name,
TREE_TYPE (rval)));
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 (xbasetype, name, protect, want_type)
register tree xbasetype, name;
int protect, want_type;
{
tree rval = lookup_member (xbasetype, name, protect, want_type);
if (rval && BASELINK_P (rval))
return NULL_TREE;
return rval;
}
tree
lookup_fnfields (xbasetype, name, protect)
register tree xbasetype, name;
int protect;
{
tree rval = lookup_member (xbasetype, name, protect, 0);
if (rval && !BASELINK_P (rval))
return NULL_TREE;
return rval;
}
tree
lookup_nested_field (name, complain)
tree name;
int complain;
{
register tree t;
tree id = NULL_TREE;
if (TYPE_MAIN_DECL (current_class_type))
{
for (t = TYPE_MAIN_DECL (current_class_type);
t && DECL_CONTEXT (t);
t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
{
if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
break;
id = lookup_field (DECL_CONTEXT (t), name, complain, 0);
if (id == error_mark_node)
{
id = NULL_TREE;
continue;
}
if (id != NULL_TREE)
{
if (TREE_CODE (id) == FIELD_DECL
&& ! TREE_STATIC (id)
&& TREE_TYPE (id) != error_mark_node)
{
if (complain)
{
error ("assignment to non-static member `%D' of enclosing class `%T'",
id, DECL_CONTEXT (t));
TREE_TYPE (id) = error_mark_node;
}
else
{
id = NULL_TREE;
continue;
}
}
break;
}
}
}
return id;
}
int
lookup_fnfields_1 (type, name)
tree type, name;
{
tree method_vec = (CLASS_TYPE_P (type)
? CLASSTYPE_METHOD_VEC (type)
: NULL_TREE);
if (method_vec != 0)
{
register int i;
register tree *methods = &TREE_VEC_ELT (method_vec, 0);
int len = TREE_VEC_LENGTH (method_vec);
tree tmp;
#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);
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
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;
if (! DECL_CONV_FN_P (tmp)
&& COMPLETE_TYPE_P (type))
{
int lo = i + 1, hi = len;
while (lo < hi)
{
i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
tmp = DECL_NAME (OVL_CURRENT (methods[i]));
if (tmp > name)
hi = i;
else if (tmp < name)
lo = i + 1;
else
return i;
}
break;
}
}
if (IDENTIFIER_TYPENAME_P (name))
{
i = CLASSTYPE_FIRST_CONVERSION_SLOT;
if (i < len && methods[i])
{
tmp = OVL_CURRENT (methods[i]);
if (TREE_CODE (tmp) == TEMPLATE_DECL
&& DECL_TEMPLATE_CONV_FN_P (tmp))
return i;
}
}
}
return -1;
}
tree
adjust_result_of_qualified_name_lookup (tree decl,
tree qualifying_class,
tree context_class)
{
my_friendly_assert (CLASS_TYPE_P (qualifying_class), 20020808);
my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
if (BASELINK_P (decl)
&& DERIVED_FROM_P (qualifying_class, context_class))
{
tree base;
base = lookup_base (context_class, qualifying_class,
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;
}
static tree
bfs_walk (binfo, fn, qfn, data)
tree binfo;
tree (*fn) PARAMS ((tree, void *));
tree (*qfn) PARAMS ((tree, void *));
void *data;
{
size_t head;
size_t tail;
tree rval = NULL_TREE;
varray_type bfs_bases;
VARRAY_TREE_INIT (bfs_bases, 10, "search_stack");
VARRAY_TREE (bfs_bases, 0) = binfo;
tail = 1;
for (head = 0; head < tail; ++head)
{
int i;
int n_baselinks;
tree binfos;
binfo = VARRAY_TREE (bfs_bases, head);
rval = (*fn) (binfo, data);
if (rval)
break;
binfos = BINFO_BASETYPES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (qfn)
base_binfo = (*qfn) (base_binfo, data);
if (base_binfo)
{
if (tail == VARRAY_SIZE (bfs_bases))
VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
VARRAY_TREE (bfs_bases, tail) = base_binfo;
++tail;
}
}
}
return rval;
}
tree
dfs_walk_real (binfo, prefn, postfn, qfn, data)
tree binfo;
tree (*prefn) PARAMS ((tree, void *));
tree (*postfn) PARAMS ((tree, void *));
tree (*qfn) PARAMS ((tree, void *));
void *data;
{
int i;
int n_baselinks;
tree binfos;
tree rval = NULL_TREE;
if (prefn)
{
rval = (*prefn) (binfo, data);
if (rval)
return rval;
}
binfos = BINFO_BASETYPES (binfo);
n_baselinks = BINFO_N_BASETYPES (binfo);
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (qfn)
base_binfo = (*qfn) (base_binfo, data);
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 (binfo, fn, qfn, data)
tree binfo;
tree (*fn) PARAMS ((tree, void *));
tree (*qfn) PARAMS ((tree, void *));
void *data;
{
return dfs_walk_real (binfo, 0, fn, qfn, data);
}
static int
covariant_return_p (brettype, drettype)
tree brettype, drettype;
{
tree binfo;
base_kind kind;
if (TREE_CODE (brettype) == FUNCTION_DECL)
{
brettype = TREE_TYPE (TREE_TYPE (brettype));
drettype = TREE_TYPE (TREE_TYPE (drettype));
}
else if (TREE_CODE (brettype) == METHOD_TYPE)
{
brettype = TREE_TYPE (brettype);
drettype = TREE_TYPE (drettype);
}
if (same_type_p (brettype, drettype))
return 0;
if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
&& (TREE_CODE (brettype) == POINTER_TYPE
|| TREE_CODE (brettype) == REFERENCE_TYPE)
&& TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
return 0;
if (! can_convert (brettype, drettype))
return 0;
brettype = TREE_TYPE (brettype);
drettype = TREE_TYPE (drettype);
if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
return -1;
binfo = lookup_base (drettype, brettype, ba_check | ba_quiet, &kind);
if (!binfo)
return 0;
if (BINFO_OFFSET_ZEROP (binfo) && kind != bk_via_virtual)
return 1;
return 2;
}
int
check_final_overrider (overrider, basefn)
tree overrider, 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 i;
if (same_type_p (base_return, over_return))
;
else if ((i = covariant_return_p (base_return, over_return)))
{
if (i == 2)
sorry ("adjusting pointers for covariant returns");
if (pedantic && i == -1)
{
cp_pedwarn_at ("invalid covariant return type for `%#D'", overrider);
cp_pedwarn_at (" overriding `%#D' (must be pointer or reference to class)", basefn);
}
}
else if (IS_AGGR_TYPE_2 (base_return, over_return)
&& same_or_base_type_p (base_return, over_return))
{
cp_error_at ("invalid covariant return type for `%#D'", overrider);
cp_error_at (" overriding `%#D' (must use pointer or reference)", basefn);
return 0;
}
else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
{
cp_error_at ("conflicting return type specified for `%#D'", overrider);
cp_error_at (" overriding `%#D'", basefn);
SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
DECL_CONTEXT (overrider));
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);
return 0;
}
return 1;
}
int
look_for_overrides (type, fndecl)
tree type, 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 (type, fndecl)
tree type, 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 (type, fndecl)
tree type, 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);
}
tree
dfs_unmarked_real_bases_queue_p (binfo, data)
tree binfo;
void *data;
{
if (TREE_VIA_VIRTUAL (binfo))
{
tree type = (tree) data;
if (TREE_CODE (type) == TREE_LIST)
type = TREE_PURPOSE (type);
binfo = binfo_for_vbase (BINFO_TYPE (binfo), type);
}
return unmarkedp (binfo, NULL);
}
tree
dfs_marked_real_bases_queue_p (binfo, data)
tree binfo;
void *data;
{
if (TREE_VIA_VIRTUAL (binfo))
{
tree type = (tree) data;
if (TREE_CODE (type) == TREE_LIST)
type = TREE_PURPOSE (type);
binfo = binfo_for_vbase (BINFO_TYPE (binfo), type);
}
return markedp (binfo, NULL);
}
tree
dfs_skip_vbases (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
if (TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
return binfo;
}
static tree
dfs_get_pure_virtuals (binfo, data)
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));
}
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
void
get_pure_virtuals (type)
tree type;
{
tree vbases;
CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;
dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals,
dfs_unmarked_real_bases_queue_p, type);
dfs_walk (TYPE_BINFO (type), dfs_unmark,
dfs_marked_real_bases_queue_p, 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 (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
tree
unmarkedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
tree
marked_vtable_pathp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
}
tree
unmarked_vtable_pathp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return !BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
marked_pushdecls_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return (CLASS_TYPE_P (BINFO_TYPE (binfo))
&& BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
static tree
unmarked_pushdecls_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return (CLASS_TYPE_P (BINFO_TYPE (binfo))
&& !BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
tree
dfs_unmark (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
CLEAR_BINFO_MARKED (binfo);
return NULL_TREE;
}
static tree
dfs_get_vbase_types (binfo, data)
tree binfo;
void *data;
{
tree type = (tree) data;
if (TREE_VIA_VIRTUAL (binfo))
CLASSTYPE_VBASECLASSES (type)
= tree_cons (BINFO_TYPE (binfo),
binfo,
CLASSTYPE_VBASECLASSES (type));
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
static tree
dfs_build_inheritance_graph_order (binfo, data)
tree binfo;
void *data;
{
tree *last_binfo = (tree *) data;
if (*last_binfo)
TREE_CHAIN (*last_binfo) = binfo;
*last_binfo = binfo;
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
void
get_vbase_types (type)
tree type;
{
tree last_binfo;
CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, 0);
last_binfo = NULL;
dfs_walk_real (TYPE_BINFO (type),
dfs_build_inheritance_graph_order,
NULL,
unmarkedp,
&last_binfo);
dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, NULL);
}
static tree
dfs_find_vbase_instance (binfo, data)
tree binfo;
void *data;
{
tree base = TREE_VALUE ((tree) data);
if (BINFO_PRIMARY_P (binfo)
&& same_type_p (BINFO_TYPE (binfo), base))
return binfo;
return NULL_TREE;
}
tree
find_vbase_instance (base, type)
tree base;
tree type;
{
tree instance;
instance = binfo_for_vbase (base, type);
if (!BINFO_PRIMARY_P (instance))
return instance;
return dfs_walk (TYPE_BINFO (type),
dfs_find_vbase_instance,
NULL,
build_tree_list (type, base));
}
void
maybe_suppress_debug_info (t)
tree t;
{
if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
return;
if (!flag_debug_only_used_symbols)
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 (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree t = BINFO_TYPE (binfo);
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
return NULL_TREE;
}
static tree
dfs_debug_unmarkedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo))
? binfo : NULL_TREE);
}
void
note_debug_info_needed (type)
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 int
dependent_base_p (binfo)
tree binfo;
{
for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (currently_open_class (TREE_TYPE (binfo)))
break;
if (uses_template_parms (TREE_TYPE (binfo)))
return 1;
}
return 0;
}
static void
setup_class_bindings (name, type_binding_p)
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,
1);
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,
0);
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);
pushdecl_class_level (value_binding);
}
}
}
static tree
dfs_push_type_decls (binfo, data)
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);
SET_BINFO_PUSHDECLS_MARKED (binfo);
return NULL_TREE;
}
static tree
dfs_push_decls (binfo, data)
tree binfo;
void *data;
{
tree type;
tree method_vec;
int dep_base_p;
type = BINFO_TYPE (binfo);
dep_base_p = (processing_template_decl && type != current_class_type
&& dependent_base_p (binfo));
if (!dep_base_p)
{
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);
}
}
CLEAR_BINFO_PUSHDECLS_MARKED (binfo);
return NULL_TREE;
}
void
push_class_decls (type)
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 (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = TREE_TYPE (binfo);
tree fields;
for (fields = TYPE_FIELDS (type); 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 (type)
tree type;
{
dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp, 0);
}
void
pop_class_decls ()
{
if (search_stack)
search_stack = pop_search_level (search_stack);
}
void
print_search_statistics ()
{
#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 ()
{
gcc_obstack_init (&search_obstack);
}
void
reinit_search_statistics ()
{
#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 (binfo, data)
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))
{
*conversions = tree_cons (binfo, tmp, *conversions);
IDENTIFIER_MARKED (name) = 1;
}
}
return NULL_TREE;
}
tree
lookup_conversions (type)
tree type;
{
tree t;
tree conversions = NULL_TREE;
if (COMPLETE_TYPE_P (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 (empty_binfo, data)
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 (binfo, data)
tree binfo;
void *data;
{
struct overlap_info *oi = (struct overlap_info *) data;
return !oi->found_overlap ? binfo : NULL_TREE;
}
int
types_overlap_p (empty_type, next_type)
tree empty_type, 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 (var)
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 (binfo)
tree binfo;
{
for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
if (TREE_VIA_VIRTUAL (binfo))
return binfo;
}
return NULL_TREE;
}
tree
binfo_via_virtual (binfo, limit)
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
binfo_for_vbase (basetype, classtype)
tree basetype;
tree classtype;
{
tree binfo;
binfo = purpose_member (basetype, CLASSTYPE_VBASECLASSES (classtype));
return binfo ? TREE_VALUE (binfo) : NULL_TREE;
}