1993-07-09 17:11:49 +04:00
|
|
|
|
/* 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)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
|
1993-08-02 21:28:42 +04:00
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] = "$Id: cp-search.c,v 1.2 1993/08/02 17:32:11 mycroft Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
1993-07-09 17:11:49 +04:00
|
|
|
|
#if 0
|
|
|
|
|
/* Remove before release, should only appear for development and testing. */
|
|
|
|
|
#define CHECK_convert_pointer_to_single_level
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* High-level class interface. */
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "tree.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "cp-tree.h"
|
|
|
|
|
#include "obstack.h"
|
|
|
|
|
#include "flags.h"
|
|
|
|
|
|
|
|
|
|
#define obstack_chunk_alloc xmalloc
|
|
|
|
|
#define obstack_chunk_free free
|
|
|
|
|
|
|
|
|
|
void init_search ();
|
|
|
|
|
extern struct obstack *current_obstack;
|
|
|
|
|
|
|
|
|
|
#include "stack.h"
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
struct stack_level *
|
|
|
|
|
push_stack_level (obstack, tp, size)
|
|
|
|
|
struct obstack *obstack;
|
|
|
|
|
char *tp; /* Sony NewsOS 5.0 compiler doesn't like void * here. */
|
|
|
|
|
int size;
|
|
|
|
|
{
|
|
|
|
|
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 *);
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct stack_level *
|
|
|
|
|
pop_stack_level (stack)
|
|
|
|
|
struct stack_level *stack;
|
|
|
|
|
{
|
|
|
|
|
struct stack_level *tem = stack;
|
|
|
|
|
struct obstack *obstack = tem->obstack;
|
|
|
|
|
stack = tem->prev;
|
|
|
|
|
obstack_free (obstack, tem);
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define search_level stack_level
|
|
|
|
|
static struct search_level *search_stack;
|
|
|
|
|
|
|
|
|
|
static tree lookup_field_1 ();
|
|
|
|
|
static int lookup_fnfields_1 ();
|
|
|
|
|
static void dfs_walk ();
|
|
|
|
|
static int markedp ();
|
|
|
|
|
static void dfs_unmark ();
|
|
|
|
|
static void dfs_init_vbase_pointers ();
|
|
|
|
|
|
|
|
|
|
static tree vbase_types;
|
|
|
|
|
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;
|
|
|
|
|
struct obstack *obstack;
|
|
|
|
|
{
|
|
|
|
|
struct search_level tem;
|
|
|
|
|
tem.prev = 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. */
|
|
|
|
|
struct type_level
|
|
|
|
|
{
|
|
|
|
|
struct stack_level base;
|
|
|
|
|
|
|
|
|
|
/* First object allocated in obstack of entries. */
|
|
|
|
|
char *entries;
|
|
|
|
|
|
|
|
|
|
/* Number of types memoized in this context. */
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
/* Type being memoized; save this if we are saving
|
|
|
|
|
memoized contexts. */
|
|
|
|
|
tree type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Obstack used for memoizing member and member function lookup. */
|
|
|
|
|
|
|
|
|
|
static struct obstack type_obstack, type_obstack_entries;
|
|
|
|
|
static struct type_level *type_stack;
|
|
|
|
|
static tree _vptr_name;
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
struct obstack *obstack;
|
|
|
|
|
{
|
|
|
|
|
struct type_level tem;
|
|
|
|
|
|
|
|
|
|
tem.base.prev = stack;
|
|
|
|
|
|
|
|
|
|
obstack_finish (&type_obstack_entries);
|
|
|
|
|
tem.entries = (char *) obstack_base (&type_obstack_entries);
|
|
|
|
|
tem.len = 0;
|
|
|
|
|
tem.type = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
return (struct type_level *)push_stack_level (obstack, (char *) &tem,
|
|
|
|
|
sizeof (tem));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Discard a level of type memoization context. */
|
|
|
|
|
|
|
|
|
|
static struct type_level *
|
|
|
|
|
pop_type_level (stack)
|
|
|
|
|
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. */
|
|
|
|
|
static tree
|
|
|
|
|
my_tree_cons (purpose, value, chain)
|
|
|
|
|
tree purpose, value, chain;
|
|
|
|
|
{
|
|
|
|
|
tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_list));
|
|
|
|
|
++my_tree_node_counter;
|
|
|
|
|
TREE_TYPE (p) = NULL_TREE;
|
|
|
|
|
((HOST_WIDE_INT *)p)[3] = 0;
|
|
|
|
|
TREE_SET_CODE (p, TREE_LIST);
|
|
|
|
|
TREE_PURPOSE (p) = purpose;
|
|
|
|
|
TREE_VALUE (p) = value;
|
|
|
|
|
TREE_CHAIN (p) = chain;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
my_build_string (str)
|
|
|
|
|
char *str;
|
|
|
|
|
{
|
|
|
|
|
tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_string));
|
|
|
|
|
++my_tree_node_counter;
|
|
|
|
|
TREE_TYPE (p) = 0;
|
|
|
|
|
((int *)p)[3] = 0;
|
|
|
|
|
TREE_SET_CODE (p, STRING_CST);
|
|
|
|
|
TREE_STRING_POINTER (p) = str;
|
|
|
|
|
TREE_STRING_LENGTH (p) = strlen (str);
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Memoizing machinery to make searches for multiple inheritance
|
|
|
|
|
reasonably efficient. */
|
|
|
|
|
#define MEMOIZE_HASHSIZE 8
|
|
|
|
|
typedef struct memoized_entry
|
|
|
|
|
{
|
|
|
|
|
struct memoized_entry *chain;
|
|
|
|
|
int uid;
|
|
|
|
|
tree data_members[MEMOIZE_HASHSIZE];
|
|
|
|
|
tree function_members[MEMOIZE_HASHSIZE];
|
|
|
|
|
} *ME;
|
|
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make an entry in the memoized table for type TYPE
|
|
|
|
|
that the entry for NAME is FIELD. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
make_memoized_table_entry (type, name, function_p)
|
|
|
|
|
tree type, name;
|
|
|
|
|
int function_p;
|
|
|
|
|
{
|
|
|
|
|
int index = MEMOIZED_HASH_FN (name);
|
|
|
|
|
tree entry, *prev_entry;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
type_stack->len++;
|
|
|
|
|
if (type_stack->len * 2 >= type_stack->base.limit)
|
|
|
|
|
my_friendly_abort (88);
|
|
|
|
|
}
|
|
|
|
|
if (function_p)
|
|
|
|
|
prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
|
|
|
|
|
else
|
|
|
|
|
prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
|
|
|
|
|
|
|
|
|
|
entry = my_tree_cons (name, NULL_TREE, *prev_entry);
|
|
|
|
|
*prev_entry = entry;
|
|
|
|
|
|
|
|
|
|
/* Don't know the error message to give yet. */
|
|
|
|
|
TREE_TYPE (entry) = error_mark_node;
|
|
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
void
|
|
|
|
|
push_memoized_context (type, use_old)
|
|
|
|
|
tree type;
|
|
|
|
|
int use_old;
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
tree *tem;
|
|
|
|
|
|
|
|
|
|
if (prev_type_stack)
|
|
|
|
|
{
|
|
|
|
|
if (use_old && prev_type_memoized == type)
|
|
|
|
|
{
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_contexts_saved++;
|
|
|
|
|
#endif
|
|
|
|
|
type_stack = prev_type_stack;
|
|
|
|
|
prev_type_stack = 0;
|
|
|
|
|
|
|
|
|
|
tem = &type_stack->base.first[0];
|
|
|
|
|
len = type_stack->len;
|
|
|
|
|
while (len--)
|
|
|
|
|
CLASSTYPE_MTABLE_ENTRY (tem[len*2]) = (char *)tem[len*2+1];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Otherwise, need to pop old stack here. */
|
|
|
|
|
type_stack = pop_type_level (prev_type_stack);
|
|
|
|
|
prev_type_memoized = 0;
|
|
|
|
|
prev_type_stack = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type_stack = push_type_level ((struct stack_level *)type_stack,
|
|
|
|
|
&type_obstack);
|
|
|
|
|
type_stack->type = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
void
|
|
|
|
|
pop_memoized_context (use_old)
|
|
|
|
|
int use_old;
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
tree *tem = &type_stack->base.first[0];
|
|
|
|
|
|
|
|
|
|
if (! flag_save_memoized_contexts)
|
|
|
|
|
use_old = 0;
|
|
|
|
|
else if (use_old)
|
|
|
|
|
{
|
|
|
|
|
len = type_stack->len;
|
|
|
|
|
while (len--)
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
len = type_stack->len;
|
|
|
|
|
while (len--)
|
|
|
|
|
CLASSTYPE_MTABLE_ENTRY (tem[len*2])
|
|
|
|
|
= (char *)MEMOIZED_CHAIN (CLASSTYPE_MTABLE_ENTRY (tem[len*2]));
|
|
|
|
|
}
|
|
|
|
|
if (! use_old)
|
|
|
|
|
type_stack = pop_type_level (type_stack);
|
|
|
|
|
else
|
|
|
|
|
type_stack = (struct type_level *)type_stack->base.prev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This can go away when the new searching strategy as a little mileage on it. */
|
|
|
|
|
#define NEW_SEARCH 1
|
|
|
|
|
#if NEW_SEARCH
|
|
|
|
|
/* This is the newer recursive depth first one, the old one follows. */
|
|
|
|
|
static tree
|
|
|
|
|
get_binfo_recursive (binfo, is_private, parent, rval, rval_private_ptr, xtype,
|
|
|
|
|
friends, protect)
|
|
|
|
|
tree binfo, parent, rval, xtype, friends;
|
|
|
|
|
int *rval_private_ptr, protect, is_private;
|
|
|
|
|
{
|
|
|
|
|
tree binfos;
|
|
|
|
|
int i, n_baselinks;
|
|
|
|
|
|
|
|
|
|
if (BINFO_TYPE (binfo) == parent)
|
|
|
|
|
{
|
|
|
|
|
if (rval == NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
rval = binfo;
|
|
|
|
|
*rval_private_ptr = is_private;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (protect)
|
|
|
|
|
{
|
|
|
|
|
/* 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));
|
|
|
|
|
rval = error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (via_private == 0)
|
|
|
|
|
;
|
|
|
|
|
else if (protect == 0)
|
|
|
|
|
via_private = 0;
|
|
|
|
|
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. */
|
|
|
|
|
via_private = 0;
|
|
|
|
|
#ifndef NOJJG
|
|
|
|
|
else if (protect
|
|
|
|
|
&& friends != NULL_TREE
|
|
|
|
|
&& BINFO_TYPE (binfo) == xtype
|
|
|
|
|
&& value_member (current_class_type, friends))
|
|
|
|
|
/* Friend types of the most derived type have access
|
|
|
|
|
to its baseclass pointers. */
|
|
|
|
|
via_private = 0;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
rval = get_binfo_recursive (base_binfo, via_private, parent, rval,
|
|
|
|
|
rval_private_ptr, xtype, friends,
|
|
|
|
|
protect);
|
|
|
|
|
if (rval == error_mark_node)
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
would be private.
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
tree
|
|
|
|
|
get_binfo (parent, binfo, protect)
|
|
|
|
|
register tree parent, binfo;
|
|
|
|
|
int protect;
|
|
|
|
|
{
|
|
|
|
|
tree xtype, type;
|
|
|
|
|
tree otype;
|
|
|
|
|
int head = 0, tail = 0;
|
|
|
|
|
int is_private = 0;
|
|
|
|
|
tree rval = NULL_TREE;
|
|
|
|
|
int rval_private = 0;
|
|
|
|
|
tree friends;
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_get_base_type++;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (parent) == TREE_VEC)
|
|
|
|
|
parent = BINFO_TYPE (parent);
|
|
|
|
|
/* unions cannot participate in inheritance relationships */
|
|
|
|
|
else if (TREE_CODE (parent) == UNION_TYPE)
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
else if (TREE_CODE (parent) != RECORD_TYPE)
|
|
|
|
|
my_friendly_abort (89);
|
|
|
|
|
|
|
|
|
|
parent = TYPE_MAIN_VARIANT (parent);
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (binfo) == TREE_VEC)
|
|
|
|
|
type = BINFO_TYPE (binfo);
|
|
|
|
|
else if (TREE_CODE (binfo) == RECORD_TYPE)
|
|
|
|
|
{
|
|
|
|
|
type = binfo;
|
|
|
|
|
binfo = TYPE_BINFO (type);
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (90);
|
|
|
|
|
xtype = type;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (protect == 3)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error_with_aggr_type (xtype, "type `%s' is derived from private `%s'",
|
|
|
|
|
TYPE_NAME_STRING (parent));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
/* 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
|
|
|
|
|
would be private.
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
tree
|
|
|
|
|
get_binfo (parent, binfo, protect)
|
|
|
|
|
register tree parent, binfo;
|
|
|
|
|
int protect;
|
|
|
|
|
{
|
|
|
|
|
tree xtype, type;
|
|
|
|
|
tree otype;
|
|
|
|
|
int head = 0, tail = 0;
|
|
|
|
|
int is_private = 0;
|
|
|
|
|
tree rval = NULL_TREE;
|
|
|
|
|
int rval_private = 0;
|
|
|
|
|
tree friends;
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_get_base_type++;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (parent) == TREE_VEC)
|
|
|
|
|
parent = BINFO_TYPE (parent);
|
|
|
|
|
/* unions cannot participate in inheritance relationships */
|
|
|
|
|
else if (TREE_CODE (parent) == UNION_TYPE)
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
else if (TREE_CODE (parent) != RECORD_TYPE)
|
|
|
|
|
my_friendly_abort (89);
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
type = binfo;
|
|
|
|
|
binfo = TYPE_BINFO (type);
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (90);
|
|
|
|
|
xtype = type;
|
|
|
|
|
friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (via_private == 0)
|
|
|
|
|
;
|
|
|
|
|
else if (protect == 0)
|
|
|
|
|
via_private = 0;
|
|
|
|
|
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. */
|
|
|
|
|
via_private = 0;
|
|
|
|
|
#ifndef NOJJG
|
|
|
|
|
else if (protect
|
|
|
|
|
&& friends != NULL_TREE
|
|
|
|
|
&& BINFO_TYPE (binfo) == xtype
|
|
|
|
|
&& value_member (current_class_type, friends))
|
|
|
|
|
/* Friend types of the most derived type have access
|
|
|
|
|
to its baseclass pointers. */
|
|
|
|
|
via_private = 0;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
otype = type;
|
|
|
|
|
obstack_ptr_grow (&search_obstack, base_binfo);
|
|
|
|
|
obstack_ptr_grow (&search_obstack, (void *) via_private);
|
|
|
|
|
tail += 2;
|
|
|
|
|
if (tail >= search_stack->limit)
|
|
|
|
|
my_friendly_abort (91);
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
/* This code cannot possibly be right. Ambiguities can only be
|
|
|
|
|
checked by traversing the whole tree, and seeing if it pops
|
|
|
|
|
up twice. */
|
|
|
|
|
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));
|
|
|
|
|
rval = error_mark_node;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dont_queue:
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
binfo = search_stack->first[head++];
|
|
|
|
|
is_private = (int) search_stack->first[head++];
|
|
|
|
|
if (BINFO_TYPE (binfo) == parent)
|
|
|
|
|
{
|
|
|
|
|
if (rval == 0)
|
|
|
|
|
{
|
|
|
|
|
rval = binfo;
|
|
|
|
|
rval_private = is_private;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (protect)
|
|
|
|
|
{
|
|
|
|
|
/* 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));
|
|
|
|
|
rval = error_mark_node;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
goto dont_queue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
{
|
|
|
|
|
tree *tp = search_stack->first;
|
|
|
|
|
tree *search_tail = tp + tail;
|
|
|
|
|
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
CLEAR_BINFO_MARKED (*tp);
|
|
|
|
|
tp += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
|
|
|
|
|
if (rval == error_mark_node)
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
|
|
|
|
|
if (rval && protect && rval_private)
|
|
|
|
|
{
|
|
|
|
|
if (protect == 3)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error_with_aggr_type (xtype, "type `%s' is derived from private `%s'",
|
|
|
|
|
TYPE_NAME_STRING (parent));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if NEW_SEARCH
|
|
|
|
|
/* This is the newer depth first get_base_distance, the older one follows. */
|
|
|
|
|
static
|
|
|
|
|
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,
|
|
|
|
|
via_virtual;
|
|
|
|
|
{
|
|
|
|
|
tree binfos;
|
|
|
|
|
int i, n_baselinks;
|
|
|
|
|
|
|
|
|
|
if (BINFO_TYPE (binfo) == parent)
|
|
|
|
|
{
|
|
|
|
|
if (rval == -1)
|
|
|
|
|
{
|
|
|
|
|
rval = depth;
|
|
|
|
|
*rval_private_ptr = is_private;
|
|
|
|
|
*new_binfo_ptr = binfo;
|
|
|
|
|
*via_virtual_ptr = via_virtual;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int same_object = tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
|
|
|
|
|
BINFO_OFFSET (binfo));
|
|
|
|
|
|
|
|
|
|
if (*via_virtual_ptr && via_virtual==0)
|
|
|
|
|
{
|
|
|
|
|
*rval_private_ptr = is_private;
|
|
|
|
|
*new_binfo_ptr = binfo;
|
|
|
|
|
*via_virtual_ptr = via_virtual;
|
|
|
|
|
}
|
|
|
|
|
else if (same_object)
|
|
|
|
|
{
|
|
|
|
|
/* Note, this should probably succeed to find, and
|
|
|
|
|
override the old one if the old one was private and
|
|
|
|
|
this one isn't. */
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rval = -2;
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
depth += 1;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
int was;
|
|
|
|
|
|
|
|
|
|
/* When searching for a non-virtual, we cannot mark
|
|
|
|
|
virtually found binfos. */
|
|
|
|
|
if (!via_virtual)
|
|
|
|
|
SET_BINFO_MARKED (base_binfo);
|
|
|
|
|
|
|
|
|
|
if (via_private == 0)
|
|
|
|
|
;
|
|
|
|
|
else if (protect == 0)
|
|
|
|
|
via_private = 0;
|
|
|
|
|
|
|
|
|
|
#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 rval;
|
|
|
|
|
|
|
|
|
|
#undef WATCH_VALUES
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
set.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
(mrs)
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
want to see -2. (mrs)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
get_base_distance (parent, binfo, protect, path_ptr)
|
|
|
|
|
register tree parent, binfo;
|
|
|
|
|
int protect;
|
|
|
|
|
tree *path_ptr;
|
|
|
|
|
{
|
|
|
|
|
int head, tail;
|
|
|
|
|
int is_private = 0;
|
|
|
|
|
int rval = -1;
|
|
|
|
|
int depth = 0;
|
|
|
|
|
int rval_private = 0;
|
|
|
|
|
tree type, basetype_path;
|
|
|
|
|
tree friends;
|
|
|
|
|
int use_leftmost;
|
|
|
|
|
tree new_binfo;
|
|
|
|
|
int via_virtual;
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
type = binfo;
|
|
|
|
|
binfo = TYPE_BINFO (type);
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (92);
|
|
|
|
|
|
|
|
|
|
friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
|
|
|
|
|
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
*path_ptr = basetype_path;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rval = get_base_distance_recursive (binfo, 0, 0, NULL_TREE, rval,
|
|
|
|
|
&rval_private, &new_binfo, parent,
|
|
|
|
|
path_ptr, protect, &via_virtual, 0);
|
|
|
|
|
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
basetype_path = binfo;
|
|
|
|
|
|
|
|
|
|
dfs_walk (binfo, dfs_unmark, markedp);
|
|
|
|
|
|
|
|
|
|
binfo = new_binfo;
|
|
|
|
|
|
|
|
|
|
/* Visibilities don't count if we found an ambiguous basetype. */
|
|
|
|
|
if (rval == -2)
|
|
|
|
|
rval_private = 0;
|
|
|
|
|
|
|
|
|
|
if (rval && protect && rval_private)
|
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
*path_ptr = binfo;
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
/* Recursively search for a path from PARENT to BINFO.
|
|
|
|
|
If RVAL is > 0 and we succeed, update the BINFO_INHERITANCE_CHAIN
|
|
|
|
|
pointers.
|
|
|
|
|
If we find a distinct basetype that's not the one from BINFO,
|
|
|
|
|
return -2;
|
|
|
|
|
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. */
|
|
|
|
|
static int
|
|
|
|
|
recursive_bounded_basetype_p (parent, binfo, rval, update_chain)
|
|
|
|
|
tree parent, binfo;
|
|
|
|
|
int rval;
|
|
|
|
|
int update_chain;
|
|
|
|
|
{
|
|
|
|
|
tree binfos;
|
|
|
|
|
|
|
|
|
|
if (BINFO_TYPE (parent) == BINFO_TYPE (binfo))
|
|
|
|
|
{
|
|
|
|
|
if (tree_int_cst_equal (BINFO_OFFSET (parent), BINFO_OFFSET (binfo)))
|
|
|
|
|
return rval;
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TREE_VIA_VIRTUAL (binfo))
|
|
|
|
|
update_chain = 0;
|
|
|
|
|
|
|
|
|
|
if (binfos = BINFO_BASETYPES (binfo))
|
|
|
|
|
{
|
|
|
|
|
int i, nval;
|
|
|
|
|
for (i = 0; i < TREE_VEC_LENGTH (binfos); i++)
|
|
|
|
|
{
|
|
|
|
|
nval = recursive_bounded_basetype_p (parent, TREE_VEC_ELT (binfos, i),
|
|
|
|
|
rval, update_chain);
|
|
|
|
|
if (nval < 0)
|
|
|
|
|
return nval;
|
|
|
|
|
if (nval > 0 && update_chain)
|
|
|
|
|
BINFO_INHERITANCE_CHAIN (TREE_VEC_ELT (binfos, i)) = binfo;
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------- */
|
|
|
|
|
/* 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) */
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
get_binfo2_recursive (binfo, parent, type)
|
|
|
|
|
register tree binfo, parent;
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
tree rval = NULL_TREE;
|
|
|
|
|
tree nrval;
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
|
|
|
|
|
if (BINFO_TYPE (binfo) == parent)
|
|
|
|
|
{
|
|
|
|
|
return binfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
return nrval;
|
|
|
|
|
if (nrval)
|
|
|
|
|
if (rval == 0)
|
|
|
|
|
{
|
|
|
|
|
rval = nrval;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
get_binfo2 (parent, binfo)
|
|
|
|
|
register tree parent, binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type;
|
|
|
|
|
tree rval = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (parent) == TREE_VEC)
|
|
|
|
|
parent = BINFO_TYPE (parent);
|
|
|
|
|
/* unions cannot participate in inheritance relationships */
|
|
|
|
|
else if (TREE_CODE (parent) == UNION_TYPE)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (TREE_CODE (parent) != RECORD_TYPE)
|
|
|
|
|
my_friendly_abort (89);
|
|
|
|
|
|
|
|
|
|
parent = TYPE_MAIN_VARIANT (parent);
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (binfo) == TREE_VEC)
|
|
|
|
|
type = BINFO_TYPE (binfo);
|
|
|
|
|
else if (TREE_CODE (binfo) == RECORD_TYPE)
|
|
|
|
|
{
|
|
|
|
|
type = binfo;
|
|
|
|
|
binfo = TYPE_BINFO (type);
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (90);
|
|
|
|
|
|
|
|
|
|
rval = get_binfo2_recursive (binfo, parent, type);
|
|
|
|
|
|
|
|
|
|
dfs_walk (binfo, dfs_unmark, markedp);
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
chosen.
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
set.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
(mrs)
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
want to see -2. (mrs)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
get_base_distance (parent, binfo, protect, path_ptr)
|
|
|
|
|
register tree parent, binfo;
|
|
|
|
|
int protect;
|
|
|
|
|
tree *path_ptr;
|
|
|
|
|
{
|
|
|
|
|
int head, tail;
|
|
|
|
|
int is_private = 0;
|
|
|
|
|
int rval = -1;
|
|
|
|
|
int depth = 0;
|
|
|
|
|
int rval_private = 0;
|
|
|
|
|
tree type, basetype_path;
|
|
|
|
|
tree friends;
|
|
|
|
|
int use_leftmost;
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
type = binfo;
|
|
|
|
|
binfo = TYPE_BINFO (type);
|
|
|
|
|
}
|
|
|
|
|
else if (TREE_CODE (binfo) == UNION_TYPE)
|
|
|
|
|
{
|
|
|
|
|
/* UNION_TYPEs do not participate in inheritance relationships. */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (92);
|
|
|
|
|
|
|
|
|
|
friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
|
|
|
|
|
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
*path_ptr = basetype_path;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
{
|
|
|
|
|
obstack_ptr_grow (&search_obstack, NULL_PTR);
|
|
|
|
|
head = 4;
|
|
|
|
|
}
|
|
|
|
|
else head = 3;
|
|
|
|
|
tail = head;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (via_private == 0)
|
|
|
|
|
;
|
|
|
|
|
else if (protect == 0)
|
|
|
|
|
via_private = 0;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
tail += 3;
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
{
|
|
|
|
|
obstack_ptr_grow (&search_obstack, basetype_path);
|
|
|
|
|
tail += 1;
|
|
|
|
|
}
|
|
|
|
|
if (tail >= search_stack->limit)
|
|
|
|
|
my_friendly_abort (93);
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
/* This code cannot possibly be right. Ambiguities can only be
|
|
|
|
|
checked by traversing the whole tree, and seeing if it pops
|
|
|
|
|
up twice. */
|
|
|
|
|
else if (! TREE_VIA_VIRTUAL (base_binfo))
|
|
|
|
|
{
|
|
|
|
|
rval = -2;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
binfo = search_stack->first[head++];
|
|
|
|
|
depth = (int) search_stack->first[head++] + 1;
|
|
|
|
|
is_private = (int) search_stack->first[head++];
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
{
|
|
|
|
|
basetype_path = search_stack->first[head++];
|
|
|
|
|
BINFO_INHERITANCE_CHAIN (binfo) = basetype_path;
|
|
|
|
|
basetype_path = binfo;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
use_leftmost is set. */
|
|
|
|
|
rval = depth;
|
|
|
|
|
rval_private = is_private;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
/* Unneeded now, as we know the above code in the #if 0 is wrong. */
|
|
|
|
|
done:
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
tp += increment;
|
|
|
|
|
|
|
|
|
|
basetype_path = binfo;
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
CLEAR_BINFO_MARKED (*tp);
|
|
|
|
|
tp += increment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
basetype. */
|
|
|
|
|
|
|
|
|
|
if (use_leftmost
|
|
|
|
|
&& rval > 0
|
|
|
|
|
&& (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo)))
|
|
|
|
|
{
|
|
|
|
|
tree tp_binfos;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
/* Pick the best path. */
|
|
|
|
|
tree base_binfo;
|
|
|
|
|
int i;
|
|
|
|
|
int nrval = rval;
|
|
|
|
|
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))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
rval = nrval;
|
|
|
|
|
if (rval > 0)
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
#if 1
|
|
|
|
|
/* 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.");
|
|
|
|
|
rval = -2;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Visibilities don't count if we found an ambiguous basetype. */
|
|
|
|
|
if (rval == -2)
|
|
|
|
|
rval_private = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
|
|
|
|
|
if (rval && protect && rval_private)
|
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
|
|
if (path_ptr)
|
|
|
|
|
*path_ptr = binfo;
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* 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.) */
|
|
|
|
|
static tree
|
|
|
|
|
lookup_field_1 (type, name)
|
|
|
|
|
tree type, name;
|
|
|
|
|
{
|
|
|
|
|
register tree field = TYPE_FIELDS (type);
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_lookup_field_1++;
|
|
|
|
|
#endif
|
|
|
|
|
while (field)
|
|
|
|
|
{
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_fields_searched++;
|
|
|
|
|
#endif
|
|
|
|
|
if (DECL_NAME (field) == NULL_TREE
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
|
|
|
|
|
{
|
|
|
|
|
tree temp = lookup_field_1 (TREE_TYPE (field), name);
|
|
|
|
|
if (temp)
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
if (DECL_NAME (field) == name)
|
|
|
|
|
{
|
|
|
|
|
if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
|
|
|
|
|
&& DECL_ASSEMBLER_NAME (field) != NULL)
|
|
|
|
|
GNU_xref_ref(current_function_decl,
|
|
|
|
|
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (field)));
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
field = TREE_CHAIN (field);
|
|
|
|
|
}
|
|
|
|
|
/* Not found. */
|
|
|
|
|
if (name == _vptr_name)
|
|
|
|
|
{
|
|
|
|
|
/* Give the user what s/he thinks s/he wants. */
|
|
|
|
|
if (TYPE_VIRTUAL_P (type))
|
|
|
|
|
return CLASSTYPE_VFIELD (type);
|
|
|
|
|
}
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
if necessary.
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
enum visibility_type
|
|
|
|
|
compute_visibility (basetype_path, field)
|
|
|
|
|
tree basetype_path, field;
|
|
|
|
|
{
|
|
|
|
|
enum visibility_type visibility = visibility_public;
|
|
|
|
|
tree types;
|
|
|
|
|
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)))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
|
|
|
|
|
/* Make these special cases fast. */
|
|
|
|
|
if (BINFO_TYPE (basetype_path) == current_class_type)
|
|
|
|
|
{
|
|
|
|
|
if (DECL_PUBLIC (field))
|
|
|
|
|
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)
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
|
|
|
|
|
/* Friend function manipulating members it gets (for being a friend). */
|
|
|
|
|
if (is_friend (context, current_function_decl))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
protected members.
|
|
|
|
|
|
|
|
|
|
private members are not ok. */
|
|
|
|
|
if (current_class_type && DECL_VISIBILITY (field) == NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_PRIVATE (field))
|
|
|
|
|
PRIVATE_RETURN;
|
|
|
|
|
|
|
|
|
|
if (TREE_PROTECTED (field))
|
|
|
|
|
{
|
|
|
|
|
if (context == current_class_type
|
|
|
|
|
|| UNIQUELY_DERIVED_FROM_P (context, current_class_type))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
else
|
|
|
|
|
PROTECTED_RETURN;
|
|
|
|
|
}
|
|
|
|
|
else my_friendly_abort (94);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Friend function manipulating members it gets (for being a friend). */
|
|
|
|
|
if (is_friend (context, current_function_decl))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
|
|
|
|
|
/* must reverse more than one element */
|
|
|
|
|
basetype_path = reverse_path (basetype_path);
|
|
|
|
|
types = basetype_path;
|
|
|
|
|
|
|
|
|
|
while (types)
|
|
|
|
|
{
|
|
|
|
|
tree member;
|
|
|
|
|
tree binfo = types;
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
|
|
|
|
|
member = purpose_member (type, DECL_VISIBILITY (field));
|
|
|
|
|
if (member)
|
|
|
|
|
{
|
|
|
|
|
visibility = (enum visibility_type)TREE_VALUE (member);
|
|
|
|
|
if (visibility == visibility_public
|
|
|
|
|
|| is_friend (type, current_function_decl)
|
|
|
|
|
|| (visibility == visibility_protected
|
|
|
|
|
&& current_class_type
|
|
|
|
|
&& UNIQUELY_DERIVED_FROM_P (context, current_class_type)))
|
|
|
|
|
visibility = visibility_public;
|
|
|
|
|
goto ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Friends inherit the visibility of the class they inherit from. */
|
|
|
|
|
if (is_friend (type, current_function_decl))
|
|
|
|
|
{
|
|
|
|
|
if (type == context)
|
|
|
|
|
{
|
|
|
|
|
visibility = visibility_public;
|
|
|
|
|
goto ret;
|
|
|
|
|
}
|
|
|
|
|
if (TREE_PROTECTED (field))
|
|
|
|
|
{
|
|
|
|
|
visibility = visibility_public;
|
|
|
|
|
goto ret;
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
/* This short-cut is too short. */
|
|
|
|
|
if (visibility == visibility_public)
|
|
|
|
|
goto ret;
|
|
|
|
|
#endif
|
|
|
|
|
/* else, may be a friend of a deeper base class */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == context)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
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 (types)
|
|
|
|
|
{
|
|
|
|
|
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))
|
|
|
|
|
PRIVATE_RETURN;
|
|
|
|
|
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. */
|
|
|
|
|
if (current_class_type
|
|
|
|
|
&& UNIQUELY_DERIVED_FROM_P (context, current_class_type))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
PROTECTED_RETURN;
|
|
|
|
|
}
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (visibility == visibility_protected)
|
|
|
|
|
{
|
|
|
|
|
/* reverse_path? */
|
|
|
|
|
if (TREE_PRIVATE (field))
|
|
|
|
|
PRIVATE_RETURN;
|
|
|
|
|
/* We want to make sure that all non-private members in
|
|
|
|
|
the current class (as derived) are accessible. */
|
|
|
|
|
if (current_class_type
|
|
|
|
|
&& UNIQUELY_DERIVED_FROM_P (context, current_class_type))
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
PROTECTED_RETURN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (visibility == visibility_private
|
|
|
|
|
&& current_class_type != NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_PRIVATE (field))
|
|
|
|
|
{
|
|
|
|
|
reverse_path (basetype_path);
|
|
|
|
|
PRIVATE_RETURN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if the field isn't protected. */
|
|
|
|
|
if (TREE_PROTECTED (field))
|
|
|
|
|
{
|
|
|
|
|
tree test = basetype_path;
|
|
|
|
|
while (test)
|
|
|
|
|
{
|
|
|
|
|
if (BINFO_TYPE (test) == current_class_type)
|
|
|
|
|
break;
|
|
|
|
|
test = BINFO_INHERITANCE_CHAIN (test);
|
|
|
|
|
}
|
|
|
|
|
reverse_path (basetype_path);
|
|
|
|
|
if (test)
|
|
|
|
|
PUBLIC_RETURN;
|
|
|
|
|
PROTECTED_RETURN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if the field isn't a public member of
|
|
|
|
|
a private base class. */
|
|
|
|
|
|
|
|
|
|
visibility = visibility_public;
|
|
|
|
|
types = BINFO_INHERITANCE_CHAIN (basetype_path);
|
|
|
|
|
while (types)
|
|
|
|
|
{
|
|
|
|
|
if (! TREE_VIA_PUBLIC (types))
|
|
|
|
|
{
|
|
|
|
|
if (visibility == visibility_private)
|
|
|
|
|
{
|
|
|
|
|
visibility = visibility_private;
|
|
|
|
|
goto ret;
|
|
|
|
|
}
|
|
|
|
|
visibility = visibility_private;
|
|
|
|
|
}
|
|
|
|
|
if (BINFO_TYPE (types) == context)
|
|
|
|
|
{
|
|
|
|
|
visibility = visibility_public;
|
|
|
|
|
goto ret;
|
|
|
|
|
}
|
|
|
|
|
types = BINFO_INHERITANCE_CHAIN (types);
|
|
|
|
|
}
|
|
|
|
|
my_friendly_abort (95);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret:
|
|
|
|
|
reverse_path (basetype_path);
|
|
|
|
|
|
|
|
|
|
if (visibility == visibility_public)
|
|
|
|
|
DECL_PUBLIC (field) = 1;
|
|
|
|
|
else if (visibility == visibility_protected)
|
|
|
|
|
DECL_PROTECTED (field) = 1;
|
|
|
|
|
else if (visibility == visibility_private)
|
|
|
|
|
DECL_PRIVATE (field) = 1;
|
|
|
|
|
else my_friendly_abort (96);
|
|
|
|
|
return visibility;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
static int
|
|
|
|
|
is_subobject_of_p (parent, binfo)
|
|
|
|
|
tree parent, binfo;
|
|
|
|
|
{
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
|
|
|
|
|
if (parent == binfo)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* 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))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
static int
|
|
|
|
|
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. */
|
|
|
|
|
static int
|
|
|
|
|
lookup_fnfields_here (type, name)
|
|
|
|
|
tree type, name;
|
|
|
|
|
{
|
|
|
|
|
int index = lookup_fnfields_1 (type, name);
|
|
|
|
|
tree fndecls;
|
|
|
|
|
|
|
|
|
|
if (index <= 0)
|
|
|
|
|
return index;
|
|
|
|
|
fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
|
|
|
|
|
while (fndecls)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls))
|
|
|
|
|
== TYPE_MAIN_VARIANT (type))
|
|
|
|
|
return index;
|
|
|
|
|
fndecls = TREE_CHAIN (fndecls);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
the error. */
|
|
|
|
|
tree
|
|
|
|
|
lookup_field (xbasetype, name, protect, want_type)
|
|
|
|
|
register tree xbasetype, name;
|
|
|
|
|
int protect, want_type;
|
|
|
|
|
{
|
|
|
|
|
int head = 0, tail = 0;
|
|
|
|
|
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. */
|
|
|
|
|
char *errstr = 0;
|
|
|
|
|
|
|
|
|
|
/* 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]++;
|
|
|
|
|
tem = TREE_CHAIN (tem);
|
|
|
|
|
}
|
|
|
|
|
if (tem)
|
|
|
|
|
{
|
|
|
|
|
if (protect && TREE_TYPE (tem))
|
|
|
|
|
{
|
|
|
|
|
error (TREE_STRING_POINTER (TREE_TYPE (tem)),
|
|
|
|
|
IDENTIFIER_POINTER (name),
|
|
|
|
|
TYPE_NAME_STRING (DECL_FIELD_CONTEXT (TREE_VALUE (tem))));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
if (TREE_VALUE (tem) == NULL_TREE)
|
|
|
|
|
memoized_fast_rejects[0] += 1;
|
|
|
|
|
else
|
|
|
|
|
memoized_fast_finds[0] += 1;
|
|
|
|
|
return TREE_VALUE (tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_lookup_field++;
|
|
|
|
|
#endif
|
|
|
|
|
if (protect && flag_memoize_lookups && ! global_bindings_p ())
|
|
|
|
|
entry = make_memoized_table_entry (type, name, 0);
|
|
|
|
|
else
|
|
|
|
|
entry = 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)
|
|
|
|
|
rval = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
if (rval)
|
|
|
|
|
{
|
|
|
|
|
if (protect)
|
|
|
|
|
{
|
|
|
|
|
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'";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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'";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
{
|
|
|
|
|
if (errstr)
|
|
|
|
|
{
|
|
|
|
|
/* This depends on behavior of lookup_field_1! */
|
|
|
|
|
tree error_string = my_build_string (errstr);
|
|
|
|
|
TREE_TYPE (entry) = error_string;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Let entry know there is no problem with this access. */
|
|
|
|
|
TREE_TYPE (entry) = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
TREE_VALUE (entry) = rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errstr && protect)
|
|
|
|
|
{
|
|
|
|
|
error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
binfo = basetype_path;
|
|
|
|
|
binfo_h = binfo;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
tree nval;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
tree btypes;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
else
|
|
|
|
|
btypes = tree_cons (NULL_TREE,
|
|
|
|
|
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
|
|
|
|
|
btypes);
|
|
|
|
|
obstack_ptr_grow (&search_obstack, btypes);
|
|
|
|
|
tail += 1;
|
|
|
|
|
if (tail >= search_stack->limit)
|
|
|
|
|
my_friendly_abort (98);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
else
|
|
|
|
|
BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
binfo = basetype_path;
|
|
|
|
|
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
|
|
|
|
|
here (binfo). */
|
|
|
|
|
}
|
|
|
|
|
else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
|
|
|
|
|
{
|
|
|
|
|
/* This is ok, the member found is here (binfo), not in
|
|
|
|
|
rval_binfo. */
|
|
|
|
|
if (nval)
|
|
|
|
|
{
|
|
|
|
|
rval = nval;
|
|
|
|
|
if (entry || protect)
|
|
|
|
|
this_v = compute_visibility (basetype_path, rval);
|
|
|
|
|
/* These may look ambiguous, but they really are not. */
|
|
|
|
|
if (vbase_name_p)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Undo finding it before, as something else hides it. */
|
|
|
|
|
rval = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
rval_binfo = binfo;
|
|
|
|
|
rval_binfo_h = binfo_h;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is ambiguous. */
|
|
|
|
|
errstr = "request for member `%s' is ambiguous";
|
|
|
|
|
protect = 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
tree *tp = search_stack->first;
|
|
|
|
|
tree *search_tail = tp + tail;
|
|
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
TREE_VALUE (entry) = rval;
|
|
|
|
|
|
|
|
|
|
if (want_type && (rval == NULL_TREE || TREE_CODE (rval) != TYPE_DECL))
|
|
|
|
|
{
|
|
|
|
|
rval = NULL_TREE;
|
|
|
|
|
errstr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this FIELD_DECL defines its own visibility, deal with that. */
|
|
|
|
|
if (rval && errstr == 0
|
|
|
|
|
&& ((protect&1) || entry)
|
|
|
|
|
&& DECL_LANG_SPECIFIC (rval)
|
|
|
|
|
&& DECL_VISIBILITY (rval))
|
|
|
|
|
{
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
own_visibility = new_v;
|
|
|
|
|
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
|
|
|
|
|
tp += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
|
|
|
|
|
tp += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
|
|
|
|
|
if (errstr == 0)
|
|
|
|
|
{
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
{
|
|
|
|
|
if (errstr)
|
|
|
|
|
{
|
|
|
|
|
tree error_string = my_build_string (errstr);
|
|
|
|
|
/* Save error message with entry. */
|
|
|
|
|
TREE_TYPE (entry) = error_string;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Mark entry as having no error string. */
|
|
|
|
|
TREE_TYPE (entry) = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errstr && protect)
|
|
|
|
|
{
|
|
|
|
|
error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
|
|
|
|
|
rval = error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to find NAME inside a nested class. */
|
|
|
|
|
tree
|
|
|
|
|
lookup_nested_field (name, complain)
|
|
|
|
|
tree name;
|
|
|
|
|
int complain;
|
|
|
|
|
{
|
|
|
|
|
register tree t;
|
|
|
|
|
|
|
|
|
|
tree id = NULL_TREE;
|
|
|
|
|
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 && DECL_CONTEXT (t);
|
|
|
|
|
t = TREE_CHAIN (DECL_CONTEXT (t)))
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
id = NULL_TREE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (id != NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (id) == FIELD_DECL
|
|
|
|
|
&& ! TREE_STATIC (id)
|
|
|
|
|
&& TREE_TYPE (id) != error_mark_node)
|
|
|
|
|
{
|
|
|
|
|
if (complain)
|
|
|
|
|
{
|
|
|
|
|
/* 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
|
|
|
|
|
(DECL_CONTEXT (t))));
|
|
|
|
|
/* Mark this for do_identifier(). It would otherwise
|
|
|
|
|
claim that the variable was undeclared. */
|
|
|
|
|
TREE_TYPE (id) = error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id = NULL_TREE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
static int
|
|
|
|
|
lookup_fnfields_1 (type, name)
|
|
|
|
|
tree type, name;
|
|
|
|
|
{
|
|
|
|
|
register tree method_vec = CLASSTYPE_METHOD_VEC (type);
|
|
|
|
|
|
|
|
|
|
if (method_vec != 0)
|
|
|
|
|
{
|
|
|
|
|
register tree *methods = &TREE_VEC_ELT (method_vec, 0);
|
|
|
|
|
register tree *end = TREE_VEC_END (method_vec);
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_lookup_fnfields_1++;
|
|
|
|
|
#endif
|
|
|
|
|
if (*methods && name == constructor_name (type))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
while (++methods != end)
|
|
|
|
|
{
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_outer_fields_searched++;
|
|
|
|
|
#endif
|
|
|
|
|
if (DECL_NAME (*methods) == name)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (methods != end)
|
|
|
|
|
return methods - &TREE_VEC_ELT (method_vec, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
which have name NAME.
|
|
|
|
|
|
|
|
|
|
No visibility information is computed by this function,
|
|
|
|
|
other then to adorn the list of basetypes with
|
|
|
|
|
TREE_VIA_PUBLIC.
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
tree
|
|
|
|
|
lookup_fnfields (basetype_path, name, complain)
|
|
|
|
|
tree basetype_path, name;
|
|
|
|
|
int complain;
|
|
|
|
|
{
|
|
|
|
|
int head = 0, tail = 0;
|
|
|
|
|
tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE, rval_binfo_h;
|
|
|
|
|
tree entry, binfo, basetype_chain, binfo_h;
|
|
|
|
|
int find_all = 0;
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
int protect = complain;
|
|
|
|
|
|
|
|
|
|
/* Things for memoization. */
|
|
|
|
|
char *errstr = 0;
|
|
|
|
|
|
|
|
|
|
/* Set this to nonzero if we don't know how to compute
|
|
|
|
|
accurate error messages for visibility. */
|
|
|
|
|
int index = MEMOIZED_HASH_FN (name);
|
|
|
|
|
|
|
|
|
|
if (complain == -1)
|
|
|
|
|
{
|
|
|
|
|
find_all = 1;
|
|
|
|
|
protect = complain = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
binfo = basetype_path;
|
|
|
|
|
binfo_h = binfo;
|
|
|
|
|
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]++;
|
|
|
|
|
tem = TREE_CHAIN (tem);
|
|
|
|
|
}
|
|
|
|
|
if (tem)
|
|
|
|
|
{
|
|
|
|
|
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)))));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
if (TREE_VALUE (tem) == NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
memoized_fast_rejects[1] += 1;
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 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)
|
|
|
|
|
break;
|
|
|
|
|
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;
|
|
|
|
|
return TREE_VALUE (tem);
|
|
|
|
|
}
|
|
|
|
|
/* else, we must re-find this field by hand. */
|
|
|
|
|
baselink = tree_cons (basetype_path, TREE_VALUE (baselink), TREE_CHAIN (baselink));
|
|
|
|
|
return baselink;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
n_calls_lookup_fnfields++;
|
|
|
|
|
#endif
|
|
|
|
|
if (protect && flag_memoize_lookups && ! global_bindings_p ())
|
|
|
|
|
entry = make_memoized_table_entry (type, name, 1);
|
|
|
|
|
else
|
|
|
|
|
entry = 0;
|
|
|
|
|
|
|
|
|
|
index = lookup_fnfields_here (type, name);
|
|
|
|
|
if (index >= 0 || lookup_field_1 (type, name))
|
|
|
|
|
{
|
|
|
|
|
rval_binfo = basetype_path;
|
|
|
|
|
rval_binfo_h = rval_binfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
{
|
|
|
|
|
TREE_VALUE (entry) = rvals;
|
|
|
|
|
TREE_TYPE (entry) = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errstr && protect)
|
|
|
|
|
{
|
|
|
|
|
error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
return rvals;
|
|
|
|
|
}
|
|
|
|
|
rval = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
binfo = basetype_path;
|
|
|
|
|
binfo_h = binfo;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
tree btypes;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
else
|
|
|
|
|
btypes = tree_cons (NULL_TREE,
|
|
|
|
|
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
|
|
|
|
|
btypes);
|
|
|
|
|
obstack_ptr_grow (&search_obstack, btypes);
|
|
|
|
|
tail += 1;
|
|
|
|
|
if (tail >= search_stack->limit)
|
|
|
|
|
my_friendly_abort (99);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
else
|
|
|
|
|
BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
binfo = basetype_path;
|
|
|
|
|
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
|
|
|
|
|
here (binfo). */
|
|
|
|
|
}
|
|
|
|
|
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_binfo. */
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
|
|
|
|
|
/* Note, rvals can only be previously set if find_all is
|
|
|
|
|
true. */
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Undo finding it before, as something else hides it. */
|
|
|
|
|
rval = NULL_TREE;
|
|
|
|
|
rvals = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
rval_binfo = binfo;
|
|
|
|
|
rval_binfo_h = binfo_h;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is ambiguous. */
|
|
|
|
|
errstr = "request for member `%s' is ambiguous";
|
|
|
|
|
rvals = error_mark_node;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
tree *tp = search_stack->first;
|
|
|
|
|
tree *search_tail = tp + tail;
|
|
|
|
|
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
|
|
|
|
|
tp += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
|
{
|
|
|
|
|
if (errstr)
|
|
|
|
|
{
|
|
|
|
|
tree error_string = my_build_string (errstr);
|
|
|
|
|
/* Save error message with entry. */
|
|
|
|
|
TREE_TYPE (entry) = error_string;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Mark entry as having no error string. */
|
|
|
|
|
TREE_TYPE (entry) = NULL_TREE;
|
|
|
|
|
TREE_VALUE (entry) = rvals;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errstr && protect)
|
|
|
|
|
{
|
|
|
|
|
error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
|
|
|
|
|
rvals = error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rvals;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
even be queued. */
|
|
|
|
|
|
|
|
|
|
HOST_WIDE_INT
|
|
|
|
|
breadth_first_search (binfo, testfn, qfn)
|
|
|
|
|
tree binfo;
|
|
|
|
|
int (*testfn)();
|
|
|
|
|
int (*qfn)();
|
|
|
|
|
{
|
|
|
|
|
int head = 0, tail = 0;
|
|
|
|
|
int rval = 0;
|
|
|
|
|
|
|
|
|
|
search_stack = push_search_level (search_stack, &search_obstack);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
tail += 2;
|
|
|
|
|
if (tail >= search_stack->limit)
|
|
|
|
|
my_friendly_abort (100);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
{
|
|
|
|
|
rval = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
binfo = search_stack->first[head++];
|
|
|
|
|
i = (int) search_stack->first[head++];
|
|
|
|
|
if (rval = (*testfn) (binfo, i))
|
|
|
|
|
break;
|
|
|
|
|
binfo = BINFO_BASETYPE (binfo, i);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
tree *tp = search_stack->first;
|
|
|
|
|
tree *search_tail = tp + tail;
|
|
|
|
|
while (tp < search_tail)
|
|
|
|
|
{
|
|
|
|
|
tree binfo = *tp++;
|
|
|
|
|
int i = (HOST_WIDE_INT)(*tp++);
|
|
|
|
|
CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Functions to use in breadth first searches. */
|
|
|
|
|
typedef tree (*pft)();
|
|
|
|
|
typedef int (*pfi)();
|
|
|
|
|
|
|
|
|
|
int tree_needs_constructor_p (binfo, i)
|
|
|
|
|
tree binfo;
|
|
|
|
|
int i;
|
|
|
|
|
{
|
|
|
|
|
tree basetype;
|
|
|
|
|
my_friendly_assert (i != 0, 296);
|
|
|
|
|
basetype = BINFO_TYPE (BINFO_BASETYPE (binfo, i));
|
|
|
|
|
return TYPE_NEEDS_CONSTRUCTOR (basetype);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static tree declarator;
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
get_virtuals_named_this (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree fields;
|
|
|
|
|
|
|
|
|
|
fields = lookup_fnfields (binfo, declarator, -1);
|
|
|
|
|
/* fields cannot be error_mark_node */
|
|
|
|
|
|
|
|
|
|
if (fields == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Get to the function decls, and return the first virtual function
|
|
|
|
|
with this name, if there is one. */
|
|
|
|
|
while (fields)
|
|
|
|
|
{
|
|
|
|
|
tree fndecl;
|
|
|
|
|
|
|
|
|
|
for (fndecl = TREE_VALUE (fields); fndecl; fndecl = DECL_CHAIN (fndecl))
|
|
|
|
|
if (DECL_VINDEX (fndecl))
|
|
|
|
|
return fields;
|
|
|
|
|
fields = next_baselink (fields);
|
|
|
|
|
}
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static tree get_virtual_destructor (binfo, i)
|
|
|
|
|
tree binfo;
|
|
|
|
|
int i;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
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);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tree_has_any_destructor_p (binfo, i)
|
|
|
|
|
tree binfo;
|
|
|
|
|
int i;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
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. */
|
|
|
|
|
tree
|
|
|
|
|
get_first_matching_virtual (binfo, fndecl, dtorp)
|
|
|
|
|
tree binfo, fndecl;
|
|
|
|
|
int dtorp;
|
|
|
|
|
{
|
|
|
|
|
tree tmp = NULL_TREE;
|
|
|
|
|
|
|
|
|
|
/* Breadth first search routines start searching basetypes
|
|
|
|
|
of TYPE, so we must perform first ply of search here. */
|
|
|
|
|
if (dtorp)
|
|
|
|
|
{
|
|
|
|
|
if (tree_has_any_destructor_p (binfo, -1))
|
|
|
|
|
tmp = get_virtual_destructor (binfo, -1);
|
|
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
|
|
|
|
if (get_base_distance (DECL_CONTEXT (tmp),
|
|
|
|
|
DECL_CONTEXT (fndecl), 0, 0) > 0)
|
|
|
|
|
DECL_CONTEXT (fndecl) = DECL_CONTEXT (tmp);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp = (tree) breadth_first_search (binfo,
|
|
|
|
|
(pfi) get_virtual_destructor,
|
|
|
|
|
tree_has_any_destructor_p);
|
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
|
|
|
|
if (get_base_distance (DECL_CONTEXT (tmp),
|
|
|
|
|
DECL_CONTEXT (fndecl), 0, 0) > 0)
|
|
|
|
|
DECL_CONTEXT (fndecl) = DECL_CONTEXT (tmp);
|
|
|
|
|
}
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
|
|
|
|
|
drettype = TREE_TYPE (TREE_TYPE (fndecl));
|
|
|
|
|
dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
|
|
|
|
|
if (DECL_STATIC_FUNCTION_P (fndecl))
|
|
|
|
|
instptr_type = NULL_TREE;
|
|
|
|
|
else
|
|
|
|
|
instptr_type = TREE_TYPE (TREE_VALUE (dtypes));
|
|
|
|
|
|
|
|
|
|
for (baselink = get_virtuals_named_this (binfo);
|
|
|
|
|
baselink; baselink = next_baselink (baselink))
|
|
|
|
|
{
|
|
|
|
|
for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
|
|
|
|
|
{
|
|
|
|
|
if (! DECL_VINDEX (tmp))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
return tmp;
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
|
|
|
|
/* If this is ambiguous, we will warn about it later. */
|
|
|
|
|
if (best)
|
|
|
|
|
{
|
|
|
|
|
if (get_base_distance (DECL_CLASS_CONTEXT (best),
|
|
|
|
|
DECL_CLASS_CONTEXT (tmp), 0, 0) > 0)
|
|
|
|
|
best = tmp;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
best = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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 (best)
|
|
|
|
|
{
|
|
|
|
|
if (get_base_distance (DECL_CONTEXT (best),
|
|
|
|
|
DECL_CONTEXT (fndecl), 0, 0) > 0)
|
|
|
|
|
DECL_CONTEXT (fndecl) = DECL_CONTEXT (best);
|
|
|
|
|
}
|
|
|
|
|
return 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. */
|
|
|
|
|
tree
|
|
|
|
|
get_abstract_virtuals (type)
|
|
|
|
|
tree 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))
|
|
|
|
|
{
|
|
|
|
|
int normal;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
if (base == type)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 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))));
|
|
|
|
|
|
|
|
|
|
if (normal)
|
|
|
|
|
tmp = TREE_CHAIN (TYPE_BINFO_VIRTUALS (type));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (flag_dossier)
|
|
|
|
|
tmp = TREE_CHAIN (tmp);
|
|
|
|
|
|
|
|
|
|
while (tmp)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
tmp = TREE_CHAIN (tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
|
|
|
|
|
{
|
|
|
|
|
if (! BINFO_VIRTUALS (vbases))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
tmp = TREE_CHAIN (BINFO_VIRTUALS (vbases));
|
|
|
|
|
while (tmp)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
tmp = TREE_CHAIN (tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
get_baselinks (type_as_binfo_list, type, name)
|
|
|
|
|
tree type_as_binfo_list;
|
|
|
|
|
tree type, name;
|
|
|
|
|
{
|
|
|
|
|
int head = 0, tail = 0, index;
|
|
|
|
|
tree rval = 0, nval = 0;
|
|
|
|
|
tree basetypes = type_as_binfo_list;
|
|
|
|
|
tree binfo = TYPE_BINFO (type);
|
|
|
|
|
|
|
|
|
|
search_stack = push_search_level (search_stack, &search_obstack);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
tree btypes;
|
|
|
|
|
|
|
|
|
|
btypes = hash_tree_cons (TREE_VIA_PUBLIC (base_binfo),
|
|
|
|
|
TREE_VIA_VIRTUAL (base_binfo),
|
|
|
|
|
TREE_VIA_PROTECTED (base_binfo),
|
|
|
|
|
NULL_TREE, base_binfo,
|
|
|
|
|
basetypes);
|
|
|
|
|
obstack_ptr_grow (&search_obstack, btypes);
|
|
|
|
|
search_stack->first = (tree *)obstack_base (&search_obstack);
|
|
|
|
|
tail += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dont_queue:
|
|
|
|
|
/* Process head of queue, if one exists. */
|
|
|
|
|
if (head >= tail)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
basetypes = search_stack->first[head++];
|
|
|
|
|
binfo = TREE_VALUE (basetypes);
|
|
|
|
|
type = BINFO_TYPE (binfo);
|
|
|
|
|
index = lookup_fnfields_1 (type, name);
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
goto dont_queue;
|
|
|
|
|
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);
|
|
|
|
|
goto dont_queue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nval = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
search_stack = pop_search_level (search_stack);
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
next_baselink (baselink)
|
|
|
|
|
tree baselink;
|
|
|
|
|
{
|
|
|
|
|
tree tmp = TREE_TYPE (baselink);
|
|
|
|
|
baselink = TREE_CHAIN (baselink);
|
|
|
|
|
while (tmp)
|
|
|
|
|
{
|
|
|
|
|
/* @@ does not yet add previous base types. */
|
|
|
|
|
baselink = tree_cons (TREE_PURPOSE (tmp), TREE_VALUE (tmp),
|
|
|
|
|
baselink);
|
|
|
|
|
TREE_TYPE (baselink) = TREE_TYPE (tmp);
|
|
|
|
|
tmp = TREE_CHAIN (tmp);
|
|
|
|
|
}
|
|
|
|
|
return baselink;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
static int cid;
|
|
|
|
|
|
|
|
|
|
/* Matrix implementing a relation from CLASSTYPE X CLASSTYPE => INT.
|
|
|
|
|
Relation yields 1 if C1 <= C2, 0 otherwise. */
|
|
|
|
|
typedef char mi_boolean;
|
|
|
|
|
static mi_boolean *mi_matrix;
|
|
|
|
|
|
|
|
|
|
/* Type for which this matrix is defined. */
|
|
|
|
|
static tree mi_type;
|
|
|
|
|
|
|
|
|
|
/* Size of the matrix for indexing purposes. */
|
|
|
|
|
static int mi_size;
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
static tree
|
|
|
|
|
convert_pointer_to_single_level (to_type, expr)
|
|
|
|
|
tree to_type, expr;
|
|
|
|
|
{
|
|
|
|
|
tree binfo_of_derived;
|
|
|
|
|
tree last;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
would be no record. */
|
|
|
|
|
static void
|
|
|
|
|
dfs_walk (binfo, fn, qfn)
|
|
|
|
|
tree binfo;
|
|
|
|
|
void (*fn)();
|
|
|
|
|
int (*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 ((*qfn)(base_binfo))
|
|
|
|
|
{
|
|
|
|
|
#define NEW_CONVERT 1
|
|
|
|
|
#if NEW_CONVERT
|
|
|
|
|
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
|
|
|
|
|
right type. */
|
|
|
|
|
vbase_decl_ptr_intermediate =
|
|
|
|
|
(tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#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
|
|
|
|
|
answer.
|
|
|
|
|
|
|
|
|
|
If it doesn't, the second algorithm is at fault
|
|
|
|
|
and needs to be fixed.
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
fixed by the second. */
|
|
|
|
|
#endif
|
|
|
|
|
tree vdpi1, vdpi2;
|
|
|
|
|
|
|
|
|
|
#ifdef CHECK_convert_pointer_to_single_level
|
|
|
|
|
vdpi1 = convert_pointer_to (BINFO_TYPE (base_binfo),
|
|
|
|
|
vbase_decl_ptr_intermediate);
|
|
|
|
|
#endif
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
extern int errorcount;
|
|
|
|
|
errorcount -=2;
|
|
|
|
|
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");
|
|
|
|
|
else
|
|
|
|
|
warning ("internal: convert_pointer_to_single_level: They might not be the same, going with old algorithm");
|
|
|
|
|
vbase_decl_ptr_intermediate = vdpi1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dfs_walk (base_binfo, fn, qfn);
|
|
|
|
|
|
|
|
|
|
vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
|
|
|
|
|
} else
|
|
|
|
|
#endif
|
|
|
|
|
dfs_walk (base_binfo, fn, qfn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn (binfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_number (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
BINFO_CID (binfo) = ++cid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_unnumber (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
BINFO_CID (binfo) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_mark (binfo) tree binfo;
|
|
|
|
|
{ SET_BINFO_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_unmark (binfo) tree binfo;
|
|
|
|
|
{ CLEAR_BINFO_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_mark_vtable_path (binfo) tree binfo;
|
|
|
|
|
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_unmark_vtable_path (binfo) tree binfo;
|
|
|
|
|
{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_mark_new_vtable (binfo) tree binfo;
|
|
|
|
|
{ SET_BINFO_NEW_VTABLE_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_unmark_new_vtable (binfo) tree binfo;
|
|
|
|
|
{ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo); }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_clear_search_slot (binfo) tree binfo;
|
|
|
|
|
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_debug_mark (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
if (methods == 0
|
|
|
|
|
|| ! CLASSTYPE_INTERFACE_UNKNOWN (t)
|
|
|
|
|
|| (write_virtuals == 2 && TYPE_VIRTUAL_P (t)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
else
|
|
|
|
|
methods = TREE_VEC_ELT (methods, 1);
|
|
|
|
|
while (methods)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
the debugging info. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
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. */
|
|
|
|
|
static void
|
|
|
|
|
dfs_find_vbases (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_init_vbase_pointers (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
tree fields = TYPE_FIELDS (type);
|
|
|
|
|
tree path, this_vbase_ptr;
|
|
|
|
|
int distance;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
pointer fields. */
|
|
|
|
|
if (CLASSTYPE_DOSSIER (type) && VFIELD_NAME_P (DECL_NAME (fields)))
|
|
|
|
|
/* Get past vtable for the object. */
|
|
|
|
|
fields = TREE_CHAIN (fields);
|
|
|
|
|
|
|
|
|
|
if (fields == NULL_TREE
|
|
|
|
|
|| DECL_NAME (fields) == NULL_TREE
|
|
|
|
|
|| ! VBASE_NAME_P (DECL_NAME (fields)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
#if NEW_CONVERT
|
|
|
|
|
this_vbase_ptr = vbase_decl_ptr_intermediate;
|
|
|
|
|
|
|
|
|
|
if (TYPE_POINTER_TO (type) != TREE_TYPE (this_vbase_ptr))
|
|
|
|
|
my_friendly_abort (125);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if NEW_CONVERT == 0
|
|
|
|
|
distance = get_base_distance (type, TREE_TYPE (vbase_decl), 0, &path);
|
|
|
|
|
if (distance == -2)
|
|
|
|
|
{
|
|
|
|
|
error ("inheritance lattice too complex below");
|
|
|
|
|
}
|
|
|
|
|
while (path)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_VIA_VIRTUAL (path))
|
|
|
|
|
break;
|
|
|
|
|
distance -= 1;
|
|
|
|
|
path = BINFO_INHERITANCE_CHAIN (path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (distance > 0)
|
|
|
|
|
this_vbase_ptr = convert_pointer_to (type, (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (path)));
|
|
|
|
|
else
|
|
|
|
|
this_vbase_ptr = convert_pointer_to (type, vbase_decl_ptr);
|
|
|
|
|
|
|
|
|
|
/* This happens when it is ambiguous. */
|
|
|
|
|
if (this_vbase_ptr == error_mark_node)
|
|
|
|
|
return;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
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)),
|
|
|
|
|
vbase_types),
|
|
|
|
|
build_modify_expr (ref, NOP_EXPR, init),
|
|
|
|
|
vbase_init_result);
|
|
|
|
|
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). */
|
|
|
|
|
static void
|
|
|
|
|
dfs_clear_vbase_slots (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
CLASSTYPE_SEARCH_SLOT (type) = 0;
|
|
|
|
|
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
|
|
|
|
|
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
init_vbase_pointers (type, decl_ptr)
|
|
|
|
|
tree type;
|
|
|
|
|
tree 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;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
are initializing.
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
|
|
tree
|
|
|
|
|
build_vbase_vtables_init (main_binfo, binfo, true_exp, decl_ptr, ctor_p)
|
|
|
|
|
tree main_binfo, binfo;
|
|
|
|
|
tree true_exp, decl_ptr;
|
|
|
|
|
int 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);
|
|
|
|
|
|
|
|
|
|
if (ctor_p)
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
while (vbases)
|
|
|
|
|
{
|
|
|
|
|
/* 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 addr;
|
|
|
|
|
tree vtbl = BINFO_VTABLE (vbases);
|
|
|
|
|
tree init = build_unary_op (ADDR_EXPR, vtbl, 0);
|
|
|
|
|
assemble_external (vtbl);
|
|
|
|
|
TREE_USED (vtbl) = 1;
|
|
|
|
|
|
|
|
|
|
if (ctor_p == 0)
|
|
|
|
|
addr = convert_pointer_to (vbases, vbase_decl_ptr);
|
|
|
|
|
else
|
|
|
|
|
addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases));
|
|
|
|
|
|
|
|
|
|
if (addr)
|
|
|
|
|
{
|
|
|
|
|
tree ref = build_vfield_ref (build_indirect_ref (addr, 0),
|
|
|
|
|
BINFO_TYPE (vbases));
|
|
|
|
|
init = convert_force (TREE_TYPE (ref), init);
|
|
|
|
|
vtable_init_result = tree_cons (NULL_TREE, build_modify_expr (ref, NOP_EXPR, init),
|
|
|
|
|
vtable_init_result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vbases = TREE_CHAIN (vbases);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
|
|
|
|
|
|
|
|
|
|
flag_this_is_variable = old_flag;
|
|
|
|
|
if (vtable_init_result)
|
|
|
|
|
return build_compound_expr (vtable_init_result);
|
|
|
|
|
}
|
|
|
|
|
return error_mark_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
clear_search_slots (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
dfs_walk (TYPE_BINFO (type),
|
|
|
|
|
dfs_clear_search_slot, dfs_search_slot_nonempty_p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_get_vbase_types (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
tree binfos = BINFO_BASETYPES (binfo);
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
tree these_vbase_types = CLASSTYPE_VBASECLASSES (type);
|
|
|
|
|
|
|
|
|
|
if (these_vbase_types)
|
|
|
|
|
{
|
|
|
|
|
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,
|
|
|
|
|
this_type,
|
|
|
|
|
TYPE_BINFO_VTABLE (this_type),
|
|
|
|
|
TYPE_BINFO_VIRTUALS (this_type),
|
|
|
|
|
vbase_types);
|
|
|
|
|
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
|
|
|
|
|
list. */
|
|
|
|
|
tree
|
|
|
|
|
get_vbase_types (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
tree ordered_vbase_types = NULL_TREE, prev, next;
|
|
|
|
|
tree vbases;
|
|
|
|
|
|
|
|
|
|
vbase_types = NULL_TREE;
|
|
|
|
|
dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp);
|
|
|
|
|
dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
|
|
|
|
|
|
|
|
|
|
while (vbase_types)
|
|
|
|
|
{
|
|
|
|
|
/* 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;
|
|
|
|
|
vbases; vbases = next)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (prev)
|
|
|
|
|
TREE_CHAIN (prev) = TREE_CHAIN (vbases);
|
|
|
|
|
else
|
|
|
|
|
vbase_types = TREE_CHAIN (vbases);
|
|
|
|
|
TREE_CHAIN (vbases) = NULL_TREE;
|
|
|
|
|
ordered_vbase_types = chainon (ordered_vbase_types, vbases);
|
|
|
|
|
CLEAR_BINFO_VBASE_MARKED (vbases);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
prev = 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))))
|
|
|
|
|
t = TREE_CHAIN (t);
|
|
|
|
|
if (t == NULL_TREE)
|
|
|
|
|
CLEAR_BINFO_VBASE_MARKED (vbases);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ordered_vbase_types;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_record_inheritance (binfo)
|
|
|
|
|
tree 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--)
|
|
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
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
|
|
|
|
|
or C2 <= C1 or 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. */
|
|
|
|
|
|
|
|
|
|
#define SAVE_MI_MATRIX
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
build_mi_matrix (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
tree binfo = TYPE_BINFO (type);
|
|
|
|
|
cid = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef SAVE_MI_MATRIX
|
|
|
|
|
if (CLASSTYPE_MI_MATRIX (type))
|
|
|
|
|
{
|
|
|
|
|
mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
|
|
|
|
|
mi_matrix = CLASSTYPE_MI_MATRIX (type);
|
|
|
|
|
mi_type = type;
|
|
|
|
|
dfs_walk (binfo, dfs_number, unnumberedp);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
|
|
|
|
|
mi_matrix = (char *)xmalloc ((mi_size+1) * (mi_size+1));
|
|
|
|
|
mi_type = type;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
free_mi_matrix ()
|
|
|
|
|
{
|
|
|
|
|
dfs_walk (TYPE_BINFO (mi_type), dfs_unnumber, numberedp);
|
|
|
|
|
|
|
|
|
|
#ifdef SAVE_MI_MATRIX
|
|
|
|
|
CLASSTYPE_MI_MATRIX (mi_type) = mi_matrix;
|
|
|
|
|
#else
|
|
|
|
|
free (mi_matrix);
|
|
|
|
|
mi_size = 0;
|
|
|
|
|
cid = 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Local variables for detecting ambiguities of virtual functions
|
|
|
|
|
when two or more classes are joined at a multiple inheritance
|
|
|
|
|
seam. */
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
tree decl;
|
|
|
|
|
tree args;
|
|
|
|
|
tree ptr;
|
|
|
|
|
} mi_ventry;
|
|
|
|
|
static mi_ventry *mi_vmatrix;
|
|
|
|
|
static int *mi_vmax;
|
|
|
|
|
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
|
|
|
|
|
M entries per class.
|
|
|
|
|
|
|
|
|
|
This function does nothing if N is 0 or 1. */
|
|
|
|
|
void
|
|
|
|
|
build_mi_virtuals (rows, cols)
|
|
|
|
|
int rows, cols;
|
|
|
|
|
{
|
|
|
|
|
if (rows < 2 || cols == 0)
|
|
|
|
|
return;
|
|
|
|
|
mi_vrows = rows;
|
|
|
|
|
mi_vcols = cols;
|
|
|
|
|
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. */
|
|
|
|
|
mi_vmatrix -= cols;
|
|
|
|
|
mi_vmax -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Comparison function for ordering virtual function table entries. */
|
|
|
|
|
static int
|
|
|
|
|
rank_mi_virtuals (v1, v2)
|
|
|
|
|
mi_ventry *v1, *v2;
|
|
|
|
|
{
|
|
|
|
|
tree p1, p2;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = (long) (DECL_NAME (v1->decl)) - (long) (DECL_NAME (v2->decl));
|
|
|
|
|
if (i)
|
|
|
|
|
return i;
|
|
|
|
|
p1 = v1->args;
|
|
|
|
|
p2 = v2->args;
|
|
|
|
|
|
|
|
|
|
if (p1 == p2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
while (p1 && p2)
|
|
|
|
|
{
|
|
|
|
|
i = ((long) (TREE_VALUE (p1)) - (long) (TREE_VALUE (p2)));
|
|
|
|
|
if (i)
|
|
|
|
|
return i;
|
|
|
|
|
|
|
|
|
|
if (TREE_CHAIN (p1))
|
|
|
|
|
{
|
|
|
|
|
if (! TREE_CHAIN (p2))
|
|
|
|
|
return 1;
|
|
|
|
|
p1 = TREE_CHAIN (p1);
|
|
|
|
|
p2 = TREE_CHAIN (p2);
|
|
|
|
|
}
|
|
|
|
|
else if (TREE_CHAIN (p2))
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* When matches of argument lists occur, pick lowest
|
|
|
|
|
address to keep searching time to a minimum on
|
|
|
|
|
later passes--like hashing, only different.
|
|
|
|
|
*MUST BE STABLE*. */
|
|
|
|
|
if ((long) (v2->args) < (long) (v1->args))
|
|
|
|
|
v1->args = v2->args;
|
|
|
|
|
else
|
|
|
|
|
v2->args = v1->args;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Install the virtuals functions got from the initializer VIRTUALS to
|
|
|
|
|
the table at index ROW. */
|
|
|
|
|
void
|
|
|
|
|
add_mi_virtuals (row, virtuals)
|
|
|
|
|
int row;
|
|
|
|
|
tree virtuals;
|
|
|
|
|
{
|
|
|
|
|
int col = 0;
|
|
|
|
|
|
|
|
|
|
if (mi_vmatrix == 0)
|
|
|
|
|
return;
|
|
|
|
|
while (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);
|
|
|
|
|
col += 1;
|
|
|
|
|
}
|
|
|
|
|
mi_vmax[row] = col;
|
|
|
|
|
|
|
|
|
|
qsort (mi_vmatrix + row * mi_vcols,
|
|
|
|
|
col,
|
|
|
|
|
sizeof (mi_ventry),
|
|
|
|
|
rank_mi_virtuals);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If joining two types results in an ambiguity in the virtual
|
|
|
|
|
function table, report such here. */
|
|
|
|
|
void
|
|
|
|
|
report_ambiguous_mi_virtuals (rows, type)
|
|
|
|
|
int rows;
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
int *mi_vmin;
|
|
|
|
|
int row1, col1, row, col;
|
|
|
|
|
|
|
|
|
|
if (mi_vmatrix == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* 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));
|
|
|
|
|
|
|
|
|
|
/* adjust. */
|
|
|
|
|
mi_vmin -= 1;
|
|
|
|
|
|
|
|
|
|
/* 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++)
|
|
|
|
|
{
|
|
|
|
|
tree this_decl = 0;
|
|
|
|
|
|
|
|
|
|
for (col1 = mi_vmax[row1]-1; col1 >= mi_vmin[row1]; col1--)
|
|
|
|
|
{
|
|
|
|
|
tree these_args = MI_VMATRIX (row1, col1).args;
|
|
|
|
|
tree this_context;
|
|
|
|
|
|
|
|
|
|
this_decl = MI_VMATRIX (row1, col1).decl;
|
|
|
|
|
if (this_decl == 0)
|
|
|
|
|
continue;
|
|
|
|
|
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--)
|
|
|
|
|
{
|
|
|
|
|
mi_ventry this_entry;
|
|
|
|
|
|
|
|
|
|
if (MI_VMATRIX (row, col).decl == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
same base class.
|
|
|
|
|
(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
|
|
|
|
|
base classes.
|
|
|
|
|
|
|
|
|
|
The first three cases are ok (non-ambiguous). */
|
|
|
|
|
|
|
|
|
|
tree that_context, tmp;
|
|
|
|
|
int this_before_that;
|
|
|
|
|
|
|
|
|
|
if (type == BINFO_TYPE (this_context))
|
|
|
|
|
/* case 1. */
|
|
|
|
|
goto ok;
|
|
|
|
|
that_context = get_binfo (DECL_CLASS_CONTEXT (MI_VMATRIX (row, col).decl), type, 0);
|
|
|
|
|
if (that_context == this_context)
|
|
|
|
|
/* case 2. */
|
|
|
|
|
goto ok;
|
|
|
|
|
if (that_context != NULL_TREE)
|
|
|
|
|
{
|
|
|
|
|
tmp = get_binfo (that_context, this_context, 0);
|
|
|
|
|
this_before_that = (that_context != tmp);
|
|
|
|
|
if (this_before_that == 0)
|
|
|
|
|
/* case 3a. */
|
|
|
|
|
goto ok;
|
|
|
|
|
tmp = get_binfo (this_context, that_context, 0);
|
|
|
|
|
this_before_that = (this_context == tmp);
|
|
|
|
|
if (this_before_that != 0)
|
|
|
|
|
/* case 3b. */
|
|
|
|
|
goto ok;
|
|
|
|
|
|
|
|
|
|
/* case 4. */
|
|
|
|
|
/* These two are not hard errors, but could be
|
|
|
|
|
symptoms of bad code. The resultant code
|
|
|
|
|
the compiler generates needs to be checked.
|
|
|
|
|
(mrs) */
|
|
|
|
|
#if 0
|
|
|
|
|
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));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
ok:
|
|
|
|
|
MI_VMATRIX (row, col).decl = 0;
|
|
|
|
|
|
|
|
|
|
/* Let zeros propagate. */
|
|
|
|
|
if (col == mi_vmax[row]-1)
|
|
|
|
|
{
|
|
|
|
|
int i = col;
|
|
|
|
|
while (i >= mi_vmin[row]
|
|
|
|
|
&& MI_VMATRIX (row, i).decl == 0)
|
|
|
|
|
i--;
|
|
|
|
|
mi_vmax[row] = i+1;
|
|
|
|
|
}
|
|
|
|
|
else if (col == mi_vmin[row])
|
|
|
|
|
{
|
|
|
|
|
int i = col;
|
|
|
|
|
while (i < mi_vmax[row]
|
|
|
|
|
&& MI_VMATRIX (row, i).decl == 0)
|
|
|
|
|
i++;
|
|
|
|
|
mi_vmin[row] = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free (mi_vmatrix + mi_vcols);
|
|
|
|
|
mi_vmatrix = 0;
|
|
|
|
|
free (mi_vmax + 1);
|
|
|
|
|
mi_vmax = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
note_debug_info_needed (type)
|
|
|
|
|
tree 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. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_pushdecls (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
tree fields, *methods, *end;
|
|
|
|
|
tree method_vec;
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
TREE_USED (fields) = 0;
|
|
|
|
|
|
|
|
|
|
if (DECL_NAME (fields) == NULL_TREE
|
|
|
|
|
&& TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
|
|
|
|
|
{
|
|
|
|
|
dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (TREE_CODE (fields) != TYPE_DECL)
|
|
|
|
|
{
|
|
|
|
|
DECL_PUBLIC (fields) = 0;
|
|
|
|
|
DECL_PROTECTED (fields) = 0;
|
|
|
|
|
DECL_PRIVATE (fields) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DECL_NAME (fields))
|
|
|
|
|
{
|
|
|
|
|
tree value = IDENTIFIER_CLASS_VALUE (DECL_NAME (fields));
|
|
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
tree context;
|
|
|
|
|
|
|
|
|
|
/* 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 = fields;
|
|
|
|
|
else
|
|
|
|
|
value = tree_cons (NULL_TREE, fields,
|
|
|
|
|
build_tree_list (NULL_TREE, value));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
tree values;
|
|
|
|
|
int problem = 0;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
problem = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
context = DECL_CLASS_CONTEXT (sub_values);
|
|
|
|
|
|
|
|
|
|
if (! TYPE_DERIVES_FROM (context, type))
|
|
|
|
|
{
|
|
|
|
|
value = tree_cons (NULL_TREE, values, value);
|
|
|
|
|
problem = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
if (method_vec != 0)
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
while (methods != end)
|
|
|
|
|
{
|
|
|
|
|
/* 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 tmp;
|
|
|
|
|
tree old = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods));
|
|
|
|
|
|
|
|
|
|
if (old && TREE_CODE (old) == TREE_LIST)
|
|
|
|
|
tmp = tree_cons (DECL_NAME (*methods), *methods, old);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 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;
|
|
|
|
|
#if 0
|
|
|
|
|
TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods);
|
|
|
|
|
#endif
|
|
|
|
|
TREE_NONLOCAL_FLAG (tmp) = 1;
|
|
|
|
|
IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)) = tmp;
|
|
|
|
|
|
|
|
|
|
tmp = *methods;
|
|
|
|
|
while (tmp != 0)
|
|
|
|
|
{
|
|
|
|
|
DECL_PUBLIC (tmp) = 0;
|
|
|
|
|
DECL_PROTECTED (tmp) = 0;
|
|
|
|
|
DECL_PRIVATE (tmp) = 0;
|
|
|
|
|
tmp = DECL_CHAIN (tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
methods++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SET_BINFO_MARKED (binfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Consolidate unique (by name) member functions. */
|
|
|
|
|
static void
|
|
|
|
|
dfs_compress_decls (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
tree method_vec = CLASSTYPE_METHOD_VEC (type);
|
|
|
|
|
|
|
|
|
|
if (method_vec != 0)
|
|
|
|
|
{
|
|
|
|
|
/* 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
|
|
|
|
|
alone. */
|
|
|
|
|
if (TREE_CODE (tmp) != TREE_LIST)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (TREE_CHAIN (tmp) == NULL_TREE
|
|
|
|
|
&& TREE_VALUE (tmp)
|
|
|
|
|
&& 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
|
|
|
|
|
message. */
|
|
|
|
|
void
|
|
|
|
|
push_class_decls (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
tree id;
|
|
|
|
|
struct obstack *ambient_obstack = current_obstack;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
tree tags = CLASSTYPE_TAGS (type);
|
|
|
|
|
|
|
|
|
|
while (tags)
|
|
|
|
|
{
|
|
|
|
|
tree code_type_node;
|
|
|
|
|
tree tag;
|
|
|
|
|
|
|
|
|
|
switch (TREE_CODE (TREE_VALUE (tags)))
|
|
|
|
|
{
|
|
|
|
|
case ENUMERAL_TYPE:
|
|
|
|
|
code_type_node = enum_type_node;
|
|
|
|
|
break;
|
|
|
|
|
case RECORD_TYPE:
|
|
|
|
|
code_type_node = record_type_node;
|
|
|
|
|
break;
|
|
|
|
|
case CLASS_TYPE:
|
|
|
|
|
code_type_node = class_type_node;
|
|
|
|
|
break;
|
|
|
|
|
case UNION_TYPE:
|
|
|
|
|
code_type_node = union_type_node;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
my_friendly_abort (297);
|
|
|
|
|
}
|
|
|
|
|
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)));
|
|
|
|
|
#else
|
|
|
|
|
pushdecl (build_decl (TYPE_DECL, TREE_PURPOSE (tags), TREE_VALUE (tags)));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
current_obstack = &bridge_obstack;
|
|
|
|
|
search_stack = push_search_level (search_stack, &bridge_obstack);
|
|
|
|
|
|
|
|
|
|
id = TYPE_IDENTIFIER (type);
|
|
|
|
|
if (IDENTIFIER_TEMPLATE (id) != 0)
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
tree tmpl = IDENTIFIER_TEMPLATE (id);
|
|
|
|
|
push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
|
|
|
|
|
TREE_VALUE (tmpl), 1);
|
|
|
|
|
#endif
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dfs_popdecls (binfo)
|
|
|
|
|
tree binfo;
|
|
|
|
|
{
|
|
|
|
|
tree type = BINFO_TYPE (binfo);
|
|
|
|
|
tree fields = TYPE_FIELDS (type);
|
|
|
|
|
tree method_vec = CLASSTYPE_METHOD_VEC (type);
|
|
|
|
|
|
|
|
|
|
while (fields)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
if (method_vec != 0)
|
|
|
|
|
{
|
|
|
|
|
tree *methods = &TREE_VEC_ELT (method_vec, 0);
|
|
|
|
|
tree *end = TREE_VEC_END (method_vec);
|
|
|
|
|
|
|
|
|
|
/* Clear out ctors and dtors. */
|
|
|
|
|
if (*methods)
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pop_class_decls (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
/* Unmark. */
|
|
|
|
|
dfs_walk (binfo, dfs_unmark, markedp);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
tmpl = IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (type));
|
|
|
|
|
if (tmpl != 0)
|
|
|
|
|
pop_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
|
|
|
|
|
TREE_VALUE (tmpl), 1);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
we have generated.
|
|
|
|
|
|
|
|
|
|
For example, given
|
|
|
|
|
|
|
|
|
|
class A; class B; class C : A, B;
|
|
|
|
|
|
|
|
|
|
it is possible to distinguish "A" from "C's A". And given
|
|
|
|
|
|
|
|
|
|
class L;
|
|
|
|
|
class A : L; class B : L; class C : A, B;
|
|
|
|
|
|
|
|
|
|
it is possible to distinguish "L" from "A's L", and also from
|
|
|
|
|
"C's L from A".
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
tree
|
|
|
|
|
build_type_pathname (format, parent, type)
|
|
|
|
|
char *format;
|
|
|
|
|
tree parent, type;
|
|
|
|
|
{
|
|
|
|
|
extern struct obstack temporary_obstack;
|
|
|
|
|
char *first, *base, *name;
|
|
|
|
|
int i;
|
|
|
|
|
tree id;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
#ifdef JOINER
|
|
|
|
|
obstack_1grow (&temporary_obstack, JOINER);
|
|
|
|
|
#else
|
|
|
|
|
obstack_1grow (&temporary_obstack, '_');
|
|
|
|
|
#endif
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
bfs_unmark_finished_struct (binfo, i)
|
|
|
|
|
tree binfo;
|
|
|
|
|
int i;
|
|
|
|
|
{
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
binfo = BINFO_BASETYPE (binfo, i);
|
|
|
|
|
|
|
|
|
|
if (BINFO_NEW_VTABLE_MARKED (binfo))
|
|
|
|
|
{
|
|
|
|
|
tree decl, context;
|
|
|
|
|
|
|
|
|
|
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_CONTEXT (decl) = 0;
|
|
|
|
|
if (write_virtuals >= 0
|
|
|
|
|
&& DECL_INITIAL (decl) != BINFO_VIRTUALS (binfo))
|
|
|
|
|
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE,
|
|
|
|
|
BINFO_VIRTUALS (binfo));
|
|
|
|
|
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);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
unmark_finished_struct (type)
|
|
|
|
|
tree type;
|
|
|
|
|
{
|
|
|
|
|
tree binfo = TYPE_BINFO (type);
|
|
|
|
|
bfs_unmark_finished_struct (binfo, -1);
|
|
|
|
|
breadth_first_search (binfo, bfs_unmark_finished_struct, bfs_marked_vtable_pathp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
print_search_statistics ()
|
|
|
|
|
{
|
|
|
|
|
#ifdef GATHER_STATISTICS
|
|
|
|
|
if (flag_memoize_lookups)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "%d memoized contexts saved\n",
|
|
|
|
|
n_contexts_saved);
|
|
|
|
|
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);
|
|
|
|
|
#else
|
|
|
|
|
fprintf (stderr, "no search statistics\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
reinit_search_statistics ()
|
|
|
|
|
{
|
|
|
|
|
my_memoized_entry_counter = 0;
|
|
|
|
|
memoized_fast_finds[0] = 0;
|
|
|
|
|
memoized_fast_finds[1] = 0;
|
|
|
|
|
memoized_adds[0] = 0;
|
|
|
|
|
memoized_adds[1] = 0;
|
|
|
|
|
memoized_fast_rejects[0] = 0;
|
|
|
|
|
memoized_fast_rejects[1] = 0;
|
|
|
|
|
memoized_fields_searched[0] = 0;
|
|
|
|
|
memoized_fields_searched[1] = 0;
|
|
|
|
|
n_fields_searched = 0;
|
|
|
|
|
n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0;
|
|
|
|
|
n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0;
|
|
|
|
|
n_calls_get_base_type = 0;
|
|
|
|
|
n_outer_fields_searched = 0;
|
|
|
|
|
n_contexts_saved = 0;
|
|
|
|
|
}
|