/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Remove before release, should only appear for development and testing. */
#define CHECK_convert_pointer_to_single_level
/* High-level class interface. */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern struct obstack
*current_obstack
;
/* Obstack used for remembering decision points of breadth-first. */
static struct obstack search_obstack
;
/* Obstack used to bridge from one function context to another. */
static struct obstack bridge_obstack
;
/* Methods for pushing and popping objects to and from obstacks. */
push_stack_level (obstack
, tp
, size
)
char *tp
; /* Sony NewsOS 5.0 compiler doesn't like void * here. */
struct stack_level
*stack
;
/* FIXME. Doesn't obstack_grow, in the case when the current chunk has
insufficient space, move the base so that obstack_next_free is not
valid? Perhaps obstack_copy should be used rather than obstack_grow,
and its returned value be used. -- Raeburn
stack
= (struct stack_level
*) obstack_next_free (obstack
);
obstack_grow (obstack
, tp
, size
);
obstack_finish (obstack
);
stack
->obstack
= obstack
;
stack
->first
= (tree
*) obstack_base (obstack
);
stack
->limit
= obstack_room (obstack
) / sizeof (tree
*);
struct stack_level
*stack
;
struct stack_level
*tem
= stack
;
struct obstack
*obstack
= tem
->obstack
;
obstack_free (obstack
, tem
);
#define search_level stack_level
static struct search_level
*search_stack
;
static tree
lookup_field_1 ();
static int lookup_fnfields_1 ();
static void dfs_unmark ();
static void dfs_init_vbase_pointers ();
static tree vbase_decl
, vbase_decl_ptr
;
static tree vbase_decl_ptr_intermediate
;
static tree vbase_init_result
;
/* Allocate a level of searching. */
static struct search_level
*
push_search_level (stack
, obstack
)
struct stack_level
*stack
;
return push_stack_level (obstack
, (char *) &tem
, sizeof (tem
));
/* Discard a level of search allocation. */
#define pop_search_level pop_stack_level
/* Search memoization. */
/* First object allocated in obstack of entries. */
/* Number of types memoized in this context. */
/* Type being memoized; save this if we are saving
/* Obstack used for memoizing member and member function lookup. */
static struct obstack type_obstack
, type_obstack_entries
;
static struct type_level
*type_stack
;
/* Make things that look like tree nodes, but allocate them
on type_obstack_entries. */
static int my_tree_node_counter
;
static tree
my_tree_cons (), my_build_string ();
extern int flag_memoize_lookups
, flag_save_memoized_contexts
;
/* Variables for gathering statistics. */
static int my_memoized_entry_counter
;
static int memoized_fast_finds
[2], memoized_adds
[2], memoized_fast_rejects
[2];
static int memoized_fields_searched
[2];
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
;
/* Local variables to help save memoization contexts. */
static tree prev_type_memoized
;
static struct type_level
*prev_type_stack
;
/* Allocate a level of type memoization context. */
static struct type_level
*
push_type_level (stack
, obstack
)
struct stack_level
*stack
;
obstack_finish (&type_obstack_entries
);
tem
.entries
= (char *) obstack_base (&type_obstack_entries
);
return (struct type_level
*)push_stack_level (obstack
, (char *) &tem
,
/* Discard a level of type memoization context. */
static struct type_level
*
struct type_level
*stack
;
obstack_free (&type_obstack_entries
, stack
->entries
);
return (struct type_level
*)pop_stack_level ((struct stack_level
*)stack
);
/* Make something that looks like a TREE_LIST, but
do it on the type_obstack_entries obstack. */
my_tree_cons (purpose
, value
, chain
)
tree purpose
, value
, chain
;
tree p
= (tree
)obstack_alloc (&type_obstack_entries
, sizeof (struct tree_list
));
TREE_TYPE (p
) = NULL_TREE
;
((HOST_WIDE_INT
*)p
)[3] = 0;
TREE_SET_CODE (p
, TREE_LIST
);
TREE_PURPOSE (p
) = purpose
;
tree p
= (tree
)obstack_alloc (&type_obstack_entries
, sizeof (struct tree_string
));
TREE_SET_CODE (p
, STRING_CST
);
TREE_STRING_POINTER (p
) = str
;
TREE_STRING_LENGTH (p
) = strlen (str
);
/* Memoizing machinery to make searches for multiple inheritance
#define MEMOIZE_HASHSIZE 8
typedef struct memoized_entry
struct memoized_entry
*chain
;
tree data_members
[MEMOIZE_HASHSIZE
];
tree function_members
[MEMOIZE_HASHSIZE
];
#define MEMOIZED_CHAIN(ENTRY) (((ME)ENTRY)->chain)
#define MEMOIZED_UID(ENTRY) (((ME)ENTRY)->uid)
#define MEMOIZED_FIELDS(ENTRY,INDEX) (((ME)ENTRY)->data_members[INDEX])
#define MEMOIZED_FNFIELDS(ENTRY,INDEX) (((ME)ENTRY)->function_members[INDEX])
/* The following is probably a lousy hash function. */
#define MEMOIZED_HASH_FN(NODE) (((long)(NODE)>>4)&(MEMOIZE_HASHSIZE - 1))
static struct memoized_entry
*
my_new_memoized_entry (chain
)
struct memoized_entry
*chain
;
struct memoized_entry
*p
=
(struct memoized_entry
*)obstack_alloc (&type_obstack_entries
,
sizeof (struct memoized_entry
));
bzero (p
, sizeof (struct memoized_entry
));
MEMOIZED_CHAIN (p
) = chain
;
MEMOIZED_UID (p
) = ++my_memoized_entry_counter
;
/* Make an entry in the memoized table for type TYPE
that the entry for NAME is FIELD. */
make_memoized_table_entry (type
, name
, function_p
)
int index
= MEMOIZED_HASH_FN (name
);
memoized_adds
[function_p
] += 1;
if (CLASSTYPE_MTABLE_ENTRY (type
) == 0)
obstack_ptr_grow (&type_obstack
, type
);
obstack_blank (&type_obstack
, sizeof (struct memoized_entry
*));
CLASSTYPE_MTABLE_ENTRY (type
) = (char *)my_new_memoized_entry ((struct memoized_entry
*)0);
if (type_stack
->len
* 2 >= type_stack
->base
.limit
)
prev_entry
= &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type
), index
);
prev_entry
= &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type
), index
);
entry
= my_tree_cons (name
, NULL_TREE
, *prev_entry
);
/* Don't know the error message to give yet. */
TREE_TYPE (entry
) = error_mark_node
;
/* When a new function or class context is entered, we build
a table of types which have been searched for members.
The table is an array (obstack) of types. When a type is
entered into the obstack, its CLASSTYPE_MTABLE_ENTRY
field is set to point to a new record, of type struct memoized_entry.
A non-NULL TREE_TYPE of the entry contains a visibility error message.
The slots for the data members are arrays of tree nodes.
These tree nodes are lists, with the TREE_PURPOSE
of this list the known member name, and the TREE_VALUE
as the FIELD_DECL for the member.
For member functions, the TREE_PURPOSE is again the
name of the member functions for that class,
and the TREE_VALUE of the list is a pairs
whose TREE_PURPOSE is a member functions of this name,
and whose TREE_VALUE is a list of known argument lists this
member function has been called with. The TREE_TYPE of the pair,
if non-NULL, is an error message to print. */
/* Tell search machinery that we are entering a new context, and
to update tables appropriately.
TYPE is the type of the context we are entering, which can
be NULL_TREE if we are not in a class's scope.
USE_OLD, if nonzero tries to use previous context. */
push_memoized_context (type
, use_old
)
if (use_old
&& prev_type_memoized
== type
)
type_stack
= prev_type_stack
;
tem
= &type_stack
->base
.first
[0];
CLASSTYPE_MTABLE_ENTRY (tem
[len
*2]) = (char *)tem
[len
*2+1];
/* Otherwise, need to pop old stack here. */
type_stack
= pop_type_level (prev_type_stack
);
type_stack
= push_type_level ((struct stack_level
*)type_stack
,
/* Tell search machinery that we have left a context.
We do not currently save these contexts for later use.
If we wanted to, we could not use pop_search_level, since
poping that level allows the data we have collected to
be clobbered; a stack of obstacks would be needed. */
pop_memoized_context (use_old
)
tree
*tem
= &type_stack
->base
.first
[0];
if (! flag_save_memoized_contexts
)
tem
[len
*2+1] = (tree
)CLASSTYPE_MTABLE_ENTRY (tem
[len
*2]);
prev_type_stack
= type_stack
;
prev_type_memoized
= type_stack
->type
;
if (flag_memoize_lookups
)
CLASSTYPE_MTABLE_ENTRY (tem
[len
*2])
= (char *)MEMOIZED_CHAIN (CLASSTYPE_MTABLE_ENTRY (tem
[len
*2]));
type_stack
= pop_type_level (type_stack
);
type_stack
= (struct type_level
*)type_stack
->base
.prev
;
/* This can go away when the new searching strategy as a little mileage on it. */
/* This is the newer recursive depth first one, the old one follows. */
get_binfo_recursive (binfo
, is_private
, parent
, rval
, rval_private_ptr
, xtype
,
tree binfo
, parent
, rval
, xtype
, friends
;
int *rval_private_ptr
, protect
, is_private
;
if (BINFO_TYPE (binfo
) == parent
)
*rval_private_ptr
= is_private
;
/* I believe it is the case that this error is only an error
when used by someone that wants error messages printed.
Routines that call this one, that don't set protect want
the first one found, even if there are more. */
/* Found two or more possible return values. */
error_with_aggr_type (parent
, "type `%s' is ambiguous base class for type `%s'",
TYPE_NAME_STRING (xtype
));
binfos
= BINFO_BASETYPES (binfo
);
n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0)
int via_private
= is_private
|| !TREE_VIA_PUBLIC (base_binfo
);
SET_BINFO_MARKED (base_binfo
);
else if (protect
== 1 && BINFO_TYPE (binfo
) == current_class_type
)
/* The immediate base class of the class we are in
does let its public members through. */
&& BINFO_TYPE (binfo
) == xtype
&& value_member (current_class_type
, friends
))
/* Friend types of the most derived type have access
to its baseclass pointers. */
rval
= get_binfo_recursive (base_binfo
, via_private
, parent
, rval
,
rval_private_ptr
, xtype
, friends
,
if (rval
== error_mark_node
)
/* Check whether the type given in BINFO is derived from PARENT. If
it isn't, return 0. If it is, but the derivation is MI-ambiguous
AND protect != 0, emit an error message and return error_mark_node.
Otherwise, if TYPE is derived from PARENT, return the actual base
information, unless a one of the protection violations below
occurs, in which case emit an error message and return error_mark_node.
The below should be worded better. It may not be exactly what the code
does, but there should be a lose correlation. If you understand the code
well, please try and make the comments below more readable.
If PROTECT is 1, then check if access to a public field of PARENT
If PROTECT is 2, then check if the given type is derived from
PARENT via private visibility rules.
If PROTECT is 3, then immediately private baseclass is ok,
but deeper than that, check if private. */
get_binfo (parent
, binfo
, protect
)
register tree parent
, binfo
;
if (TREE_CODE (parent
) == TREE_VEC
)
parent
= BINFO_TYPE (parent
);
/* unions cannot participate in inheritance relationships */
else if (TREE_CODE (parent
) == UNION_TYPE
)
else if (TREE_CODE (parent
) != RECORD_TYPE
)
parent
= TYPE_MAIN_VARIANT (parent
);
if (TREE_CODE (binfo
) == TREE_VEC
)
type
= BINFO_TYPE (binfo
);
else if (TREE_CODE (binfo
) == RECORD_TYPE
)
binfo
= TYPE_BINFO (type
);
else my_friendly_abort (90);
friends
= current_class_type
? CLASSTYPE_FRIEND_CLASSES (type
) : NULL_TREE
;
rval
= get_binfo_recursive (binfo
, is_private
, parent
, rval
, &rval_private
,
xtype
, friends
, protect
);
dfs_walk (binfo
, dfs_unmark
, markedp
);
if (rval
&& protect
&& rval_private
)
tree binfos
= BINFO_BASETYPES (TYPE_BINFO (xtype
));
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
);
if (parent
== BINFO_TYPE (base_binfo
))
/* It's ok, since it's immediate. */
error_with_aggr_type (xtype
, "type `%s' is derived from private `%s'",
TYPE_NAME_STRING (parent
));
/* Check whether the type given in BINFO is derived from PARENT. If
it isn't, return 0. If it is, but the derivation is MI-ambiguous
AND protect != 0, emit an error message and return error_mark_node.
Otherwise, if TYPE is derived from PARENT, return the actual base
information, unless a one of the protection violations below
occurs, in which case emit an error message and return error_mark_node.
The below should be worded better. It may not be exactly what the code
does, but there should be a lose correlation. If you understand the code
well, please try and make the comments below more readable.
If PROTECT is 1, then check if access to a public field of PARENT
If PROTECT is 2, then check if the given type is derived from
PARENT via private visibility rules.
If PROTECT is 3, then immediately private baseclass is ok,
but deeper than that, check if private. */
get_binfo (parent
, binfo
, protect
)
register tree parent
, binfo
;
if (TREE_CODE (parent
) == TREE_VEC
)
parent
= BINFO_TYPE (parent
);
/* unions cannot participate in inheritance relationships */
else if (TREE_CODE (parent
) == UNION_TYPE
)
else if (TREE_CODE (parent
) != RECORD_TYPE
)
parent
= TYPE_MAIN_VARIANT (parent
);
search_stack
= push_search_level (search_stack
, &search_obstack
);
if (TREE_CODE (binfo
) == TREE_VEC
)
type
= BINFO_TYPE (binfo
);
else if (TREE_CODE (binfo
) == RECORD_TYPE
)
binfo
= TYPE_BINFO (type
);
else my_friendly_abort (90);
friends
= current_class_type
? CLASSTYPE_FRIEND_CLASSES (type
) : NULL_TREE
;
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0)
int via_private
= is_private
|| !TREE_VIA_PUBLIC (base_binfo
);
SET_BINFO_MARKED (base_binfo
);
else if (protect
== 1 && BINFO_TYPE (binfo
) == current_class_type
)
/* The immediate base class of the class we are in
does let its public members through. */
&& BINFO_TYPE (binfo
) == xtype
&& value_member (current_class_type
, friends
))
/* Friend types of the most derived type have access
to its baseclass pointers. */
obstack_ptr_grow (&search_obstack
, base_binfo
);
obstack_ptr_grow (&search_obstack
, (void *) via_private
);
if (tail
>= search_stack
->limit
)
/* This code cannot possibly be right. Ambiguities can only be
checked by traversing the whole tree, and seeing if it pops
else if (protect
&& ! TREE_VIA_VIRTUAL (base_binfo
))
error_with_aggr_type (parent
, "type `%s' is ambiguous base class for type `%s'",
TYPE_NAME_STRING (xtype
));
error ("(base class for types `%s' and `%s')",
TYPE_NAME_STRING (BINFO_TYPE (binfo
)),
TYPE_NAME_STRING (otype
));
/* Process head of queue, if one exists. */
binfo
= search_stack
->first
[head
++];
is_private
= (int) search_stack
->first
[head
++];
if (BINFO_TYPE (binfo
) == parent
)
rval_private
= is_private
;
/* I believe it is the case that this error is only an error when
used by someone that wants error messages printed. Routines that
call this one, that don't set protect want the first one found,
even if there are more. */
/* Found two or more possible return values. */
error_with_aggr_type (parent
, "type `%s' is ambiguous base class for type `%s'",
TYPE_NAME_STRING (xtype
));
tree
*tp
= search_stack
->first
;
tree
*search_tail
= tp
+ tail
;
CLEAR_BINFO_MARKED (*tp
);
search_stack
= pop_search_level (search_stack
);
if (rval
== error_mark_node
)
if (rval
&& protect
&& rval_private
)
tree binfos
= BINFO_BASETYPES (TYPE_BINFO (xtype
));
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
);
if (parent
== BINFO_TYPE (base_binfo
))
/* It's ok, since it's immediate. */
error_with_aggr_type (xtype
, "type `%s' is derived from private `%s'",
TYPE_NAME_STRING (parent
));
/* This is the newer depth first get_base_distance, the older one follows. */
get_base_distance_recursive (binfo
, depth
, is_private
, basetype_path
, rval
,
rval_private_ptr
, new_binfo_ptr
, parent
, path_ptr
,
protect
, via_virtual_ptr
, via_virtual
)
tree binfo
, basetype_path
, *new_binfo_ptr
, parent
, *path_ptr
;
int *rval_private_ptr
, depth
, is_private
, rval
, protect
, *via_virtual_ptr
,
if (BINFO_TYPE (binfo
) == parent
)
*rval_private_ptr
= is_private
;
*via_virtual_ptr
= via_virtual
;
int same_object
= tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr
),
if (*via_virtual_ptr
&& via_virtual
==0)
*rval_private_ptr
= is_private
;
*via_virtual_ptr
= via_virtual
;
/* Note, this should probably succeed to find, and
override the old one if the old one was private and
binfos
= BINFO_BASETYPES (binfo
);
n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0)
int via_private
= is_private
|| !TREE_VIA_PUBLIC (base_binfo
);
/* When searching for a non-virtual, we cannot mark
virtually found binfos. */
SET_BINFO_MARKED (base_binfo
);
#define WATCH_VALUES(rval, via_private) (rval == -1 ? 3 : via_private)
was
= WATCH_VALUES (rval
, *via_virtual_ptr
);
rval
= get_base_distance_recursive (base_binfo
, depth
, via_private
,
binfo
, rval
, rval_private_ptr
,
new_binfo_ptr
, parent
, path_ptr
,
protect
, via_virtual_ptr
,
TREE_VIA_VIRTUAL (base_binfo
)|via_virtual
);
/* watch for updates, only update, if path is good. */
if (path_ptr
&& WATCH_VALUES (rval
, *via_virtual_ptr
) != was
)
BINFO_INHERITANCE_CHAIN (base_binfo
) = binfo
;
if (rval
== -2 && *via_virtual_ptr
== 0)
/* Return the number of levels between type PARENT and the type given
in BINFO, following the leftmost path to PARENT not found along a
virtual path, if there are no real PARENTs (all come from virtual
base classes), then follow the leftmost path to PARENT.
Return -1 if TYPE is not derived from PARENT.
Return -2 if PARENT is an ambiguous base class of TYPE.
Return -3 if PARENT is private to TYPE, and protect is non-zero.
If PATH_PTR is non-NULL, then also build the list of types
from PARENT to TYPE, with TREE_VIA_VIRUAL and TREE_VIA_PUBLIC
It is unclear whether or not the path should be built if -2 and/or
-3 is returned. Maybe, maybe not. I suspect that there is code
that relies upon it being built, such as prepare_fresh_vtable.
Also, it would appear that we only sometimes want -2. The question is
under what exact conditions do we want to see -2, and when do we not
It is also unlikely that this thing finds all ambiguties, as I
don't trust any deviation from the method used in get_binfo. It
would be nice to use that method here, as it is simple and straight
forward. The code here and in recursive_bounded_basetype_p is not.
For now, I shall include an extra call to find ambiguities. (mrs)
get_base_distance (parent
, binfo
, protect
, path_ptr
)
register tree parent
, binfo
;
tree type
, basetype_path
;
if (TYPE_READONLY (parent
) || TYPE_VOLATILE (parent
))
parent
= TYPE_MAIN_VARIANT (parent
);
use_leftmost
= (parent
== TYPE_MAIN_VARIANT (parent
));
if (TREE_CODE (binfo
) == TREE_VEC
)
type
= BINFO_TYPE (binfo
);
else if (TREE_CODE (binfo
) == RECORD_TYPE
)
binfo
= TYPE_BINFO (type
);
else my_friendly_abort (92);
friends
= current_class_type
? CLASSTYPE_FRIEND_CLASSES (type
) : NULL_TREE
;
basetype_path
= TYPE_BINFO (type
);
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
if (TYPE_MAIN_VARIANT (parent
) == type
)
/* If the distance is 0, then we don't really need
a path pointer, but we shouldn't let garbage go back. */
*path_ptr
= basetype_path
;
rval
= get_base_distance_recursive (binfo
, 0, 0, NULL_TREE
, rval
,
&rval_private
, &new_binfo
, parent
,
path_ptr
, protect
, &via_virtual
, 0);
BINFO_INHERITANCE_CHAIN (binfo
) = NULL_TREE
;
dfs_walk (binfo
, dfs_unmark
, markedp
);
/* Visibilities don't count if we found an ambiguous basetype. */
if (rval
&& protect
&& rval_private
)
/* Recursively search for a path from PARENT to BINFO.
If RVAL is > 0 and we succeed, update the BINFO_INHERITANCE_CHAIN
If we find a distinct basetype that's not the one from BINFO,
If we don't find any path, return 0.
If we encounter a virtual basetype on the path, return RVAL
and don't change any pointers after that point. */
recursive_bounded_basetype_p (parent
, binfo
, rval
, update_chain
)
if (BINFO_TYPE (parent
) == BINFO_TYPE (binfo
))
if (tree_int_cst_equal (BINFO_OFFSET (parent
), BINFO_OFFSET (binfo
)))
if (TREE_VIA_VIRTUAL (binfo
))
if (binfos
= BINFO_BASETYPES (binfo
))
for (i
= 0; i
< TREE_VEC_LENGTH (binfos
); i
++)
nval
= recursive_bounded_basetype_p (parent
, TREE_VEC_ELT (binfos
, i
),
if (nval
> 0 && update_chain
)
BINFO_INHERITANCE_CHAIN (TREE_VEC_ELT (binfos
, i
)) = binfo
;
/* -------------------------------------------------- */
/* These two routines are ONLY here to check for ambiguities for
get_base_distance, as it probably cannot check by itself for
all ambiguities. When get_base_distance is sure to check for all,
these routines can go. (mrs) */
get_binfo2_recursive (binfo
, parent
, type
)
register tree binfo
, parent
;
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
if (BINFO_TYPE (binfo
) == parent
)
/* Process base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0)
SET_BINFO_MARKED (base_binfo
);
nrval
= get_binfo2_recursive (base_binfo
, parent
, type
);
if (nrval
== error_mark_node
)
get_binfo2 (parent
, binfo
)
register tree parent
, binfo
;
if (TREE_CODE (parent
) == TREE_VEC
)
parent
= BINFO_TYPE (parent
);
/* unions cannot participate in inheritance relationships */
else if (TREE_CODE (parent
) == UNION_TYPE
)
else if (TREE_CODE (parent
) != RECORD_TYPE
)
parent
= TYPE_MAIN_VARIANT (parent
);
if (TREE_CODE (binfo
) == TREE_VEC
)
type
= BINFO_TYPE (binfo
);
else if (TREE_CODE (binfo
) == RECORD_TYPE
)
binfo
= TYPE_BINFO (type
);
else my_friendly_abort (90);
rval
= get_binfo2_recursive (binfo
, parent
, type
);
dfs_walk (binfo
, dfs_unmark
, markedp
);
/* -------------------------------------------------- */
/* Return the number of levels between type PARENT and the type given
in BINFO, following the leftmost path to PARENT. If PARENT is its
own main type variant, then if PARENT appears in different places
from TYPE's point of view, the leftmost PARENT will be the one
Return -1 if TYPE is not derived from PARENT.
Return -2 if PARENT is an ambiguous base class of TYPE.
Return -3 if PARENT is private to TYPE, and protect is non-zero.
If PATH_PTR is non-NULL, then also build the list of types
from PARENT to TYPE, with TREE_VIA_VIRUAL and TREE_VIA_PUBLIC
It is unclear whether or not the path should be built if -2 and/or
-3 is returned. Maybe, maybe not. I suspect that there is code
that relies upon it being built, such as prepare_fresh_vtable.
Also, it would appear that we only sometimes want -2. The question is
under what exact conditions do we want to see -2, and when do we not
It is also unlikely that this thing finds all ambiguties, as I
don't trust any deviation from the method used in get_binfo. It
would be nice to use that method here, as it is simple and straight
forward. The code here and in recursive_bounded_basetype_p is not.
For now, I shall include an extra call to find ambiguities. (mrs)
get_base_distance (parent
, binfo
, protect
, path_ptr
)
register tree parent
, binfo
;
tree type
, basetype_path
;
if (TYPE_READONLY (parent
) || TYPE_VOLATILE (parent
))
parent
= TYPE_MAIN_VARIANT (parent
);
use_leftmost
= (parent
== TYPE_MAIN_VARIANT (parent
));
if (TREE_CODE (binfo
) == TREE_VEC
)
type
= BINFO_TYPE (binfo
);
else if (TREE_CODE (binfo
) == RECORD_TYPE
)
binfo
= TYPE_BINFO (type
);
else if (TREE_CODE (binfo
) == UNION_TYPE
)
/* UNION_TYPEs do not participate in inheritance relationships. */
else my_friendly_abort (92);
friends
= current_class_type
? CLASSTYPE_FRIEND_CLASSES (type
) : NULL_TREE
;
basetype_path
= TYPE_BINFO (type
);
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
if (TYPE_MAIN_VARIANT (parent
) == type
)
/* If the distance is 0, then we don't really need
a path pointer, but we shouldn't let garbage go back. */
*path_ptr
= basetype_path
;
search_stack
= push_search_level (search_stack
, &search_obstack
);
/* Keep space for TYPE. */
obstack_ptr_grow (&search_obstack
, binfo
);
obstack_ptr_grow (&search_obstack
, NULL_PTR
);
obstack_ptr_grow (&search_obstack
, NULL_PTR
);
obstack_ptr_grow (&search_obstack
, NULL_PTR
);
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0)
int via_private
= is_private
|| !TREE_VIA_PUBLIC (base_binfo
);
SET_BINFO_MARKED (base_binfo
);
obstack_ptr_grow (&search_obstack
, base_binfo
);
obstack_ptr_grow (&search_obstack
, (HOST_WIDE_INT
) depth
);
obstack_ptr_grow (&search_obstack
, (HOST_WIDE_INT
) via_private
);
obstack_ptr_grow (&search_obstack
, basetype_path
);
if (tail
>= search_stack
->limit
)
/* This code cannot possibly be right. Ambiguities can only be
checked by traversing the whole tree, and seeing if it pops
else if (! TREE_VIA_VIRTUAL (base_binfo
))
/* Process head of queue, if one exists. */
binfo
= search_stack
->first
[head
++];
depth
= (int) search_stack
->first
[head
++] + 1;
is_private
= (int) search_stack
->first
[head
++];
basetype_path
= search_stack
->first
[head
++];
BINFO_INHERITANCE_CHAIN (binfo
) = basetype_path
;
if (BINFO_TYPE (binfo
) == parent
)
/* It is wrong to set this and break, the proper thing to do
would be to set it only if it has not been set before,
and if is has been set, an ambiguity exists, and just
continue searching the tree for more of them as is done
in get_binfo. But until the code below can cope, this
can't be done. Also, it is not clear what should happen if
rval_private
= is_private
;
/* Unneeded now, as we know the above code in the #if 0 is wrong. */
int increment
= path_ptr
? 4 : 3;
tree
*tp
= search_stack
->first
;
tree
*search_tail
= tp
+ tail
;
/* We can skip the first entry, since it wasn't marked. */
CLEAR_BINFO_MARKED (*tp
);
/* Now, guarantee that we are following the leftmost path in the
chain. Algorithm: the search stack holds tuples in BFS order.
The last tuple on the search stack contains the tentative binfo
for the basetype we are looking for. We know that starting
with FIRST, each tuple with only a single basetype must be on
the leftmost path. Each time we come to a split, we select
the tuple for the leftmost basetype that can reach the ultimate
&& (! BINFO_OFFSET_ZEROP (binfo
) || TREE_VIA_VIRTUAL (binfo
)))
/* Farm out the tuples with a single basetype. */
for (tp
= search_stack
->first
; tp
< search_tail
; tp
+= increment
)
tp_binfos
= BINFO_BASETYPES (*tp
);
if (tp_binfos
&& TREE_VEC_LENGTH (tp_binfos
) > 1)
/* Pick the best path. */
for (i
= 0; i
< TREE_VEC_LENGTH (tp_binfos
); i
++)
base_binfo
= TREE_VEC_ELT (tp_binfos
, i
);
if (tp
+((i
+1)*increment
) < search_tail
)
my_friendly_assert (base_binfo
== tp
[(i
+1)*increment
], 295);
if (nrval
= recursive_bounded_basetype_p (binfo
, base_binfo
, rval
, 1))
BINFO_INHERITANCE_CHAIN (base_binfo
) = *tp
;
/* Because I don't trust recursive_bounded_basetype_p to find
all ambiguities, I will just make sure here. When it is
sure that all ambiguities are found, the two routines and
this call can be removed. Not toally sure this should be
here, but I think it should. (mrs) */
if (get_binfo2 (parent
, type
) == error_mark_node
&& rval
!= -2)
/* This warning is here because the code over in
prepare_fresh_vtable relies on partial completion
offered by recursive_bounded_basetype_p I think, but
that behavior is not documented. It needs to be. I
don't think prepare_fresh_vtable is the only routine
that relies upon path_ptr being set to something in a
particular way when this routine returns -2. (mrs) */
/* See PR 428 for a test case that can tickle this. */
warning ("internal consistency check failed, please report, recovering.");
/* Visibilities don't count if we found an ambiguous basetype. */
search_stack
= pop_search_level (search_stack
);
if (rval
&& protect
&& rval_private
)
/* Search for a member with name NAME in a multiple inheritance lattice
specified by TYPE. If it does not exist, return NULL_TREE.
If the member is ambiguously referenced, return `error_mark_node'.
Otherwise, return the FIELD_DECL. */
/* Do a 1-level search for NAME as a member of TYPE. The caller
must figure out whether it has a visible path to this field.
(Since it is only one level, this is reasonable.) */
lookup_field_1 (type
, name
)
register tree field
= TYPE_FIELDS (type
);
n_calls_lookup_field_1
++;
if (DECL_NAME (field
) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field
)) == UNION_TYPE
)
tree temp
= lookup_field_1 (TREE_TYPE (field
), name
);
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
)));
field
= TREE_CHAIN (field
);
/* Give the user what s/he thinks s/he wants. */
if (TYPE_VIRTUAL_P (type
))
return CLASSTYPE_VFIELD (type
);
/* Compute the visibility of FIELD. This is done by computing
the visibility available to each type in BASETYPES (which comes
as a list of [via_public/basetype] in reverse order, namely base
class before derived class). The first one which defines a
visibility defines the visibility for the field. Otherwise, the
visibility of the field is that which occurs normally.
Uses global variables CURRENT_CLASS_TYPE and
CURRENT_FUNCTION_DECL to use friend relationships
This will be static when lookup_fnfield comes into this file. */
#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), visibility_public
#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), visibility_protected
#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), visibility_private
compute_visibility (basetype_path
, field
)
tree basetype_path
, field
;
enum visibility_type visibility
= visibility_public
;
tree context
= DECL_CLASS_CONTEXT (field
);
/* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT
slot set to the union type rather than the record type containing
the anonymous union. In this case, DECL_FIELD_CONTEXT is correct. */
if (context
&& TREE_CODE (context
) == UNION_TYPE
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (context
)))
context
= DECL_FIELD_CONTEXT (field
);
/* Virtual function tables are never private.
But we should know that we are looking for this,
and not even try to hide it. */
if (DECL_NAME (field
) && VFIELD_NAME_P (DECL_NAME (field
)) == 1)
return visibility_public
;
/* Member function manipulating its own members. */
if (current_class_type
== context
|| (context
&& current_class_type
== TYPE_MAIN_VARIANT (context
)))
/* Make these special cases fast. */
if (BINFO_TYPE (basetype_path
) == current_class_type
)
return visibility_public
;
if (DECL_PROTECTED (field
))
return visibility_protected
;
if (DECL_PRIVATE (field
))
return visibility_private
;
/* Member found immediately within object. */
if (BINFO_INHERITANCE_CHAIN (basetype_path
) == NULL_TREE
)
/* At object's top level, public members are public. */
if (TREE_PROTECTED (field
) == 0 && TREE_PRIVATE (field
) == 0)
/* Friend function manipulating members it gets (for being a friend). */
if (is_friend (context
, current_function_decl
))
/* Inner than that, without special visibility,
protected members are ok if type of object is current_class_type
is derived therefrom. This means that if the type of the object
is a base type for our current class type, we cannot access
private members are not ok. */
if (current_class_type
&& DECL_VISIBILITY (field
) == NULL_TREE
)
if (TREE_PRIVATE (field
))
if (TREE_PROTECTED (field
))
if (context
== current_class_type
|| UNIQUELY_DERIVED_FROM_P (context
, current_class_type
))
else my_friendly_abort (94);
/* Friend function manipulating members it gets (for being a friend). */
if (is_friend (context
, current_function_decl
))
/* must reverse more than one element */
basetype_path
= reverse_path (basetype_path
);
tree type
= BINFO_TYPE (binfo
);
member
= purpose_member (type
, DECL_VISIBILITY (field
));
visibility
= (enum visibility_type
)TREE_VALUE (member
);
if (visibility
== visibility_public
|| is_friend (type
, current_function_decl
)
|| (visibility
== visibility_protected
&& UNIQUELY_DERIVED_FROM_P (context
, current_class_type
)))
visibility
= visibility_public
;
/* Friends inherit the visibility of the class they inherit from. */
if (is_friend (type
, current_function_decl
))
visibility
= visibility_public
;
if (TREE_PROTECTED (field
))
visibility
= visibility_public
;
/* This short-cut is too short. */
if (visibility
== visibility_public
)
/* else, may be a friend of a deeper base class */
types
= BINFO_INHERITANCE_CHAIN (types
);
/* If the next type was not VIA_PUBLIC, then fields of all
remaining class past that one are private. */
if (TREE_VIA_PROTECTED (types
))
visibility
= visibility_protected
;
else if (! TREE_VIA_PUBLIC (types
))
visibility
= visibility_private
;
/* No special visibilities apply. Use normal rules.
No assignment needed for BASETYPEs here from the nreverse.
This is because we use it only for information about the
path to the base. The code earlier dealt with what
happens when we are at the base level. */
if (visibility
== visibility_public
)
basetype_path
= reverse_path (basetype_path
);
if (TREE_PRIVATE (field
))
if (TREE_PROTECTED (field
))
/* Used to check if the current class type was derived from
the type that contains the field. This is wrong for
multiple inheritance because is gives one class reference
to protected members via another classes protected path.
I.e., if A; B1 : A; B2 : A; Then B1 and B2 can access
their own members which are protected in A, but not
those same members in one another. */
&& UNIQUELY_DERIVED_FROM_P (context
, current_class_type
))
if (visibility
== visibility_protected
)
if (TREE_PRIVATE (field
))
/* We want to make sure that all non-private members in
the current class (as derived) are accessible. */
&& UNIQUELY_DERIVED_FROM_P (context
, current_class_type
))
if (visibility
== visibility_private
&& current_class_type
!= NULL_TREE
)
if (TREE_PRIVATE (field
))
reverse_path (basetype_path
);
/* See if the field isn't protected. */
if (TREE_PROTECTED (field
))
tree test
= basetype_path
;
if (BINFO_TYPE (test
) == current_class_type
)
test
= BINFO_INHERITANCE_CHAIN (test
);
reverse_path (basetype_path
);
/* See if the field isn't a public member of
visibility
= visibility_public
;
types
= BINFO_INHERITANCE_CHAIN (basetype_path
);
if (! TREE_VIA_PUBLIC (types
))
if (visibility
== visibility_private
)
visibility
= visibility_private
;
visibility
= visibility_private
;
if (BINFO_TYPE (types
) == context
)
visibility
= visibility_public
;
types
= BINFO_INHERITANCE_CHAIN (types
);
reverse_path (basetype_path
);
if (visibility
== visibility_public
)
else if (visibility
== visibility_protected
)
DECL_PROTECTED (field
) = 1;
else if (visibility
== visibility_private
)
DECL_PRIVATE (field
) = 1;
else my_friendly_abort (96);
/* Routine to see if the sub-object denoted by the binfo PARENT can be
found as a base class and sub-object of the object denoted by
BINFO. This routine relies upon binfos not being shared, except
for binfos for virtual bases. */
is_subobject_of_p (parent
, binfo
)
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (TREE_VIA_VIRTUAL (base_binfo
))
base_binfo
= TYPE_BINFO (BINFO_TYPE (base_binfo
));
if (is_subobject_of_p (parent
, base_binfo
))
/* See if a one FIELD_DECL hides another. This routine is meant to
correspond to ANSI working paper Sept 17, 1992 10p4. The two
binfos given are the binfos corresponding to the particular places
the FIELD_DECLs are found. This routine relies upon binfos not
being shared, except for virtual bases. */
hides (hider_binfo
, hidee_binfo
)
tree hider_binfo
, hidee_binfo
;
/* hider hides hidee, if hider has hidee as a base class and
the instance of hidee is a sub-object of hider. The first
part is always true is the second part is true.
When hider and hidee are the same (two ways to get to the exact
same member) we consider either one as hiding the other. */
return is_subobject_of_p (hidee_binfo
, hider_binfo
);
/* Very similar to lookup_fnfields_1 but it ensures that at least one
function was declared inside the class given by TYPE. It really should
only return functions that match the given TYPE. */
lookup_fnfields_here (type
, name
)
int index
= lookup_fnfields_1 (type
, name
);
fndecls
= TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), index
);
if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls
))
== TYPE_MAIN_VARIANT (type
))
fndecls
= TREE_CHAIN (fndecls
);
/* Look for a field named NAME in an inheritance lattice dominated by
XBASETYPE. PROTECT is zero if we can avoid computing visibility
information, otherwise it is 1. WANT_TYPE is 1 when we should only
return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE.
It was not clear what should happen if WANT_TYPE is set, and an
ambiguity is found. At least one use (lookup_name) to not see
lookup_field (xbasetype
, name
, protect
, want_type
)
register tree xbasetype
, name
;
tree rval
, rval_binfo
= NULL_TREE
, rval_binfo_h
;
tree type
, basetype_chain
, basetype_path
;
enum visibility_type this_v
= visibility_default
;
tree entry
, binfo
, binfo_h
;
enum visibility_type own_visibility
= visibility_default
;
int vbase_name_p
= VBASE_NAME_P (name
);
/* rval_binfo is the binfo associated with the found member, note,
this can be set with useful information, even when rval is not
set, because it must deal with ALL members, not just non-function
members. It is used for ambiguity checking and the hidden
checks. Whereas rval is only set if a proper (not hidden)
non-function member is found. */
/* rval_binfo_h and binfo_h are binfo values used when we perform the
hiding checks, as virtual base classes may not be shared. The strategy
is we always go into the the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
/* Things for memoization. */
/* Set this to nonzero if we don't know how to compute
accurate error messages for visibility. */
int index
= MEMOIZED_HASH_FN (name
);
if (TREE_CODE (xbasetype
) == TREE_VEC
)
basetype_path
= xbasetype
, type
= BINFO_TYPE (xbasetype
);
else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype
)))
basetype_path
= TYPE_BINFO (xbasetype
), type
= xbasetype
;
else my_friendly_abort (97);
if (CLASSTYPE_MTABLE_ENTRY (type
))
tree tem
= MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type
), index
);
while (tem
&& TREE_PURPOSE (tem
) != name
)
memoized_fields_searched
[0]++;
if (protect
&& TREE_TYPE (tem
))
error (TREE_STRING_POINTER (TREE_TYPE (tem
)),
IDENTIFIER_POINTER (name
),
TYPE_NAME_STRING (DECL_FIELD_CONTEXT (TREE_VALUE (tem
))));
if (TREE_VALUE (tem
) == NULL_TREE
)
memoized_fast_rejects
[0] += 1;
memoized_fast_finds
[0] += 1;
if (protect
&& flag_memoize_lookups
&& ! global_bindings_p ())
entry
= make_memoized_table_entry (type
, name
, 0);
rval
= lookup_field_1 (type
, name
);
if (rval
|| lookup_fnfields_here (type
, name
)>=0)
rval_binfo
= basetype_path
;
rval_binfo_h
= rval_binfo
;
if (rval
&& TREE_CODE (rval
) != TYPE_DECL
&& want_type
)
if (TREE_PRIVATE (rval
) | TREE_PROTECTED (rval
))
this_v
= compute_visibility (basetype_path
, rval
);
if (TREE_CODE (rval
) == CONST_DECL
)
if (this_v
== visibility_private
)
errstr
= "enum `%s' is a private value of class `%s'";
else if (this_v
== visibility_protected
)
errstr
= "enum `%s' is a protected value of class `%s'";
if (this_v
== visibility_private
)
errstr
= "member `%s' is a private member of class `%s'";
else if (this_v
== visibility_protected
)
errstr
= "member `%s' is a protected member of class `%s'";
/* This depends on behavior of lookup_field_1! */
tree error_string
= my_build_string (errstr
);
TREE_TYPE (entry
) = error_string
;
/* Let entry know there is no problem with this access. */
TREE_TYPE (entry
) = NULL_TREE
;
TREE_VALUE (entry
) = rval
;
error (errstr
, IDENTIFIER_POINTER (name
), TYPE_NAME_STRING (type
));
basetype_chain
= CLASSTYPE_BINFO_AS_LIST (type
);
TREE_VIA_PUBLIC (basetype_chain
) = 1;
/* The ambiguity check relies upon breadth first searching. */
search_stack
= push_search_level (search_stack
, &search_obstack
);
BINFO_VIA_PUBLIC (basetype_path
) = 1;
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_FIELDS_MARKED (base_binfo
) == 0)
SET_BINFO_FIELDS_MARKED (base_binfo
);
btypes
= my_tree_cons (NULL_TREE
, base_binfo
, basetype_chain
);
TREE_VIA_PUBLIC (btypes
) = TREE_VIA_PUBLIC (base_binfo
);
TREE_VIA_PROTECTED (btypes
) = TREE_VIA_PROTECTED (base_binfo
);
TREE_VIA_VIRTUAL (btypes
) = TREE_VIA_VIRTUAL (base_binfo
);
if (TREE_VIA_VIRTUAL (base_binfo
))
btypes
= tree_cons (NULL_TREE
,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h
), i
))),
btypes
= tree_cons (NULL_TREE
,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h
), i
),
obstack_ptr_grow (&search_obstack
, btypes
);
if (tail
>= search_stack
->limit
)
/* Process head of queue, if one exists. */
basetype_chain
= search_stack
->first
[head
++];
binfo_h
= TREE_VALUE (basetype_chain
);
basetype_chain
= TREE_CHAIN (basetype_chain
);
basetype_path
= TREE_VALUE (basetype_chain
);
if (TREE_CHAIN (basetype_chain
))
BINFO_INHERITANCE_CHAIN (basetype_path
) = TREE_VALUE (TREE_CHAIN (basetype_chain
));
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
type
= BINFO_TYPE (binfo
);
/* See if we can find NAME in TYPE. If RVAL is nonzero,
and we do find NAME in TYPE, verify that such a second
sighting is in fact legal. */
nval
= lookup_field_1 (type
, name
);
if (nval
|| lookup_fnfields_here (type
, name
)>=0)
if (rval_binfo
&& hides (rval_binfo_h
, binfo_h
))
/* This is ok, the member found is in rval_binfo, not
else if (rval_binfo
==NULL_TREE
|| hides (binfo_h
, rval_binfo_h
))
/* This is ok, the member found is here (binfo), not in
this_v
= compute_visibility (basetype_path
, rval
);
/* These may look ambiguous, but they really are not. */
/* Undo finding it before, as something else hides it. */
errstr
= "request for member `%s' is ambiguous";
tree
*tp
= search_stack
->first
;
tree
*search_tail
= tp
+ tail
;
TREE_VALUE (entry
) = rval
;
if (want_type
&& (rval
== NULL_TREE
|| TREE_CODE (rval
) != TYPE_DECL
))
/* If this FIELD_DECL defines its own visibility, deal with that. */
&& ((protect
&1) || entry
)
&& DECL_LANG_SPECIFIC (rval
)
&& DECL_VISIBILITY (rval
))
/* If is possible for one of the derived types on the
path to have defined special visibility for this
field. Look for such declarations and report an
error if a conflict is found. */
enum visibility_type new_v
;
if (this_v
!= visibility_default
)
new_v
= compute_visibility (TREE_VALUE (TREE_CHAIN (*tp
)), rval
);
if (this_v
!= visibility_default
&& new_v
!= this_v
)
errstr
= "conflicting visibilities to member `%s'";
this_v
= visibility_default
;
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp
)));
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp
)));
search_stack
= pop_search_level (search_stack
);
if (own_visibility
== visibility_private
)
errstr
= "member `%s' declared private";
else if (own_visibility
== visibility_protected
)
errstr
= "member `%s' declared protected";
else if (this_v
== visibility_private
)
errstr
= TREE_PRIVATE (rval
)
? "member `%s' is private"
: "member `%s' is from private base class";
else if (this_v
== visibility_protected
)
errstr
= TREE_PROTECTED (rval
)
? "member `%s' is protected"
: "member `%s' is from protected base class";
tree error_string
= my_build_string (errstr
);
/* Save error message with entry. */
TREE_TYPE (entry
) = error_string
;
/* Mark entry as having no error string. */
TREE_TYPE (entry
) = NULL_TREE
;
error (errstr
, IDENTIFIER_POINTER (name
), TYPE_NAME_STRING (type
));
/* Try to find NAME inside a nested class. */
lookup_nested_field (name
, complain
)
if (TREE_CHAIN (current_class_type
))
/* Climb our way up the nested ladder, seeing if we're trying to
modify a field in an enclosing class. If so, we should only
be able to modify if it's static. */
for (t
= TREE_CHAIN (current_class_type
);
t
= TREE_CHAIN (DECL_CONTEXT (t
)))
if (TREE_CODE (DECL_CONTEXT (t
)) != RECORD_TYPE
)
/* N.B.: lookup_field will do the visibility checking for us */
id
= lookup_field (DECL_CONTEXT (t
), name
, complain
, 0);
if (id
== error_mark_node
)
if (TREE_CODE (id
) == FIELD_DECL
&& TREE_TYPE (id
) != error_mark_node
)
/* At parse time, we don't want to give this error, since
we won't have enough state to make this kind of
decision properly. But there are times (e.g., with
enums in nested classes) when we do need to call
this fn at parse time. So, in those cases, we pass
complain as a 0 and just return a NULL_TREE. */
error ("assignment to non-static member `%s' of enclosing class `%s'",
lang_printable_name (id
),
IDENTIFIER_POINTER (TYPE_IDENTIFIER
/* Mark this for do_identifier(). It would otherwise
claim that the variable was undeclared. */
TREE_TYPE (id
) = error_mark_node
;
/* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */
lookup_fnfields_1 (type
, name
)
register tree method_vec
= CLASSTYPE_METHOD_VEC (type
);
register tree
*methods
= &TREE_VEC_ELT (method_vec
, 0);
register tree
*end
= TREE_VEC_END (method_vec
);
n_calls_lookup_fnfields_1
++;
if (*methods
&& name
== constructor_name (type
))
n_outer_fields_searched
++;
if (DECL_NAME (*methods
) == name
)
return methods
- &TREE_VEC_ELT (method_vec
, 0);
/* Starting from BASETYPE, return a TREE_BASELINK-like object
which gives the following information (in a list):
TREE_TYPE: list of basetypes needed to get to...
TREE_VALUE: list of all functions in of given type
No visibility information is computed by this function,
other then to adorn the list of basetypes with
If there are two ways to find a name (two members), if COMPLAIN is
non-zero, then error_mark_node is returned, and an error message is
printed, otherwise, just an error_mark_node is returned.
As a special case, is COMPLAIN is -1, we don't complain, and we
don't return error_mark_node, but rather the complete list of
virtuals. This is used by get_virtuals_named_this. */
lookup_fnfields (basetype_path
, name
, complain
)
tree basetype_path
, name
;
tree type
, rval
, rval_binfo
= NULL_TREE
, rvals
= NULL_TREE
, rval_binfo_h
;
tree entry
, binfo
, basetype_chain
, binfo_h
;
/* rval_binfo is the binfo associated with the found member, note,
this can be set with useful information, even when rval is not
set, because it must deal with ALL members, not just function
members. It is used for ambiguity checking and the hidden
checks. Whereas rval is only set if a proper (not hidden)
function member is found. */
/* rval_binfo_h and binfo_h are binfo values used when we perform the
hiding checks, as virtual base classes may not be shared. The strategy
is we always go into the the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
/* For now, don't try this. */
/* Things for memoization. */
/* Set this to nonzero if we don't know how to compute
accurate error messages for visibility. */
int index
= MEMOIZED_HASH_FN (name
);
type
= BINFO_TYPE (basetype_path
);
/* The memoization code is in need of maintenance. */
if (!find_all
&& CLASSTYPE_MTABLE_ENTRY (type
))
tree tem
= MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type
), index
);
while (tem
&& TREE_PURPOSE (tem
) != name
)
memoized_fields_searched
[1]++;
if (protect
&& TREE_TYPE (tem
))
error (TREE_STRING_POINTER (TREE_TYPE (tem
)),
IDENTIFIER_POINTER (name
),
TYPE_NAME_STRING (DECL_CLASS_CONTEXT (TREE_VALUE (TREE_VALUE (tem
)))));
if (TREE_VALUE (tem
) == NULL_TREE
)
memoized_fast_rejects
[1] += 1;
/* Want to return this, but we must make sure
that visibility information is consistent. */
tree baselink
= TREE_VALUE (tem
);
tree memoized_basetypes
= TREE_PURPOSE (baselink
);
tree these_basetypes
= basetype_path
;
while (memoized_basetypes
&& these_basetypes
)
memoized_fields_searched
[1]++;
if (TREE_VALUE (memoized_basetypes
) != these_basetypes
)
memoized_basetypes
= TREE_CHAIN (memoized_basetypes
);
these_basetypes
= BINFO_INHERITANCE_CHAIN (these_basetypes
);
/* The following statement is true only when both are NULL. */
if (memoized_basetypes
== these_basetypes
)
memoized_fast_finds
[1] += 1;
/* else, we must re-find this field by hand. */
baselink
= tree_cons (basetype_path
, TREE_VALUE (baselink
), TREE_CHAIN (baselink
));
n_calls_lookup_fnfields
++;
if (protect
&& flag_memoize_lookups
&& ! global_bindings_p ())
entry
= make_memoized_table_entry (type
, name
, 1);
index
= lookup_fnfields_here (type
, name
);
if (index
>= 0 || lookup_field_1 (type
, name
))
rval_binfo
= basetype_path
;
rval_binfo_h
= rval_binfo
;
rval
= TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), index
);
rvals
= my_tree_cons (basetype_path
, rval
, rvals
);
if (BINFO_BASETYPES (binfo
) && CLASSTYPE_BASELINK_VEC (type
))
TREE_TYPE (rvals
) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type
), index
);
TREE_VALUE (entry
) = rvals
;
TREE_TYPE (entry
) = NULL_TREE
;
error (errstr
, IDENTIFIER_POINTER (name
), TYPE_NAME_STRING (type
));
basetype_chain
= CLASSTYPE_BINFO_AS_LIST (type
);
TREE_VIA_PUBLIC (basetype_chain
) = 1;
/* The ambiguity check relies upon breadth first searching. */
search_stack
= push_search_level (search_stack
, &search_obstack
);
BINFO_VIA_PUBLIC (basetype_path
) = 1;
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_FIELDS_MARKED (base_binfo
) == 0)
SET_BINFO_FIELDS_MARKED (base_binfo
);
btypes
= my_tree_cons (NULL_TREE
, base_binfo
, basetype_chain
);
TREE_VIA_PUBLIC (btypes
) = TREE_VIA_PUBLIC (base_binfo
);
TREE_VIA_PROTECTED (btypes
) = TREE_VIA_PROTECTED (base_binfo
);
TREE_VIA_VIRTUAL (btypes
) = TREE_VIA_VIRTUAL (base_binfo
);
if (TREE_VIA_VIRTUAL (base_binfo
))
btypes
= tree_cons (NULL_TREE
,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h
), i
))),
btypes
= tree_cons (NULL_TREE
,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h
), i
),
obstack_ptr_grow (&search_obstack
, btypes
);
if (tail
>= search_stack
->limit
)
/* Process head of queue, if one exists. */
basetype_chain
= search_stack
->first
[head
++];
binfo_h
= TREE_VALUE (basetype_chain
);
basetype_chain
= TREE_CHAIN (basetype_chain
);
basetype_path
= TREE_VALUE (basetype_chain
);
if (TREE_CHAIN (basetype_chain
))
BINFO_INHERITANCE_CHAIN (basetype_path
) = TREE_VALUE (TREE_CHAIN (basetype_chain
));
BINFO_INHERITANCE_CHAIN (basetype_path
) = NULL_TREE
;
type
= BINFO_TYPE (binfo
);
/* See if we can find NAME in TYPE. If RVAL is nonzero,
and we do find NAME in TYPE, verify that such a second
sighting is in fact legal. */
index
= lookup_fnfields_here (type
, name
);
if (index
>= 0 || (lookup_field_1 (type
, name
)!=NULL_TREE
&& !find_all
))
if (rval_binfo
&& !find_all
&& hides (rval_binfo_h
, binfo_h
))
/* This is ok, the member found is in rval_binfo, not
else if (rval_binfo
==NULL_TREE
|| find_all
|| hides (binfo_h
, rval_binfo_h
))
/* This is ok, the member found is here (binfo), not in
rval
= TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), index
);
/* Note, rvals can only be previously set if find_all is
rvals
= my_tree_cons (basetype_path
, rval
, rvals
);
if (TYPE_BINFO_BASETYPES (type
)
&& CLASSTYPE_BASELINK_VEC (type
))
TREE_TYPE (rvals
) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type
), index
);
/* Undo finding it before, as something else hides it. */
errstr
= "request for member `%s' is ambiguous";
tree
*tp
= search_stack
->first
;
tree
*search_tail
= tp
+ tail
;
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp
)));
search_stack
= pop_search_level (search_stack
);
tree error_string
= my_build_string (errstr
);
/* Save error message with entry. */
TREE_TYPE (entry
) = error_string
;
/* Mark entry as having no error string. */
TREE_TYPE (entry
) = NULL_TREE
;
TREE_VALUE (entry
) = rvals
;
error (errstr
, IDENTIFIER_POINTER (name
), TYPE_NAME_STRING (type
));
/* BREADTH-FIRST SEARCH ROUTINES. */
/* Search a multiple inheritance hierarchy by breadth-first search.
TYPE is an aggregate type, possibly in a multiple-inheritance hierarchy.
TESTFN is a function, which, if true, means that our condition has been met,
and its return value should be returned.
QFN, if non-NULL, is a predicate dictating whether the type should
breadth_first_search (binfo
, testfn
, qfn
)
search_stack
= push_search_level (search_stack
, &search_obstack
);
tree binfos
= BINFO_BASETYPES (binfo
);
int n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (BINFO_MARKED (base_binfo
) == 0
&& (qfn
== 0 || (*qfn
) (binfo
, i
)))
SET_BINFO_MARKED (base_binfo
);
obstack_ptr_grow (&search_obstack
, binfo
);
obstack_ptr_grow (&search_obstack
, (HOST_WIDE_INT
) i
);
if (tail
>= search_stack
->limit
)
/* Process head of queue, if one exists. */
binfo
= search_stack
->first
[head
++];
i
= (int) search_stack
->first
[head
++];
if (rval
= (*testfn
) (binfo
, i
))
binfo
= BINFO_BASETYPE (binfo
, i
);
tree
*tp
= search_stack
->first
;
tree
*search_tail
= tp
+ tail
;
int i
= (HOST_WIDE_INT
)(*tp
++);
CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo
, i
));
search_stack
= pop_search_level (search_stack
);
/* Functions to use in breadth first searches. */
int tree_needs_constructor_p (binfo
, i
)
my_friendly_assert (i
!= 0, 296);
basetype
= BINFO_TYPE (BINFO_BASETYPE (binfo
, i
));
return TYPE_NEEDS_CONSTRUCTOR (basetype
);
get_virtuals_named_this (binfo
)
fields
= lookup_fnfields (binfo
, declarator
, -1);
/* fields cannot be error_mark_node */
/* Get to the function decls, and return the first virtual function
with this name, if there is one. */
for (fndecl
= TREE_VALUE (fields
); fndecl
; fndecl
= DECL_CHAIN (fndecl
))
if (DECL_VINDEX (fndecl
))
fields
= next_baselink (fields
);
static tree
get_virtual_destructor (binfo
, i
)
tree type
= BINFO_TYPE (binfo
);
type
= BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo
), i
));
if (TYPE_HAS_DESTRUCTOR (type
)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), 0)))
return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), 0);
int tree_has_any_destructor_p (binfo
, i
)
tree type
= BINFO_TYPE (binfo
);
type
= BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo
), i
));
return TYPE_NEEDS_DESTRUCTOR (type
);
/* Given a class type TYPE, and a function decl FNDECL,
look for the first function the TYPE's hierarchy which
FNDECL could match as a virtual function.
DTORP is nonzero if we are looking for a destructor. Destructors
need special treatment because they do not match by name. */
get_first_matching_virtual (binfo
, fndecl
, dtorp
)
/* Breadth first search routines start searching basetypes
of TYPE, so we must perform first ply of search here. */
if (tree_has_any_destructor_p (binfo
, -1))
tmp
= get_virtual_destructor (binfo
, -1);
if (get_base_distance (DECL_CONTEXT (tmp
),
DECL_CONTEXT (fndecl
), 0, 0) > 0)
DECL_CONTEXT (fndecl
) = DECL_CONTEXT (tmp
);
tmp
= (tree
) breadth_first_search (binfo
,
(pfi
) get_virtual_destructor
,
tree_has_any_destructor_p
);
if (get_base_distance (DECL_CONTEXT (tmp
),
DECL_CONTEXT (fndecl
), 0, 0) > 0)
DECL_CONTEXT (fndecl
) = DECL_CONTEXT (tmp
);
tree drettype
, dtypes
, btypes
, instptr_type
;
tree basetype
= DECL_CLASS_CONTEXT (fndecl
);
tree baselink
, best
= NULL_TREE
;
tree name
= DECL_ASSEMBLER_NAME (fndecl
);
declarator
= DECL_NAME (fndecl
);
if (IDENTIFIER_VIRTUAL_P (declarator
) == 0)
drettype
= TREE_TYPE (TREE_TYPE (fndecl
));
dtypes
= TYPE_ARG_TYPES (TREE_TYPE (fndecl
));
if (DECL_STATIC_FUNCTION_P (fndecl
))
instptr_type
= NULL_TREE
;
instptr_type
= TREE_TYPE (TREE_VALUE (dtypes
));
for (baselink
= get_virtuals_named_this (binfo
);
baselink
; baselink
= next_baselink (baselink
))
for (tmp
= TREE_VALUE (baselink
); tmp
; tmp
= DECL_CHAIN (tmp
))
btypes
= TYPE_ARG_TYPES (TREE_TYPE (tmp
));
if (instptr_type
== NULL_TREE
)
if (compparms (TREE_CHAIN (btypes
), dtypes
, 3))
/* Caller knows to give error in this case. */
if ((TYPE_READONLY (TREE_TYPE (TREE_VALUE (btypes
)))
== TYPE_READONLY (instptr_type
))
&& compparms (TREE_CHAIN (btypes
), TREE_CHAIN (dtypes
), 3))
if (IDENTIFIER_ERROR_LOCUS (name
) == NULL_TREE
&& ! comptypes (TREE_TYPE (TREE_TYPE (tmp
)), drettype
, 1))
error_with_decl (fndecl
, "conflicting return type specified for virtual function `%s'");
SET_IDENTIFIER_ERROR_LOCUS (name
, basetype
);
/* If this is ambiguous, we will warn about it later. */
if (get_base_distance (DECL_CLASS_CONTEXT (best
),
DECL_CLASS_CONTEXT (tmp
), 0, 0) > 0)
if (IDENTIFIER_ERROR_LOCUS (name
) == NULL_TREE
&& best
== NULL_TREE
&& warn_overloaded_virtual
)
warning_with_decl (fndecl
,
"conflicting specification deriving virtual function `%s'");
SET_IDENTIFIER_ERROR_LOCUS (name
, basetype
);
if (get_base_distance (DECL_CONTEXT (best
),
DECL_CONTEXT (fndecl
), 0, 0) > 0)
DECL_CONTEXT (fndecl
) = DECL_CONTEXT (best
);
/* Return the list of virtual functions which are abstract in type TYPE.
This information is cached, and so must be built on a
non-temporary obstack. */
get_abstract_virtuals (type
)
/* For each layer of base class (i.e., the first base class, and each
virtual base class from that one), modify the virtual function table
of the derived class to contain the new virtual function.
A class has as many vfields as it has virtual base classes (total). */
tree vfields
, vbases
, base
, tmp
;
tree vfield
= CLASSTYPE_VFIELD (type
);
tree fcontext
= vfield
? DECL_FCONTEXT (vfield
) : NULL_TREE
;
tree abstract_virtuals
= CLASSTYPE_ABSTRACT_VIRTUALS (type
);
for (vfields
= CLASSTYPE_VFIELDS (type
); vfields
; vfields
= TREE_CHAIN (vfields
))
/* This code is most likely wrong, and probably only works for single
inheritance or by accident. */
/* Find the right base class for this derived class, call it BASE. */
base
= VF_BASETYPE_VALUE (vfields
);
/* We call this case NORMAL iff this virtual function table
pointer field has its storage reserved in this class.
This is normally the case without virtual baseclasses
or off-center multiple baseclasses. */
normal
= (base
== fcontext
&& (VF_BINFO_VALUE (vfields
) == NULL_TREE
|| ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields
))));
tmp
= TREE_CHAIN (TYPE_BINFO_VIRTUALS (type
));
/* n.b.: VF_BASETYPE_VALUE (vfields) is the first basetype
that provides the virtual function table, whereas
VF_DERIVED_VALUE (vfields) is an immediate base type of TYPE
that dominates VF_BASETYPE_VALUE (vfields). The list of
vfields we want lies between these two values. */
tree binfo
= get_binfo (VF_NORMAL_VALUE (vfields
), type
, 0);
tmp
= TREE_CHAIN (BINFO_VIRTUALS (binfo
));
/* Get around dossier entry if there is one. */
tree base_pfn
= FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp
));
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
);
for (vbases
= CLASSTYPE_VBASECLASSES (type
); vbases
; vbases
= TREE_CHAIN (vbases
))
if (! BINFO_VIRTUALS (vbases
))
tmp
= TREE_CHAIN (BINFO_VIRTUALS (vbases
));
tree base_pfn
= FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp
));
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
);
return nreverse (abstract_virtuals
);
/* For the type TYPE, return a list of member functions available from
base classes with name NAME. The TREE_VALUE of the list is a chain of
member functions with name NAME. The TREE_PURPOSE of the list is a
basetype, or a list of base types (in reverse order) which were
traversed to reach the chain of member functions. If we reach a base
type which provides a member function of name NAME, and which has at
most one base type itself, then we can terminate the search. */
get_baselinks (type_as_binfo_list
, type
, name
)
int head
= 0, tail
= 0, index
;
tree basetypes
= type_as_binfo_list
;
tree binfo
= TYPE_BINFO (type
);
search_stack
= push_search_level (search_stack
, &search_obstack
);
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
/* Process and/or queue base types. */
for (i
= 0; i
< n_baselinks
; i
++)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
btypes
= hash_tree_cons (TREE_VIA_PUBLIC (base_binfo
),
TREE_VIA_VIRTUAL (base_binfo
),
TREE_VIA_PROTECTED (base_binfo
),
obstack_ptr_grow (&search_obstack
, btypes
);
search_stack
->first
= (tree
*)obstack_base (&search_obstack
);
/* Process head of queue, if one exists. */
basetypes
= search_stack
->first
[head
++];
binfo
= TREE_VALUE (basetypes
);
type
= BINFO_TYPE (binfo
);
index
= lookup_fnfields_1 (type
, name
);
nval
= TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type
), index
);
rval
= hash_tree_cons (0, 0, 0, basetypes
, nval
, rval
);
if (TYPE_BINFO_BASETYPES (type
) == 0)
else if (TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type
)) == 1)
if (CLASSTYPE_BASELINK_VEC (type
))
TREE_TYPE (rval
) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type
), index
);
search_stack
= pop_search_level (search_stack
);
tree tmp
= TREE_TYPE (baselink
);
baselink
= TREE_CHAIN (baselink
);
/* @@ does not yet add previous base types. */
baselink
= tree_cons (TREE_PURPOSE (tmp
), TREE_VALUE (tmp
),
TREE_TYPE (baselink
) = TREE_TYPE (tmp
);
/* DEPTH-FIRST SEARCH ROUTINES. */
/* Assign unique numbers to _CLASSTYPE members of the lattice
specified by TYPE. The root nodes are marked first; the nodes
are marked depth-fisrt, left-right. */
/* Matrix implementing a relation from CLASSTYPE X CLASSTYPE => INT.
Relation yields 1 if C1 <= C2, 0 otherwise. */
static mi_boolean
*mi_matrix
;
/* Type for which this matrix is defined. */
/* Size of the matrix for indexing purposes. */
/* Return nonzero if class C2 derives from class C1. */
#define BINFO_DERIVES_FROM(C1, C2) \
((mi_matrix+mi_size*(BINFO_CID (C1)-1))[BINFO_CID (C2)-1])
#define TYPE_DERIVES_FROM(C1, C2) \
((mi_matrix+mi_size*(CLASSTYPE_CID (C1)-1))[CLASSTYPE_CID (C2)-1])
#define BINFO_DERIVES_FROM_STAR(C) \
(mi_matrix+(BINFO_CID (C)-1))
/* This routine converts a pointer to be a pointer of an immediate
base class. The normal convert_pointer_to routine would diagnose
the conversion as ambiguous, under MI code that has the base class
as an ambiguous base class. */
convert_pointer_to_single_level (to_type
, expr
)
binfo_of_derived
= TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr
)));
last
= get_binfo (to_type
, TREE_TYPE (TREE_TYPE (expr
)), 0);
BINFO_INHERITANCE_CHAIN (last
) = binfo_of_derived
;
BINFO_INHERITANCE_CHAIN (binfo_of_derived
) = NULL_TREE
;
return build_vbase_path (PLUS_EXPR
, TYPE_POINTER_TO (to_type
), expr
, last
, 1);
/* The main function which implements depth first search.
This routine has to remember the path it walked up, when
dfs_init_vbase_pointers is the work function, as otherwise there
dfs_walk (binfo
, fn
, qfn
)
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
);
if (fn
== dfs_init_vbase_pointers
)
/* When traversing an arbitrary MI hierarchy, we need to keep
a record of the path we took to get down to the final base
type, as otherwise there would be no record of it, and just
trying to blindly convert at the bottom would be ambiguous.
The easiest way is to do the conversions one step at a time,
as we know we want the immediate base class at each step.
The only special trick to converting one step at a time,
is that when we hit the last virtual base class, we must
use the SLOT value for it, and not use the normal convert
routine. We use the last virtual base class, as in our
implementation, we have pointers to all virtual base
classes in the base object. */
tree saved_vbase_decl_ptr_intermediate
= vbase_decl_ptr_intermediate
;
if (TREE_VIA_VIRTUAL (base_binfo
))
/* No need for the conversion here, as we know it is the
vbase_decl_ptr_intermediate
=
(tree
)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo
));
#ifdef CHECK_convert_pointer_to_single_level
/* This code here introduces a little software fault
tolerance It should be that case that the second
one always gets the same valid answer that the
first one gives, if the first one gives a valid
If it doesn't, the second algorithm is at fault
The first one is known to be bad and produce
error_mark_node when dealing with MI base
classes. It is the only problem supposed to be
#ifdef CHECK_convert_pointer_to_single_level
vdpi1
= convert_pointer_to (BINFO_TYPE (base_binfo
),
vbase_decl_ptr_intermediate
);
vdpi2
= convert_pointer_to_single_level (BINFO_TYPE (base_binfo
),
vbase_decl_ptr_intermediate
);
vbase_decl_ptr_intermediate
= vdpi2
;
#ifdef CHECK_convert_pointer_to_single_level
if (vdpi1
== error_mark_node
&& vdpi2
!= vdpi1
)
warning ("internal: Don't worry, be happy, I can fix tangs man. (ignore above error)");
else if (simple_cst_equal (vdpi1
, vdpi2
) != 1) {
if (simple_cst_equal (vdpi1
, vdpi2
) == 0)
warning ("internal: convert_pointer_to_single_level: They are not the same, going with old algorithm");
warning ("internal: convert_pointer_to_single_level: They might not be the same, going with old algorithm");
vbase_decl_ptr_intermediate
= vdpi1
;
dfs_walk (base_binfo
, fn
, qfn
);
vbase_decl_ptr_intermediate
= saved_vbase_decl_ptr_intermediate
;
dfs_walk (base_binfo
, fn
, qfn
);
/* Predicate functions which serve for dfs_walk. */
static int numberedp (binfo
) tree binfo
;
{ return BINFO_CID (binfo
); }
static int unnumberedp (binfo
) tree binfo
;
{ return BINFO_CID (binfo
) == 0; }
static int markedp (binfo
) tree binfo
;
{ return BINFO_MARKED (binfo
); }
static int bfs_markedp (binfo
, i
) tree binfo
; int i
;
{ return BINFO_MARKED (BINFO_BASETYPE (binfo
, i
)); }
static int unmarkedp (binfo
) tree binfo
;
{ return BINFO_MARKED (binfo
) == 0; }
static int bfs_unmarkedp (binfo
, i
) tree binfo
; int i
;
{ return BINFO_MARKED (BINFO_BASETYPE (binfo
, i
)) == 0; }
static int marked_vtable_pathp (binfo
) tree binfo
;
{ return BINFO_VTABLE_PATH_MARKED (binfo
); }
static int bfs_marked_vtable_pathp (binfo
, i
) tree binfo
; int i
;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo
, i
)); }
static int unmarked_vtable_pathp (binfo
) tree binfo
;
{ return BINFO_VTABLE_PATH_MARKED (binfo
) == 0; }
static int bfs_unmarked_vtable_pathp (binfo
, i
) tree binfo
; int i
;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo
, i
)) == 0; }
static int marked_new_vtablep (binfo
) tree binfo
;
{ return BINFO_NEW_VTABLE_MARKED (binfo
); }
static int bfs_marked_new_vtablep (binfo
, i
) tree binfo
; int i
;
{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo
, i
)); }
static int unmarked_new_vtablep (binfo
) tree binfo
;
{ return BINFO_NEW_VTABLE_MARKED (binfo
) == 0; }
static int bfs_unmarked_new_vtablep (binfo
, i
) tree binfo
; int i
;
{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo
, i
)) == 0; }
static int dfs_search_slot_nonempty_p (binfo
) tree binfo
;
{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo
)) != 0; }
static int dfs_debug_unmarkedp (binfo
) tree binfo
;
{ return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo
)) == 0; }
/* The worker functions for `dfs_walk'. These do not need to
test anything (vis a vis marking) if they are paired with
a predicate function (above). */
/* Assign each type within the lattice a number which is unique
in the lattice. The first number assigned is 1. */
BINFO_CID (binfo
) = ++cid
;
dfs_mark (binfo
) tree binfo
;
{ SET_BINFO_MARKED (binfo
); }
dfs_unmark (binfo
) tree binfo
;
{ CLEAR_BINFO_MARKED (binfo
); }
dfs_mark_vtable_path (binfo
) tree binfo
;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo
); }
dfs_unmark_vtable_path (binfo
) tree binfo
;
{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo
); }
dfs_mark_new_vtable (binfo
) tree binfo
;
{ SET_BINFO_NEW_VTABLE_MARKED (binfo
); }
dfs_unmark_new_vtable (binfo
) tree binfo
;
{ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo
); }
dfs_clear_search_slot (binfo
) tree binfo
;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo
)) = 0; }
tree t
= BINFO_TYPE (binfo
);
/* Use heuristic that if there are virtual functions,
ignore until we see a non-inline virtual function. */
tree methods
= CLASSTYPE_METHOD_VEC (t
);
CLASSTYPE_DEBUG_REQUESTED (t
) = 1;
/* If interface info is known, the value of (?@@?) is correct. */
|| ! CLASSTYPE_INTERFACE_UNKNOWN (t
)
|| (write_virtuals
== 2 && TYPE_VIRTUAL_P (t
)))
/* If debug info is requested from this context for this type, supply it.
If debug info is requested from another context for this type,
see if some third context can supply it. */
if (current_function_decl
== NULL_TREE
|| DECL_CLASS_CONTEXT (current_function_decl
) != t
)
if (TREE_VEC_ELT (methods
, 0))
methods
= TREE_VEC_ELT (methods
, 0);
methods
= TREE_VEC_ELT (methods
, 1);
if (DECL_VINDEX (methods
)
&& DECL_SAVED_INSNS (methods
) == 0
&& DECL_PENDING_INLINE_INFO (methods
) == 0
&& DECL_ABSTRACT_VIRTUAL_P (methods
) == 0)
/* Somebody, somewhere is going to have to define this
virtual function. When they do, they will provide
methods
= TREE_CHAIN (methods
);
/* We cannot rely on some alien method to solve our problems,
so we must write out the debug info ourselves. */
DECL_IGNORED_P (TYPE_NAME (t
)) = 0;
if (! TREE_ASM_WRITTEN (TYPE_NAME (t
)))
rest_of_type_compilation (t
, global_bindings_p ());
/* Attach to the type of the virtual base class, the pointer to the
virtual base class, given the global pointer vbase_decl_ptr. */
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
, vbase_types
);
CLASSTYPE_SEARCH_SLOT (vbase
)
= (char *) build (PLUS_EXPR
, TYPE_POINTER_TO (vbase
),
vbase_decl_ptr
, BINFO_OFFSET (binfo
));
SET_BINFO_VTABLE_PATH_MARKED (binfo
);
SET_BINFO_NEW_VTABLE_MARKED (binfo
);
dfs_init_vbase_pointers (binfo
)
tree type
= BINFO_TYPE (binfo
);
tree fields
= TYPE_FIELDS (type
);
tree path
, this_vbase_ptr
;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo
);
/* If there is a dossier, it is the first field, though perhaps from
the base class. Otherwise, the first fields are virtual base class
if (CLASSTYPE_DOSSIER (type
) && VFIELD_NAME_P (DECL_NAME (fields
)))
/* Get past vtable for the object. */
fields
= TREE_CHAIN (fields
);
|| DECL_NAME (fields
) == NULL_TREE
|| ! VBASE_NAME_P (DECL_NAME (fields
)))
this_vbase_ptr
= vbase_decl_ptr_intermediate
;
if (TYPE_POINTER_TO (type
) != TREE_TYPE (this_vbase_ptr
))
distance
= get_base_distance (type
, TREE_TYPE (vbase_decl
), 0, &path
);
error ("inheritance lattice too complex below");
if (TREE_VIA_VIRTUAL (path
))
path
= BINFO_INHERITANCE_CHAIN (path
);
this_vbase_ptr
= convert_pointer_to (type
, (tree
)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (path
)));
this_vbase_ptr
= convert_pointer_to (type
, vbase_decl_ptr
);
/* This happens when it is ambiguous. */
if (this_vbase_ptr
== error_mark_node
)
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
, 0), fields
);
tree init
= (tree
)CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields
)));
vbase_init_result
= tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields
)),
build_modify_expr (ref
, NOP_EXPR
, init
),
fields
= TREE_CHAIN (fields
);
/* Sometimes this needs to clear both VTABLE_PATH and NEW_VTABLE. Other
times, just NEW_VTABLE, but optimizer should make both with equal
efficiency (though it does not currently). */
dfs_clear_vbase_slots (binfo
)
tree type
= BINFO_TYPE (binfo
);
CLASSTYPE_SEARCH_SLOT (type
) = 0;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo
);
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo
);
init_vbase_pointers (type
, decl_ptr
)
if (TYPE_USES_VIRTUAL_BASECLASSES (type
))
int old_flag
= flag_this_is_variable
;
tree binfo
= TYPE_BINFO (type
);
flag_this_is_variable
= -2;
vbase_types
= CLASSTYPE_VBASECLASSES (type
);
vbase_decl_ptr
= decl_ptr
;
vbase_decl
= build_indirect_ref (decl_ptr
, 0);
vbase_decl_ptr_intermediate
= vbase_decl_ptr
;
vbase_init_result
= NULL_TREE
;
dfs_walk (binfo
, dfs_find_vbases
, unmarked_vtable_pathp
);
dfs_walk (binfo
, dfs_init_vbase_pointers
, marked_vtable_pathp
);
dfs_walk (binfo
, dfs_clear_vbase_slots
, marked_new_vtablep
);
flag_this_is_variable
= old_flag
;
return vbase_init_result
;
/* Build a COMPOUND_EXPR which when expanded will generate the code
needed to initialize all the virtual function table slots of all
the virtual baseclasses. FOR_TYPE is the type which determines the
virtual baseclasses to use; TYPE is the type of the object to which
the initialization applies. TRUE_EXP is the true object we are
initializing, and DECL_PTR is the pointer to the sub-object we
CTOR_P is non-zero if the caller of this function is a top-level
constructor. It is zero when called from a destructor. When
non-zero, we can use computed offsets to store the vtables. When
zero, we must store new vtables through virtual baseclass pointers. */
build_vbase_vtables_init (main_binfo
, binfo
, true_exp
, decl_ptr
, ctor_p
)
tree for_type
= BINFO_TYPE (main_binfo
);
tree type
= BINFO_TYPE (binfo
);
if (TYPE_USES_VIRTUAL_BASECLASSES (type
))
int old_flag
= flag_this_is_variable
;
tree vtable_init_result
= NULL_TREE
;
tree vbases
= CLASSTYPE_VBASECLASSES (type
);
vbase_types
= CLASSTYPE_VBASECLASSES (for_type
);
vbase_decl_ptr
= true_exp
? build_unary_op (ADDR_EXPR
, true_exp
, 0) : decl_ptr
;
vbase_decl
= true_exp
? true_exp
: build_indirect_ref (decl_ptr
, 0);
/* This is an object of type IN_TYPE, */
flag_this_is_variable
= -2;
dfs_walk (main_binfo
, dfs_find_vbases
, unmarked_new_vtablep
);
/* Initialized with vtables of type TYPE. */
/* This time through, not every class's vtable
is going to be initialized. That is, we only initialize
the "last" vtable pointer. */
if (CLASSTYPE_VSIZE (BINFO_TYPE (vbases
)))
tree vtbl
= BINFO_VTABLE (vbases
);
tree init
= build_unary_op (ADDR_EXPR
, vtbl
, 0);
assemble_external (vtbl
);
addr
= convert_pointer_to (vbases
, vbase_decl_ptr
);
addr
= (tree
)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases
));
tree ref
= build_vfield_ref (build_indirect_ref (addr
, 0),
init
= convert_force (TREE_TYPE (ref
), init
);
vtable_init_result
= tree_cons (NULL_TREE
, build_modify_expr (ref
, NOP_EXPR
, init
),
vbases
= TREE_CHAIN (vbases
);
dfs_walk (binfo
, dfs_clear_vbase_slots
, marked_new_vtablep
);
flag_this_is_variable
= old_flag
;
return build_compound_expr (vtable_init_result
);
clear_search_slots (type
)
dfs_walk (TYPE_BINFO (type
),
dfs_clear_search_slot
, dfs_search_slot_nonempty_p
);
dfs_get_vbase_types (binfo
)
tree binfos
= BINFO_BASETYPES (binfo
);
tree type
= BINFO_TYPE (binfo
);
tree these_vbase_types
= CLASSTYPE_VBASECLASSES (type
);
while (these_vbase_types
)
tree this_type
= BINFO_TYPE (these_vbase_types
);
/* We really need to start from a fresh copy of this
virtual basetype! CLASSTYPE_MARKED2 is the shortcut
for BINFO_VBASE_MARKED. */
if (! CLASSTYPE_MARKED2 (this_type
))
vbase_types
= make_binfo (integer_zero_node
,
TYPE_BINFO_VTABLE (this_type
),
TYPE_BINFO_VIRTUALS (this_type
),
TREE_VIA_VIRTUAL (vbase_types
) = 1;
SET_CLASSTYPE_MARKED2 (this_type
);
these_vbase_types
= TREE_CHAIN (these_vbase_types
);
else for (i
= binfos
? TREE_VEC_LENGTH (binfos
)-1 : -1; i
>= 0; i
--)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
if (TREE_VIA_VIRTUAL (base_binfo
) && ! BINFO_VBASE_MARKED (base_binfo
))
vbase_types
= make_binfo (integer_zero_node
, BINFO_TYPE (base_binfo
),
BINFO_VTABLE (base_binfo
),
BINFO_VIRTUALS (base_binfo
), vbase_types
);
TREE_VIA_VIRTUAL (vbase_types
) = 1;
SET_BINFO_VBASE_MARKED (base_binfo
);
SET_BINFO_MARKED (binfo
);
/* Some virtual baseclasses might be virtual baseclasses for
other virtual baseclasses. We sort the virtual baseclasses
topologically: in the list returned, the first virtual base
classes have no virtual baseclasses themselves, and any entry
on the list has no dependency on virtual base classes later in the
tree ordered_vbase_types
= NULL_TREE
, prev
, next
;
dfs_walk (TYPE_BINFO (type
), dfs_get_vbase_types
, unmarkedp
);
dfs_walk (TYPE_BINFO (type
), dfs_unmark
, markedp
);
/* Now sort these types. This is essentially a bubble merge. */
/* Farm out virtual baseclasses which have no marked ancestors. */
for (vbases
= vbase_types
, prev
= NULL_TREE
;
next
= TREE_CHAIN (vbases
);
/* If VBASES does not have any vbases itself, or it's
topologically safe, it goes into the sorted list. */
if (! CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases
))
|| BINFO_VBASE_MARKED (vbases
) == 0)
TREE_CHAIN (prev
) = TREE_CHAIN (vbases
);
vbase_types
= TREE_CHAIN (vbases
);
TREE_CHAIN (vbases
) = NULL_TREE
;
ordered_vbase_types
= chainon (ordered_vbase_types
, vbases
);
CLEAR_BINFO_VBASE_MARKED (vbases
);
/* Now unmark types all of whose ancestors are now on the
`ordered_vbase_types' list. */
for (vbases
= vbase_types
; vbases
; vbases
= TREE_CHAIN (vbases
))
/* If all our virtual baseclasses are unmarked, ok. */
tree t
= CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases
));
while (t
&& (BINFO_VBASE_MARKED (t
) == 0
|| ! CLASSTYPE_VBASECLASSES (BINFO_TYPE (t
))))
CLEAR_BINFO_VBASE_MARKED (vbases
);
return ordered_vbase_types
;
dfs_record_inheritance (binfo
)
tree binfos
= BINFO_BASETYPES (binfo
);
int i
, n_baselinks
= binfos
? TREE_VEC_LENGTH (binfos
) : 0;
mi_boolean
*derived_row
= BINFO_DERIVES_FROM_STAR (binfo
);
for (i
= n_baselinks
-1; i
>= 0; i
--)
tree base_binfo
= TREE_VEC_ELT (binfos
, i
);
tree baseclass
= BINFO_TYPE (base_binfo
);
mi_boolean
*base_row
= BINFO_DERIVES_FROM_STAR (base_binfo
);
/* Don't search if there's nothing there! MI_SIZE can be
zero as a result of parse errors. */
if (TYPE_BINFO_BASETYPES (baseclass
) && mi_size
> 0)
for (j
= mi_size
*(CLASSTYPE_CID (baseclass
)-1); j
>= 0; j
-= mi_size
)
derived_row
[j
] |= base_row
[j
];
TYPE_DERIVES_FROM (baseclass
, BINFO_TYPE (binfo
)) = 1;
SET_BINFO_MARKED (binfo
);
/* Given a _CLASSTYPE node in a multiple inheritance lattice,
convert the lattice into a simple relation such that,
given to CIDs, C1 and C2, one can determine if C1 <= C2
Once constructed, we walk the lattice depth fisrt,
applying various functions to elements as they are encountered.
We use xmalloc here, in case we want to randomly free these tables. */
tree binfo
= TYPE_BINFO (type
);
if (CLASSTYPE_MI_MATRIX (type
))
mi_size
= CLASSTYPE_N_SUPERCLASSES (type
) + CLASSTYPE_N_VBASECLASSES (type
);
mi_matrix
= CLASSTYPE_MI_MATRIX (type
);
dfs_walk (binfo
, dfs_number
, unnumberedp
);
mi_size
= CLASSTYPE_N_SUPERCLASSES (type
) + CLASSTYPE_N_VBASECLASSES (type
);
mi_matrix
= (char *)xmalloc ((mi_size
+1) * (mi_size
+1));
bzero (mi_matrix
, mi_size
* mi_size
);
dfs_walk (binfo
, dfs_number
, unnumberedp
);
dfs_walk (binfo
, dfs_record_inheritance
, unmarkedp
);
dfs_walk (binfo
, dfs_unmark
, markedp
);
dfs_walk (TYPE_BINFO (mi_type
), dfs_unnumber
, numberedp
);
CLASSTYPE_MI_MATRIX (mi_type
) = mi_matrix
;
/* Local variables for detecting ambiguities of virtual functions
when two or more classes are joined at a multiple inheritance
static mi_ventry
*mi_vmatrix
;
static int mi_vrows
, mi_vcols
;
#define MI_VMATRIX(ROW,COL) ((mi_vmatrix + (ROW)*mi_vcols)[COL])
/* Build a table of virtual functions for a multiple-inheritance
structure. Here, there are N base classes, and at most
This function does nothing if N is 0 or 1. */
build_mi_virtuals (rows
, cols
)
if (rows
< 2 || cols
== 0)
mi_vmatrix
= (mi_ventry
*)xmalloc ((rows
+1) * cols
* sizeof (mi_ventry
));
mi_vmax
= (int *)xmalloc ((rows
+1) * sizeof (int));
bzero (mi_vmax
, rows
* sizeof (int));
/* Row indices start at 1, so adjust this. */
/* Comparison function for ordering virtual function table entries. */
rank_mi_virtuals (v1
, v2
)
i
= (long) (DECL_NAME (v1
->decl
)) - (long) (DECL_NAME (v2
->decl
));
i
= ((long) (TREE_VALUE (p1
)) - (long) (TREE_VALUE (p2
)));
else if (TREE_CHAIN (p2
))
/* When matches of argument lists occur, pick lowest
address to keep searching time to a minimum on
later passes--like hashing, only different.
if ((long) (v2
->args
) < (long) (v1
->args
))
/* Install the virtuals functions got from the initializer VIRTUALS to
the table at index ROW. */
add_mi_virtuals (row
, virtuals
)
tree decl
= TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals
)), 0);
MI_VMATRIX (row
, col
).decl
= decl
;
MI_VMATRIX (row
, col
).args
= FUNCTION_ARG_CHAIN (decl
);
MI_VMATRIX (row
, col
).ptr
= TREE_VALUE (virtuals
);
virtuals
= TREE_CHAIN (virtuals
);
qsort (mi_vmatrix
+ row
* mi_vcols
,
/* If joining two types results in an ambiguity in the virtual
function table, report such here. */
report_ambiguous_mi_virtuals (rows
, type
)
int row1
, col1
, row
, col
;
/* Now virtuals are all sorted, so we merge to find ambiguous cases. */
mi_vmin
= (int *)alloca ((rows
+1) * sizeof (int));
bzero (mi_vmin
, rows
* sizeof (int));
/* For each base class with virtual functions (and this includes views
of the virtual baseclasses from different base classes), see that
each virtual function in that base class has a unique meet.
When the column loop is finished, THIS_DECL is in fact the meet.
If that value does not appear in the virtual function table for
the row, install it. This happens when that virtual function comes
from a virtual baseclass, or a non-leftmost baseclass. */
for (row1
= 1; row1
< rows
; row1
++)
for (col1
= mi_vmax
[row1
]-1; col1
>= mi_vmin
[row1
]; col1
--)
tree these_args
= MI_VMATRIX (row1
, col1
).args
;
this_decl
= MI_VMATRIX (row1
, col1
).decl
;
this_context
= TYPE_BINFO (DECL_CLASS_CONTEXT (this_decl
));
if (this_context
!= TYPE_BINFO (type
))
this_context
= get_binfo (this_context
, type
, 0);
for (row
= row1
+1; row
<= rows
; row
++)
for (col
= mi_vmax
[row
]-1; col
>= mi_vmin
[row
]; col
--)
if (MI_VMATRIX (row
, col
).decl
== 0)
this_entry
.decl
= this_decl
;
this_entry
.args
= these_args
;
this_entry
.ptr
= MI_VMATRIX (row1
, col1
).ptr
;
if (rank_mi_virtuals (&this_entry
, &MI_VMATRIX (row
, col
)) == 0)
/* They are equal. There are four possibilities:
(1) Derived class is defining this virtual function.
(2) Two paths to the same virtual function in the
(3) A path to a virtual function declared in one base
class, and another path to a virtual function in a
base class of the base class.
(4) Two paths to the same virtual function in different
The first three cases are ok (non-ambiguous). */
if (type
== BINFO_TYPE (this_context
))
that_context
= get_binfo (DECL_CLASS_CONTEXT (MI_VMATRIX (row
, col
).decl
), type
, 0);
if (that_context
== this_context
)
if (that_context
!= NULL_TREE
)
tmp
= get_binfo (that_context
, this_context
, 0);
this_before_that
= (that_context
!= tmp
);
if (this_before_that
== 0)
tmp
= get_binfo (this_context
, that_context
, 0);
this_before_that
= (this_context
== tmp
);
if (this_before_that
!= 0)
/* These two are not hard errors, but could be
symptoms of bad code. The resultant code
the compiler generates needs to be checked.
error_with_decl (MI_VMATRIX (row
, col
).decl
, "ambiguous virtual function `%s'");
error_with_decl (this_decl
, "ambiguating function `%s' (joined by type `%s')", IDENTIFIER_POINTER (current_class_name
));
MI_VMATRIX (row
, col
).decl
= 0;
/* Let zeros propagate. */
if (col
== mi_vmax
[row
]-1)
&& MI_VMATRIX (row
, i
).decl
== 0)
else if (col
== mi_vmin
[row
])
&& MI_VMATRIX (row
, i
).decl
== 0)
free (mi_vmatrix
+ mi_vcols
);
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
the problem of not writing any debug info for intermediate basetypes
that have abstract virtual functions. */
note_debug_info_needed (type
)
dfs_walk (TYPE_BINFO (type
), dfs_debug_mark
, dfs_debug_unmarkedp
);
/* Subroutines of push_class_decls (). */
/* Add the instance variables which this class contributed to the
current class binding contour. When a redefinition occurs,
if the redefinition is strictly within a single inheritance path,
we just overwrite (in the case of a data field) or
cons (in the case of a member function) the old declaration with
the new. If the fields are not within a single inheritance path,
we must cons them in either case. */
tree type
= BINFO_TYPE (binfo
);
tree fields
, *methods
, *end
;
for (fields
= TYPE_FIELDS (type
); fields
; fields
= TREE_CHAIN (fields
))
/* Unmark so that if we are in a constructor, and then find that
this field was initialized by a base initializer,
we can emit an error message. */
if (TREE_CODE (fields
) == FIELD_DECL
)
if (DECL_NAME (fields
) == NULL_TREE
&& TREE_CODE (TREE_TYPE (fields
)) == UNION_TYPE
)
dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields
)));
if (TREE_CODE (fields
) != TYPE_DECL
)
DECL_PUBLIC (fields
) = 0;
DECL_PROTECTED (fields
) = 0;
DECL_PRIVATE (fields
) = 0;
tree value
= IDENTIFIER_CLASS_VALUE (DECL_NAME (fields
));
/* Possible ambiguity. If its defining type(s)
is (are all) derived from us, no problem. */
if (TREE_CODE (value
) != TREE_LIST
)
context
= DECL_CLASS_CONTEXT (value
);
if (context
&& (context
== type
|| TYPE_DERIVES_FROM (context
, type
)))
value
= tree_cons (NULL_TREE
, fields
,
build_tree_list (NULL_TREE
, value
));
/* All children may derive from us, in which case
there is no problem. Otherwise, we have to
keep lists around of what the ambiguities might be. */
for (values
= value
; values
; values
= TREE_CHAIN (values
))
tree sub_values
= TREE_VALUE (values
);
if (TREE_CODE (sub_values
) == TREE_LIST
)
for (; sub_values
; sub_values
= TREE_CHAIN (sub_values
))
context
= DECL_CLASS_CONTEXT (TREE_VALUE (sub_values
));
if (! TYPE_DERIVES_FROM (context
, type
))
value
= tree_cons (NULL_TREE
, TREE_VALUE (values
), value
);
context
= DECL_CLASS_CONTEXT (sub_values
);
if (! TYPE_DERIVES_FROM (context
, type
))
value
= tree_cons (NULL_TREE
, values
, value
);
if (! problem
) value
= fields
;
/* Mark this as a potentially ambiguous member. */
if (TREE_CODE (value
) == TREE_LIST
)
/* Leaving TREE_TYPE blank is intentional.
We cannot use `error_mark_node' (lookup_name)
or `unknown_type_node' (all member functions use this). */
TREE_NONLOCAL_FLAG (value
) = 1;
IDENTIFIER_CLASS_VALUE (DECL_NAME (fields
)) = value
;
else IDENTIFIER_CLASS_VALUE (DECL_NAME (fields
)) = fields
;
method_vec
= CLASSTYPE_METHOD_VEC (type
);
/* Farm out constructors and destructors. */
methods
= &TREE_VEC_ELT (method_vec
, 1);
end
= TREE_VEC_END (method_vec
);
/* This does not work for multiple inheritance yet. */
/* This will cause lookup_name to return a pointer
to the tree_list of possible methods of this name.
If the order is a problem, we can nreverse them. */
tree old
= IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods
));
if (old
&& TREE_CODE (old
) == TREE_LIST
)
tmp
= tree_cons (DECL_NAME (*methods
), *methods
, old
);
/* Only complain if we shadow something we can access. */
if (old
&& (DECL_CLASS_CONTEXT (old
) == current_class_type
|| ! TREE_PRIVATE (old
)))
/* Should figure out visibility more accurately. */
warning ("shadowing member `%s' with member function",
IDENTIFIER_POINTER (DECL_NAME (*methods
)));
tmp
= build_tree_list (DECL_NAME (*methods
), *methods
);
TREE_TYPE (tmp
) = unknown_type_node
;
TREE_OVERLOADED (tmp
) = DECL_OVERLOADED (*methods
);
TREE_NONLOCAL_FLAG (tmp
) = 1;
IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods
)) = tmp
;
DECL_PROTECTED (tmp
) = 0;
SET_BINFO_MARKED (binfo
);
/* Consolidate unique (by name) member functions. */
dfs_compress_decls (binfo
)
tree type
= BINFO_TYPE (binfo
);
tree method_vec
= CLASSTYPE_METHOD_VEC (type
);
/* Farm out constructors and destructors. */
tree
*methods
= &TREE_VEC_ELT (method_vec
, 1);
tree
*end
= TREE_VEC_END (method_vec
);
for (; methods
!= end
; methods
++)
tree tmp
= IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods
));
/* This was replaced in scope by somebody else. Just leave it
if (TREE_CODE (tmp
) != TREE_LIST
)
if (TREE_CHAIN (tmp
) == NULL_TREE
&& DECL_CHAIN (TREE_VALUE (tmp
)) == NULL_TREE
)
IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods
)) = TREE_VALUE (tmp
);
CLEAR_BINFO_MARKED (binfo
);
/* When entering the scope of a class, we cache all of the
fields that that class provides within its inheritance
lattice. Where ambiguities result, we mark them
with `error_mark_node' so that if they are encountered
without explicit qualification, we can emit an error
struct obstack
*ambient_obstack
= current_obstack
;
tree tags
= CLASSTYPE_TAGS (type
);
switch (TREE_CODE (TREE_VALUE (tags
)))
code_type_node
= enum_type_node
;
code_type_node
= record_type_node
;
code_type_node
= class_type_node
;
code_type_node
= union_type_node
;
tag
= xref_tag (code_type_node
, TREE_PURPOSE (tags
),
TYPE_BINFO_BASETYPE (TREE_VALUE (tags
), 0));
#if 0 /* not yet, should get fixed properly later */
pushdecl (make_type_decl (TREE_PURPOSE (tags
), TREE_VALUE (tags
)));
pushdecl (build_decl (TYPE_DECL
, TREE_PURPOSE (tags
), TREE_VALUE (tags
)));
current_obstack
= &bridge_obstack
;
search_stack
= push_search_level (search_stack
, &bridge_obstack
);
id
= TYPE_IDENTIFIER (type
);
if (IDENTIFIER_TEMPLATE (id
) != 0)
tree tmpl
= IDENTIFIER_TEMPLATE (id
);
push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl
)),
overload_template_name (id
, 0);
/* Push class fields into CLASS_VALUE scope, and mark. */
dfs_walk (TYPE_BINFO (type
), dfs_pushdecls
, unmarkedp
);
/* Compress fields which have only a single entry
by a given name, and unmark. */
dfs_walk (TYPE_BINFO (type
), dfs_compress_decls
, markedp
);
current_obstack
= ambient_obstack
;
tree type
= BINFO_TYPE (binfo
);
tree fields
= TYPE_FIELDS (type
);
tree method_vec
= CLASSTYPE_METHOD_VEC (type
);
if (DECL_NAME (fields
) == NULL_TREE
&& TREE_CODE (TREE_TYPE (fields
)) == UNION_TYPE
)
dfs_popdecls (TYPE_BINFO (TREE_TYPE (fields
)));
else if (DECL_NAME (fields
))
IDENTIFIER_CLASS_VALUE (DECL_NAME (fields
)) = NULL_TREE
;
fields
= TREE_CHAIN (fields
);
tree
*methods
= &TREE_VEC_ELT (method_vec
, 0);
tree
*end
= TREE_VEC_END (method_vec
);
/* Clear out ctors and dtors. */
IDENTIFIER_CLASS_VALUE (TYPE_IDENTIFIER (type
)) = NULL_TREE
;
for (methods
+= 1; methods
!= end
; methods
++)
IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods
)) = NULL_TREE
;
SET_BINFO_MARKED (binfo
);
tree binfo
= TYPE_BINFO (type
);
/* Clear out the IDENTIFIER_CLASS_VALUE which this
class may have occupied, and mark. */
dfs_walk (binfo
, dfs_popdecls
, unmarkedp
);
dfs_walk (binfo
, dfs_unmark
, markedp
);
tmpl
= IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (type
));
pop_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl
)),
search_stack
= pop_search_level (search_stack
);
/* Given a base type PARENT, and a derived type TYPE, build
a name which distinguishes exactly the PARENT member of TYPE's type.
FORMAT is a string which controls how sprintf formats the name
class A; class B; class C : A, B;
it is possible to distinguish "A" from "C's A". And given
class A : L; class B : L; class C : A, B;
it is possible to distinguish "L" from "A's L", and also from
Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the
type, as template have DECL_NAMEs like: X<int>, whereas the
DECL_ASSEMBLER_NAME is set to be something the assembler can handle.
build_type_pathname (format
, parent
, type
)
extern struct obstack temporary_obstack
;
char *first
, *base
, *name
;
parent
= TYPE_MAIN_VARIANT (parent
);
/* Remember where to cut the obstack to. */
first
= obstack_base (&temporary_obstack
);
/* Put on TYPE+PARENT. */
obstack_grow (&temporary_obstack
,
TYPE_ASSEMBLER_NAME_STRING (type
),
TYPE_ASSEMBLER_NAME_LENGTH (type
));
obstack_1grow (&temporary_obstack
, JOINER
);
obstack_1grow (&temporary_obstack
, '_');
obstack_grow0 (&temporary_obstack
,
TYPE_ASSEMBLER_NAME_STRING (parent
),
TYPE_ASSEMBLER_NAME_LENGTH (parent
));
i
= obstack_object_size (&temporary_obstack
);
base
= obstack_base (&temporary_obstack
);
obstack_finish (&temporary_obstack
);
/* Put on FORMAT+TYPE+PARENT. */
obstack_blank (&temporary_obstack
, strlen (format
) + i
+ 1);
name
= obstack_base (&temporary_obstack
);
sprintf (name
, format
, base
);
id
= get_identifier (name
);
obstack_free (&temporary_obstack
, first
);
bfs_unmark_finished_struct (binfo
, i
)
binfo
= BINFO_BASETYPE (binfo
, i
);
if (BINFO_NEW_VTABLE_MARKED (binfo
))
if (TREE_VIA_VIRTUAL (binfo
))
binfo
= binfo_member (BINFO_TYPE (binfo
),
CLASSTYPE_VBASECLASSES (current_class_type
));
decl
= BINFO_VTABLE (binfo
);
context
= DECL_CONTEXT (decl
);
&& DECL_INITIAL (decl
) != BINFO_VIRTUALS (binfo
))
DECL_INITIAL (decl
) = build_nt (CONSTRUCTOR
, NULL_TREE
,
finish_decl (decl
, DECL_INITIAL (decl
), NULL_TREE
, 0);
DECL_CONTEXT (decl
) = context
;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo
);
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo
);
unmark_finished_struct (type
)
tree binfo
= TYPE_BINFO (type
);
bfs_unmark_finished_struct (binfo
, -1);
breadth_first_search (binfo
, bfs_unmark_finished_struct
, bfs_marked_vtable_pathp
);
print_search_statistics ()
if (flag_memoize_lookups
)
fprintf (stderr
, "%d memoized contexts saved\n",
fprintf (stderr
, "%d local tree nodes made\n", my_tree_node_counter
);
fprintf (stderr
, "%d local hash nodes made\n", my_memoized_entry_counter
);
fprintf (stderr
, "fields statistics:\n");
fprintf (stderr
, " memoized finds = %d; rejects = %d; (searches = %d)\n",
memoized_fast_finds
[0], memoized_fast_rejects
[0],
memoized_fields_searched
[0]);
fprintf (stderr
, " memoized_adds = %d\n", memoized_adds
[0]);
fprintf (stderr
, "fnfields statistics:\n");
fprintf (stderr
, " memoized finds = %d; rejects = %d; (searches = %d)\n",
memoized_fast_finds
[1], memoized_fast_rejects
[1],
memoized_fields_searched
[1]);
fprintf (stderr
, " memoized_adds = %d\n", memoized_adds
[1]);
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
);
fprintf (stderr
, "no search statistics\n");
init_search_processing ()
gcc_obstack_init (&search_obstack
);
gcc_obstack_init (&type_obstack
);
gcc_obstack_init (&type_obstack_entries
);
gcc_obstack_init (&bridge_obstack
);
/* This gives us room to build our chains of basetypes,
whether or not we decide to memoize them. */
type_stack
= push_type_level (0, &type_obstack
);
_vptr_name
= get_identifier ("_vptr");
reinit_search_statistics ()
my_memoized_entry_counter
= 0;
memoized_fast_finds
[0] = 0;
memoized_fast_finds
[1] = 0;
memoized_fast_rejects
[0] = 0;
memoized_fast_rejects
[1] = 0;
memoized_fields_searched
[0] = 0;
memoized_fields_searched
[1] = 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;