#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 "varray.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern struct obstack *current_obstack;
extern tree abort_fndecl;
#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;
static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
static tree next_baselink PROTO((tree));
static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
static tree convert_pointer_to_vbase PROTO((tree, tree));
static tree lookup_field_1 PROTO((tree, tree));
static tree convert_pointer_to_single_level PROTO((tree, tree));
static int lookup_fnfields_here PROTO((tree, tree));
static int is_subobject_of_p PROTO((tree, tree));
static int hides PROTO((tree, tree));
static tree virtual_context PROTO((tree, tree, tree));
static tree dfs_check_overlap PROTO((tree, void *));
static tree dfs_no_overlap_yet PROTO((tree, void *));
static int get_base_distance_recursive
PROTO((tree, int, int, int, int *, tree *, tree,
int, int *, int, int));
static void expand_upcast_fixups
PROTO((tree, tree, tree, tree, tree, tree, tree *));
static void fixup_virtual_upcast_offsets
PROTO((tree, tree, int, int, tree, tree, tree, tree,
tree *));
static tree unmarkedp PROTO((tree, void *));
static tree marked_vtable_pathp PROTO((tree, void *));
static tree unmarked_vtable_pathp PROTO((tree, void *));
static tree marked_new_vtablep PROTO((tree, void *));
static tree unmarked_new_vtablep PROTO((tree, void *));
static tree marked_pushdecls_p PROTO((tree, void *));
static tree unmarked_pushdecls_p PROTO((tree, void *));
static tree dfs_debug_unmarkedp PROTO((tree, void *));
static tree dfs_debug_mark PROTO((tree, void *));
static tree dfs_find_vbases PROTO((tree, void *));
static tree dfs_clear_vbase_slots PROTO((tree, void *));
static tree dfs_init_vbase_pointers PROTO((tree, void *));
static tree dfs_get_vbase_types PROTO((tree, void *));
static tree dfs_push_type_decls PROTO((tree, void *));
static tree dfs_push_decls PROTO((tree, void *));
static tree dfs_unuse_fields PROTO((tree, void *));
static tree add_conversions PROTO((tree, void *));
static tree get_virtuals_named_this PROTO((tree, tree));
static tree get_virtual_destructor PROTO((tree, void *));
static tree tree_has_any_destructor_p PROTO((tree, void *));
static int covariant_return_p PROTO((tree, tree));
static struct search_level *push_search_level
PROTO((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level
PROTO((struct stack_level *));
static tree bfs_walk
PROTO((tree, tree (*) (tree, void *), tree (*) (tree, void *),
void *));
static tree lookup_field_queue_p PROTO((tree, void *));
static tree lookup_field_r PROTO((tree, void *));
static tree dfs_walk_real PROTO ((tree,
tree (*) (tree, void *),
tree (*) (tree, void *),
tree (*) (tree, void *),
void *));
static tree dfs_bfv_queue_p PROTO ((tree, void *));
static tree dfs_bfv_helper PROTO ((tree, void *));
static tree get_virtuals_named_this_r PROTO ((tree, void *));
static tree context_for_name_lookup PROTO ((tree));
static tree canonical_binfo PROTO ((tree));
static tree shared_marked_p PROTO ((tree, void *));
static tree shared_unmarked_p PROTO ((tree, void *));
static int dependent_base_p PROTO ((tree));
static tree dfs_accessible_queue_p PROTO ((tree, void *));
static tree dfs_accessible_p PROTO ((tree, void *));
static tree dfs_access_in_type PROTO ((tree, void *));
static tree access_in_type PROTO ((tree, tree));
static tree dfs_canonical_queue PROTO ((tree, void *));
static tree dfs_assert_unmarked_p PROTO ((tree, void *));
static void assert_canonical_unmarked PROTO ((tree));
static int protected_accessible_p PROTO ((tree, tree, tree, tree));
static int friend_accessible_p PROTO ((tree, tree, tree, tree));
static void setup_class_bindings PROTO ((tree, int));
static int template_self_reference_p PROTO ((tree, tree));
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;
}
static tree _vptr_name;
#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 tree
get_vbase_1 (parent, binfo, depth)
tree parent, binfo;
unsigned int *depth;
{
tree binfos;
int i, n_baselinks;
tree rval = NULL_TREE;
if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo))
{
*depth = 0;
return binfo;
}
*depth = *depth - 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 nrval;
if (*depth == 0)
break;
nrval = get_vbase_1 (parent, base_binfo, depth);
if (nrval)
rval = nrval;
}
*depth = *depth+1;
return rval;
}
tree
get_vbase (parent, binfo)
tree parent;
tree binfo;
{
unsigned int d = (unsigned int)-1;
return get_vbase_1 (parent, binfo, &d);
}
static tree
convert_pointer_to_vbase (type, expr)
tree type;
tree expr;
{
tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
return convert_pointer_to_real (vb, expr);
}
tree
get_binfo (parent, binfo, protect)
register tree parent, binfo;
int protect;
{
tree type = NULL_TREE;
int dist;
tree rval = NULL_TREE;
if (TREE_CODE (parent) == TREE_VEC)
parent = BINFO_TYPE (parent);
else if (! IS_AGGR_TYPE_CODE (TREE_CODE (parent)))
my_friendly_abort (89);
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
type = binfo;
else
my_friendly_abort (90);
dist = get_base_distance (parent, binfo, protect, &rval);
if (dist == -3)
{
cp_error ("fields of `%T' are inaccessible in `%T' due to private inheritance",
parent, type);
return error_mark_node;
}
else if (dist == -2 && protect)
{
cp_error ("type `%T' is ambiguous base class for type `%T'", parent,
type);
return error_mark_node;
}
#ifdef OBJCPLUS
if (!rval)
{
if (objc_comptypes (parent, type, 1) == 1)
return parent;
}
#endif
return rval;
}
static int
get_base_distance_recursive (binfo, depth, is_private, rval,
rval_private_ptr, new_binfo_ptr, parent,
protect, via_virtual_ptr, via_virtual,
current_scope_in_chain)
tree binfo;
int depth, is_private, rval;
int *rval_private_ptr;
tree *new_binfo_ptr, parent;
int protect, *via_virtual_ptr, via_virtual;
int current_scope_in_chain;
{
tree binfos;
int i, n_baselinks;
if (protect
&& !current_scope_in_chain
&& is_friend (BINFO_TYPE (binfo), current_scope ()))
current_scope_in_chain = 1;
if (BINFO_TYPE (binfo) == parent || binfo == parent)
{
int better = 0;
if (rval == -1)
better = 1;
else if (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
BINFO_OFFSET (binfo))
&& *via_virtual_ptr && via_virtual)
{
if (protect)
better = *rval_private_ptr - is_private;
if (better == 0)
better = rval - depth;
}
else
{
rval = depth = -2;
better = *via_virtual_ptr - via_virtual;
}
if (better > 0)
{
rval = depth;
*rval_private_ptr = is_private;
*new_binfo_ptr = binfo;
*via_virtual_ptr = via_virtual;
}
return rval;
}
binfos = BINFO_BASETYPES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
depth += 1;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int via_private
= (protect
&& (is_private
|| (!TREE_VIA_PUBLIC (base_binfo)
&& !(TREE_VIA_PROTECTED (base_binfo)
&& current_scope_in_chain)
&& !is_friend (BINFO_TYPE (binfo), current_scope ()))));
int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
rval = get_base_distance_recursive (base_binfo, depth, via_private,
rval, rval_private_ptr,
new_binfo_ptr, parent,
protect, via_virtual_ptr,
this_virtual,
current_scope_in_chain);
if (rval == -2 && *via_virtual_ptr == 0)
return rval;
}
return rval;
}
int
get_base_distance (parent, binfo, protect, path_ptr)
register tree parent, binfo;
int protect;
tree *path_ptr;
{
int rval;
int rval_private = 0;
tree type = NULL_TREE;
tree new_binfo = NULL_TREE;
int via_virtual;
int watch_access = protect;
if (TREE_CODE (parent) != TREE_VEC)
parent = complete_type (TYPE_MAIN_VARIANT (parent));
else
complete_type (TREE_TYPE (parent));
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
{
type = complete_type (binfo);
binfo = TYPE_BINFO (type);
if (path_ptr)
my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE,
980827);
}
else
my_friendly_abort (92);
if (parent == type || parent == binfo)
{
if (path_ptr)
*path_ptr = binfo;
return 0;
}
if (path_ptr)
watch_access = 1;
rval = get_base_distance_recursive (binfo, 0, 0, -1,
&rval_private, &new_binfo, parent,
watch_access, &via_virtual, 0,
0);
if (rval == -2 && protect >= 0)
rval_private = 0;
if (rval && protect && rval_private)
return -3;
if (rval == -1 && TREE_CODE (parent) == TREE_VEC
&& parent == binfo_member (BINFO_TYPE (parent),
CLASSTYPE_VBASECLASSES (type)))
{
my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
new_binfo = parent;
rval = 1;
}
if (path_ptr)
*path_ptr = new_binfo;
return rval;
}
static tree
lookup_field_1 (type, name)
tree type, name;
{
register tree field;
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
|| TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
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 (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
if (DECL_NAME (field) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
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)
{
if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
&& DECL_ASSEMBLER_NAME (field) != NULL)
GNU_xref_ref(current_function_decl,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (field)));
return field;
}
field = TREE_CHAIN (field);
}
if (name == _vptr_name)
{
if (TYPE_VIRTUAL_P (type))
return CLASSTYPE_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_CLASS_CONTEXT (current_function_decl) == current_class_type)
return current_function_decl;
return current_class_type;
}
static tree
context_for_name_lookup (decl)
tree decl;
{
tree context = DECL_REAL_CONTEXT (decl);
while (TYPE_P (context) && ANON_UNION_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) ? binfo : NULL_TREE;
}
static tree
shared_unmarked_p (binfo, data)
tree binfo;
void *data;
{
binfo = canonical_binfo (binfo);
return unmarkedp (binfo, data) ? binfo : NULL_TREE;
}
static tree
dfs_access_in_type (binfo, data)
tree binfo;
void *data;
{
tree decl = (tree) data;
tree type = BINFO_TYPE (binfo);
tree access = NULL_TREE;
if (context_for_name_lookup (decl) == type)
{
if (TREE_PRIVATE (decl))
access = access_private_node;
else if (TREE_PROTECTED (decl))
access = access_protected_node;
else
access = access_public_node;
}
else
{
if (DECL_LANG_SPECIFIC (decl))
{
access = purpose_member (type, DECL_ACCESS (decl));
if (access)
access = TREE_VALUE (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);
tree base_access = TREE_CHAIN (canonical_binfo (base_binfo));
if (!base_access || base_access == access_private_node)
base_access = NULL_TREE;
else if (TREE_VIA_PROTECTED (base_binfo))
base_access = access_protected_node;
else if (!TREE_VIA_PUBLIC (base_binfo))
base_access = access_private_node;
if (base_access &&
(base_access == access_public_node
|| (base_access == access_protected_node
&& access != access_public_node)
|| (base_access == access_private_node
&& !access)))
{
access = base_access;
if (access == access_public_node)
break;
}
}
}
}
TREE_CHAIN (binfo) = access;
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
static tree
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 TREE_CHAIN (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;
tree access;
SET_BINFO_MARKED (binfo);
access = TREE_CHAIN (binfo);
if (access == access_public_node
|| (access == access_protected_node && protected_ok))
return binfo;
else if (access && is_friend (BINFO_TYPE (binfo), current_scope ()))
return binfo;
return NULL_TREE;
}
static int
protected_accessible_p (type, decl, derived, binfo)
tree type;
tree decl;
tree derived;
tree binfo;
{
tree access;
if (!DERIVED_FROM_P (type, derived))
return 0;
access = access_in_type (derived, decl);
if (same_type_p (derived, type))
{
if (access != access_private_node)
return 0;
}
else if (access != access_private_node
&& access != access_protected_node)
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, type, decl, binfo)
tree scope;
tree type;
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 (type, decl, TREE_VALUE (t), binfo))
return 1;
if (TREE_CODE (scope) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (scope))
{
if (friend_accessible_p (DECL_CLASS_CONTEXT (scope), type,
decl, binfo))
return 1;
if (DECL_TEMPLATE_INFO (scope))
return friend_accessible_p (DECL_TI_TEMPLATE (scope),
type, decl, binfo);
}
else if (CLASSTYPE_TEMPLATE_INFO (scope))
return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope),
type, decl, binfo);
return 0;
}
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 (TREE_CODE (decl) == TYPE_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 (type, decl, current_class_type,
binfo);
if (!protected_ok)
protected_ok = friend_accessible_p (current_scope (),
type, 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 (parent, binfo)
tree parent, binfo;
{
tree binfos;
int i, n_baselinks;
binfos = BINFO_BASETYPES (binfo);
parent = canonical_binfo (parent);
binfo = canonical_binfo (binfo);
if (parent == binfo)
return 1;
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (!CLASS_TYPE_P (TREE_TYPE (base_binfo)))
continue;
if (is_subobject_of_p (parent, base_binfo))
return 1;
}
return 0;
}
static int
hides (hider_binfo, hidee_binfo)
tree hider_binfo, hidee_binfo;
{
return is_subobject_of_p (hidee_binfo, hider_binfo);
}
static int
lookup_fnfields_here (type, name)
tree type, name;
{
int idx = lookup_fnfields_1 (type, name);
tree fndecls;
if (idx <= 1)
return idx;
fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
while (fndecls)
{
if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
== TYPE_MAIN_VARIANT (type))
return idx;
fndecls = OVL_CHAIN (fndecls);
}
return -1;
}
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 (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
return NULL_TREE;
if (!lfi->from_dep_base_p && lfi->rval_binfo
&& hides (lfi->rval_binfo, binfo))
return NULL_TREE;
if (TREE_VIA_VIRTUAL (binfo))
return binfo_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (lfi->type));
else
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 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_here (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)
{
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 && !hides (binfo, lfi->rval_binfo))
{
if (nval == lfi->rval && SHARED_MEMBER_P (nval))
;
else if (hides (lfi->rval_binfo, binfo))
;
else
{
if (!lfi->ambiguous && lfi->rval)
{
lfi->ambiguous = scratch_tree_cons (NULL_TREE, lfi->rval,
NULL_TREE);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
}
lfi->ambiguous = scratch_tree_cons (NULL_TREE, nval,
lfi->ambiguous);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
lfi->errstr = "request for member `%D' is ambiguous";
}
}
else
{
if (VBASE_NAME_P (lfi->name))
{
lfi->rval = nval;
return nval;
}
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
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
my_friendly_abort (97);
complete_type (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
#endif
bzero ((PTR) &lfi, 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)
&& !IS_SIGNATURE_POINTER (DECL_REAL_CONTEXT (rval))
&& !IS_SIGNATURE_REFERENCE (DECL_REAL_CONTEXT (rval))
&& !enforce_access (xbasetype, rval))
return error_mark_node;
if (errstr && protect)
{
cp_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 = scratch_tree_cons (basetype_path, rval, NULL_TREE);
SET_BASELINK_P (rval);
}
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 && TREE_CODE (rval) == TREE_LIST)
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 && TREE_CODE (rval) != TREE_LIST)
return NULL_TREE;
return rval;
}
int
lookup_fnfields_1 (type, name)
tree type, name;
{
register tree method_vec
= CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
if (method_vec != 0)
{
register tree *methods = &TREE_VEC_ELT (method_vec, 0);
register tree *end = TREE_VEC_END (method_vec);
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
#endif
if (*methods && name == ctor_identifier)
return 0;
if (*++methods && name == dtor_identifier)
return 1;
while (++methods != end && *methods)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif
if (DECL_NAME (OVL_CURRENT (*methods)) == name)
break;
}
if ((methods == end || !*methods)
&& IDENTIFIER_TYPENAME_P (name))
{
methods = &TREE_VEC_ELT (method_vec, 0) + 1;
while (++methods != end && *methods)
{
tree method_name = DECL_NAME (OVL_CURRENT (*methods));
if (!IDENTIFIER_TYPENAME_P (method_name))
{
methods = end;
break;
}
else if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL)
break;
}
}
if (methods != end && *methods)
return methods - &TREE_VEC_ELT (method_vec, 0);
}
return -1;
}
static tree
bfs_walk (binfo, fn, qfn, data)
tree binfo;
tree (*fn) PROTO((tree, void *));
tree (*qfn) PROTO((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;
}
}
}
VARRAY_FREE (bfs_bases);
return rval;
}
static tree
dfs_walk_real (binfo, prefn, postfn, qfn, data)
tree binfo;
tree (*prefn) PROTO((tree, void *));
tree (*postfn) PROTO((tree, void *));
tree (*qfn) PROTO((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 = 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)
{
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) PROTO((tree, void *));
tree (*qfn) PROTO((tree, void *));
void *data;
{
return dfs_walk_real (binfo, 0, fn, qfn, data);
}
struct gvnt_info
{
tree name;
tree fields;
};
static tree
get_virtuals_named_this_r (binfo, data)
tree binfo;
void *data;
{
struct gvnt_info *gvnti = (struct gvnt_info *) data;
tree type = BINFO_TYPE (binfo);
int idx;
idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
if (idx >= 0)
gvnti->fields
= scratch_tree_cons (binfo,
TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
idx),
gvnti->fields);
return NULL_TREE;
}
static tree
get_virtuals_named_this (binfo, name)
tree binfo;
tree name;
{
struct gvnt_info gvnti;
tree fields;
gvnti.name = name;
gvnti.fields = NULL_TREE;
bfs_walk (binfo, get_virtuals_named_this_r, 0, &gvnti);
for (fields = gvnti.fields; fields; fields = next_baselink (fields))
{
tree fndecl;
for (fndecl = TREE_VALUE (fields); fndecl; fndecl = OVL_NEXT (fndecl))
if (DECL_VINDEX (OVL_CURRENT (fndecl)))
return fields;
}
return NULL_TREE;
}
static tree
get_virtual_destructor (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
if (TYPE_HAS_DESTRUCTOR (type)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
return 0;
}
static tree
tree_has_any_destructor_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
return TYPE_NEEDS_DESTRUCTOR (type) ? binfo : NULL_TREE;
}
static int
covariant_return_p (brettype, drettype)
tree brettype, drettype;
{
tree binfo;
if (TREE_CODE (brettype) == FUNCTION_DECL
|| TREE_CODE (brettype) == THUNK_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 = get_binfo (brettype, drettype, 1);
if (binfo == error_mark_node)
return 1;
if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo))
return 2;
return 1;
}
tree
get_matching_virtual (binfo, fndecl, dtorp)
tree binfo, fndecl;
int dtorp;
{
tree tmp = NULL_TREE;
int i;
if (TREE_CODE (fndecl) == TEMPLATE_DECL)
return NULL_TREE;
if (dtorp)
return bfs_walk (binfo, get_virtual_destructor,
tree_has_any_destructor_p, 0);
else
{
tree drettype, dtypes, btypes, instptr_type;
tree basetype = DECL_CLASS_CONTEXT (fndecl);
tree baselink, best = NULL_TREE;
tree name = DECL_ASSEMBLER_NAME (fndecl);
tree declarator = DECL_NAME (fndecl);
if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
return NULL_TREE;
baselink = get_virtuals_named_this (binfo, declarator);
if (baselink == NULL_TREE)
return NULL_TREE;
drettype = TREE_TYPE (TREE_TYPE (fndecl));
dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (DECL_STATIC_FUNCTION_P (fndecl))
instptr_type = NULL_TREE;
else
instptr_type = TREE_TYPE (TREE_VALUE (dtypes));
for (; baselink; baselink = next_baselink (baselink))
{
tree tmps;
for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps))
{
tmp = OVL_CURRENT (tmps);
if (! DECL_VINDEX (tmp))
continue;
btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp));
if (instptr_type == NULL_TREE)
{
if (compparms (TREE_CHAIN (btypes), dtypes))
return tmp;
return NULL_TREE;
}
if (
(TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes)))
== TYPE_QUALS (instptr_type))
&& compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
{
tree brettype = TREE_TYPE (TREE_TYPE (tmp));
if (same_type_p (brettype, drettype))
;
else if ((i = covariant_return_p (brettype, drettype)))
{
if (i == 2)
sorry ("adjusting pointers for covariant returns");
if (pedantic && i == -1)
{
cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
cp_pedwarn_at (" overriding `%#D'", tmp);
}
}
else if (IS_AGGR_TYPE_2 (brettype, drettype)
&& same_or_base_type_p (brettype, drettype))
{
error ("invalid covariant return type (must use pointer or reference)");
cp_error_at (" overriding `%#D'", tmp);
cp_error_at (" with `%#D'", fndecl);
}
else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
{
cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
cp_error_at (" overriding definition as `%#D'", tmp);
SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
}
best = tmp;
}
}
}
return best;
}
}
static tree
get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
tree binfo;
int do_self;
tree abstract_virtuals;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
abstract_virtuals
= get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
abstract_virtuals);
}
if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
tree virtuals = BINFO_VIRTUALS (binfo);
skip_rtti_stuff (&virtuals, BINFO_TYPE (binfo));
while (virtuals)
{
tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
tree base_fndecl = TREE_OPERAND (base_pfn, 0);
if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
virtuals = TREE_CHAIN (virtuals);
}
}
return abstract_virtuals;
}
tree
get_abstract_virtuals (type)
tree type;
{
tree vbases;
tree abstract_virtuals = NULL;
abstract_virtuals
= get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
{
tree virtuals = BINFO_VIRTUALS (vbases);
skip_rtti_stuff (&virtuals, type);
while (virtuals)
{
tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
tree base_fndecl = TREE_OPERAND (base_pfn, 0);
if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
cp_error ("`%#D' needs a final overrider", base_fndecl);
else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
virtuals = TREE_CHAIN (virtuals);
}
}
return nreverse (abstract_virtuals);
}
static tree
next_baselink (baselink)
tree baselink;
{
tree tmp = TREE_TYPE (baselink);
baselink = TREE_CHAIN (baselink);
while (tmp)
{
baselink = tree_cons (TREE_PURPOSE (tmp), TREE_VALUE (tmp),
baselink);
TREE_TYPE (baselink) = TREE_TYPE (tmp);
tmp = TREE_CHAIN (tmp);
}
return baselink;
}
static tree
convert_pointer_to_single_level (to_type, expr)
tree to_type, expr;
{
tree derived;
tree binfo_of_derived;
int i;
derived = TREE_TYPE (TREE_TYPE (expr));
binfo_of_derived = TYPE_BINFO (derived);
my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo_of_derived) == NULL_TREE,
980827);
for (i = CLASSTYPE_N_BASECLASSES (derived) - 1; i >= 0; --i)
{
tree binfo = BINFO_BASETYPE (binfo_of_derived, i);
my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == binfo_of_derived,
980827);
if (same_type_p (BINFO_TYPE (binfo), to_type))
return build_vbase_path (PLUS_EXPR,
build_pointer_type (to_type),
expr, binfo, 1);
}
my_friendly_abort (19990607);
return NULL_TREE;
}
tree markedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
unmarkedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
marked_vtable_pathp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
unmarked_vtable_pathp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return !BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
marked_new_vtablep (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_NEW_VTABLE_MARKED (binfo) ? binfo : NULL_TREE;
}
static tree
unmarked_new_vtablep (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return !BINFO_NEW_VTABLE_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;
}
#if 0
static int dfs_search_slot_nonempty_p (binfo) tree binfo;
{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
#endif
static tree
dfs_debug_unmarkedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo))
? binfo : NULL_TREE);
}
#if 0
static void
dfs_mark (binfo) tree binfo;
{ SET_BINFO_MARKED (binfo); }
#endif
tree
dfs_unmark (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
CLEAR_BINFO_MARKED (binfo);
return NULL_TREE;
}
#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
static void
dfs_unmark_vtable_path (binfo) tree binfo;
{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
static void
dfs_mark_new_vtable (binfo) tree binfo;
{ SET_BINFO_NEW_VTABLE_MARKED (binfo); }
static void
dfs_unmark_new_vtable (binfo) tree binfo;
{ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo); }
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
#endif
static tree
dfs_debug_mark (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree t = BINFO_TYPE (binfo);
tree methods = CLASSTYPE_METHOD_VEC (t);
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
if (methods == 0)
return NULL_TREE;
if (CLASSTYPE_INTERFACE_KNOWN (t))
return NULL_TREE;
if (current_function_decl == NULL_TREE
|| DECL_CLASS_CONTEXT (current_function_decl) != t)
{
if (TREE_VEC_ELT (methods, 1))
methods = TREE_VEC_ELT (methods, 1);
else if (TREE_VEC_ELT (methods, 0))
methods = TREE_VEC_ELT (methods, 0);
else
methods = TREE_VEC_ELT (methods, 2);
methods = OVL_CURRENT (methods);
while (methods)
{
if (DECL_VINDEX (methods)
&& DECL_THIS_INLINE (methods) == 0
&& DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
{
return NULL_TREE;
}
methods = TREE_CHAIN (methods);
}
}
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
rest_of_type_compilation (t, toplevel_bindings_p ());
return NULL_TREE;
}
struct vbase_info
{
tree decl_ptr;
tree inits;
tree vbase_types;
};
static tree
dfs_find_vbases (binfo, data)
tree binfo;
void *data;
{
struct vbase_info *vi = (struct vbase_info *) data;
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = n_baselinks-1; i >= 0; i--)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (TREE_VIA_VIRTUAL (base_binfo)
&& CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo)) == 0)
{
tree vbase = BINFO_TYPE (base_binfo);
tree binfo = binfo_member (vbase, vi->vbase_types);
CLASSTYPE_SEARCH_SLOT (vbase)
= build (PLUS_EXPR, build_pointer_type (vbase),
vi->decl_ptr, BINFO_OFFSET (binfo));
}
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
SET_BINFO_NEW_VTABLE_MARKED (binfo);
return NULL_TREE;
}
static tree
dfs_init_vbase_pointers (binfo, data)
tree binfo;
void *data;
{
struct vbase_info *vi = (struct vbase_info *) data;
tree type = BINFO_TYPE (binfo);
tree fields = TYPE_FIELDS (type);
tree this_vbase_ptr;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
#if 0
if (VFIELD_NAME_P (DECL_NAME (fields)))
fields = TREE_CHAIN (fields);
#endif
if (BINFO_INHERITANCE_CHAIN (binfo))
{
this_vbase_ptr = TREE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo));
if (TREE_VIA_VIRTUAL (binfo))
this_vbase_ptr = CLASSTYPE_SEARCH_SLOT (type);
else
this_vbase_ptr = convert_pointer_to_single_level (type,
this_vbase_ptr);
TREE_CHAIN (binfo) = this_vbase_ptr;
}
else
this_vbase_ptr = TREE_CHAIN (binfo);
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
|| ! VBASE_NAME_P (DECL_NAME (fields)))
return NULL_TREE;
if (build_pointer_type (type)
!= TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr)))
my_friendly_abort (125);
while (fields && DECL_NAME (fields) && VBASE_NAME_P (DECL_NAME (fields)))
{
tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
build_indirect_ref (this_vbase_ptr, NULL_PTR), fields);
tree init = CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
vi->inits = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
vi->vbase_types),
build_modify_expr (ref, NOP_EXPR, init),
vi->inits);
fields = TREE_CHAIN (fields);
}
return NULL_TREE;
}
static tree
dfs_clear_vbase_slots (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
CLASSTYPE_SEARCH_SLOT (type) = 0;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
return NULL_TREE;
}
tree
init_vbase_pointers (type, decl_ptr)
tree type;
tree decl_ptr;
{
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
struct vbase_info vi;
int old_flag = flag_this_is_variable;
tree binfo = TYPE_BINFO (type);
flag_this_is_variable = -2;
vi.decl_ptr = decl_ptr;
vi.vbase_types = CLASSTYPE_VBASECLASSES (type);
vi.inits = NULL_TREE;
dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp, &vi);
TREE_CHAIN (binfo) = decl_ptr;
dfs_walk_real (binfo,
dfs_init_vbase_pointers, 0,
marked_vtable_pathp,
&vi);
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
flag_this_is_variable = old_flag;
return vi.inits;
}
return 0;
}
static tree
virtual_context (fndecl, t, vbase)
tree fndecl, t, vbase;
{
tree path;
if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0)
{
if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), vbase, 0, &path) >= 0)
{
while (path)
{
if (TREE_VIA_VIRTUAL (path) || path == vbase)
return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
path = BINFO_INHERITANCE_CHAIN (path);
}
}
warning ("recoverable compiler error, fixups for virtual function");
return vbase;
}
while (path)
{
if (TREE_VIA_VIRTUAL (path))
return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
path = BINFO_INHERITANCE_CHAIN (path);
}
return 0;
}
static void
expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
vbase_offsets)
tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
{
tree virtuals = BINFO_VIRTUALS (binfo);
tree vc;
tree delta;
unsigned HOST_WIDE_INT n;
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
delta = build (MINUS_EXPR, ptrdiff_type_node, delta, vbase_addr);
delta = save_expr (delta);
delta = tree_cons (vbase, delta, *vbase_offsets);
*vbase_offsets = delta;
}
n = skip_rtti_stuff (&virtuals, t);
while (virtuals)
{
tree current_fndecl = TREE_VALUE (virtuals);
current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
current_fndecl = TREE_OPERAND (current_fndecl, 0);
if (current_fndecl
&& current_fndecl != abort_fndecl
&& (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
{
tree idx = build_int_2 (n, 0);
tree vtbl = BINFO_VTABLE (binfo);
tree nvtbl = lookup_name (DECL_NAME (vtbl), 0);
tree aref, ref, naref;
tree old_delta, new_delta;
tree init;
if (nvtbl == NULL_TREE
|| nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl)))
{
nvtbl = build_decl
(VAR_DECL, DECL_NAME (vtbl),
TYPE_MAIN_VARIANT (TREE_TYPE (vtbl)));
DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (nvtbl));
TREE_READONLY (nvtbl) = 0;
DECL_ARTIFICIAL (nvtbl) = 1;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
cp_finish_decl (nvtbl, init, NULL_TREE, 0,
LOOKUP_ONLYCONVERTING);
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
nvtbl, vtbl);
TREE_SIDE_EFFECTS (init) = 1;
expand_expr_stmt (init);
ref = build_vfield_ref
(build_indirect_ref (addr, NULL_PTR),
DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
expand_expr_stmt
(build_modify_expr (ref, NOP_EXPR, nvtbl));
}
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
naref = build_array_ref (nvtbl, idx);
old_delta = build_component_ref (aref, delta_identifier,
NULL_TREE, 0);
new_delta = build_component_ref (naref, delta_identifier,
NULL_TREE, 0);
old_delta = build_binary_op (PLUS_EXPR, old_delta,
TREE_VALUE (delta));
if (vc)
{
tree vc_delta = purpose_member (vc, *vbase_offsets);
if (! vc_delta)
{
tree vc_addr = convert_pointer_to_real (vc, orig_addr);
vc_delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
vc_delta = build (MINUS_EXPR, ptrdiff_type_node,
vc_delta, vc_addr);
vc_delta = save_expr (vc_delta);
*vbase_offsets = tree_cons (vc, vc_delta, *vbase_offsets);
}
else
vc_delta = TREE_VALUE (vc_delta);
old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta);
}
TREE_READONLY (new_delta) = 0;
TREE_TYPE (new_delta) =
cp_build_qualified_type (TREE_TYPE (new_delta),
CP_TYPE_QUALS (TREE_TYPE (new_delta))
& ~TYPE_QUAL_CONST);
expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
old_delta));
}
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
static void
fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
tree real_binfo, binfo;
int init_self, can_elide;
tree addr, orig_addr, type, vbase, *vbase_offsets;
{
tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
orig_addr, type, vbase, vbase_offsets);
}
#if 0
if (can_elide && ! BINFO_MODIFIED (binfo))
return;
#endif
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
{
tree new_addr = convert_pointer_to_real (binfo, addr);
expand_upcast_fixups (real_binfo, new_addr, orig_addr, vbase, addr,
type, vbase_offsets);
}
}
void
expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
tree binfo;
tree true_exp, decl_ptr;
{
tree type = BINFO_TYPE (binfo);
mark_all_temps_used();
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
rtx fixup_insns = NULL_RTX;
tree vbases = CLASSTYPE_VBASECLASSES (type);
struct vbase_info vi;
vi.decl_ptr = (true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0)
: decl_ptr);
vi.vbase_types = vbases;
dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi);
for (; vbases; vbases = TREE_CHAIN (vbases))
{
tree addr;
addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vi.decl_ptr);
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
if (flag_vtable_thunks)
{
}
else
{
tree vbase_offsets = NULL_TREE;
push_to_sequence (fixup_insns);
fixup_virtual_upcast_offsets (vbases,
TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr, vi.decl_ptr,
type, vbases, &vbase_offsets);
fixup_insns = get_insns ();
end_sequence ();
}
}
if (fixup_insns)
{
extern tree in_charge_identifier;
tree in_charge_node = lookup_name (in_charge_identifier, 0);
if (! in_charge_node)
{
warning ("recoverable internal compiler error, nobody's in charge!");
in_charge_node = integer_zero_node;
}
in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node);
expand_start_cond (in_charge_node, 0);
emit_insns (fixup_insns);
expand_end_cond ();
}
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
}
}
static tree
dfs_get_vbase_types (binfo, data)
tree binfo;
void *data;
{
tree *vbase_types = (tree *) data;
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
tree new_vbase = make_binfo (integer_zero_node, binfo,
BINFO_VTABLE (binfo),
BINFO_VIRTUALS (binfo));
TREE_CHAIN (new_vbase) = *vbase_types;
TREE_VIA_VIRTUAL (new_vbase) = 1;
*vbase_types = new_vbase;
SET_BINFO_VBASE_MARKED (binfo);
}
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
tree
get_vbase_types (type)
tree type;
{
tree vbase_types;
tree vbases;
tree binfo;
binfo = TYPE_BINFO (type);
vbase_types = NULL_TREE;
dfs_walk (binfo, dfs_get_vbase_types, unmarkedp, &vbase_types);
dfs_walk (binfo, dfs_unmark, markedp, 0);
vbase_types = nreverse (vbase_types);
for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
CLEAR_BINFO_VBASE_MARKED (vbases);
return vbase_types;
}
void
note_debug_info_needed (type)
tree type;
{
tree field;
if (current_template_parms)
return;
if (TYPE_BEING_DEFINED (type))
return;
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
return;
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
tree ttype;
if (TREE_CODE (field) == FIELD_DECL
&& IS_AGGR_TYPE (ttype = target_type (TREE_TYPE (field)))
&& dfs_debug_unmarkedp (TYPE_BINFO (ttype), 0))
note_debug_info_needed (ttype);
}
}
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
|| (TREE_CODE (value_binding) == TREE_LIST
&& TREE_TYPE (value_binding) == error_mark_node
&& (TREE_CODE (TREE_VALUE (value_binding))
== TYPE_DECL))))
my_friendly_assert (type_binding_p, 19990401);
else
{
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 = TREE_VALUE (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)
setup_class_bindings (DECL_NAME (fields), 0);
else if (TREE_CODE (fields) == FIELD_DECL
&& ANON_UNION_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 *methods;
tree *end;
end = TREE_VEC_END (method_vec);
for (methods = &TREE_VEC_ELT (method_vec, 2);
*methods && methods != end;
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;
{
struct obstack *ambient_obstack = current_obstack;
search_stack = push_search_level (search_stack, &search_obstack);
push_cache_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);
pop_obstacks ();
current_obstack = ambient_obstack;
}
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)
continue;
TREE_USED (fields) = 0;
if (DECL_NAME (fields) == NULL_TREE
&& TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
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);
_vptr_name = get_identifier ("_vptr");
}
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
}
#define scratch_tree_cons expr_tree_cons
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;
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 = scratch_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 (TYPE_SIZE (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;
}
struct bfv_info {
tree vbases;
tree var;
};
static tree
dfs_bfv_queue_p (binfo, data)
tree binfo;
void *data;
{
struct bfv_info *bfvi = (struct bfv_info *) data;
if (TREE_VIA_VIRTUAL (binfo))
return binfo_member (BINFO_TYPE (binfo), bfvi->vbases);
return binfo;
}
static tree
dfs_bfv_helper (binfo, data)
tree binfo;
void *data;
{
struct bfv_info *bfvi = (struct bfv_info *) data;
if (BINFO_VTABLE (binfo) == bfvi->var)
return binfo;
return NULL_TREE;
}
tree
binfo_for_vtable (var)
tree var;
{
tree type;
struct bfv_info bfvi;
type = DECL_CONTEXT (var);
bfvi.vbases = CLASSTYPE_VBASECLASSES (type);
bfvi.var = var;
return dfs_walk_real (TYPE_BINFO (type),
0, dfs_bfv_helper, dfs_bfv_queue_p, &bfvi);
}