6278 lines
187 KiB
C
6278 lines
187 KiB
C
/* Functions related to building and playing with classes.
|
||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||
Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */
|
||
|
||
|
||
/* High-level class interface. */
|
||
|
||
#include "config.h"
|
||
#include "tree.h"
|
||
#include "cplus-tree.h"
|
||
#include "flags.h"
|
||
#include "rtl.h"
|
||
#include "assert.h"
|
||
#include <stdio.h>
|
||
|
||
#include "obstack.h"
|
||
#define obstack_chunk_alloc xmalloc
|
||
#define obstack_chunk_free free
|
||
|
||
extern int xmalloc ();
|
||
extern void free ();
|
||
|
||
#define NULL 0
|
||
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
|
||
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
|
||
|
||
/* See cplus-decl.c for comment of this variable. */
|
||
extern int flag_int_enum_equivalence;
|
||
|
||
/* some statistics gathering help. */
|
||
static int n_vtables, n_vtable_entries, n_vtable_searches, n_vtable_elems;
|
||
static int n_convert_harshness, n_compute_conversion_costs, n_build_method_call;
|
||
static int n_inner_fields_searched;
|
||
|
||
/* Compute the ease with which a conversion can be performed
|
||
between an expected and the given type. */
|
||
static int convert_harshness ();
|
||
|
||
/* in decl.c. */
|
||
extern tree lookup_tag_current_binding_level ();
|
||
|
||
/* in method.c. */
|
||
extern void do_inline_function_hair ();
|
||
|
||
/* Way of stacking class types. */
|
||
static tree *current_class_base, *current_class_stack;
|
||
static int current_class_stacksize;
|
||
|
||
struct class_level
|
||
{
|
||
/* The previous class level. */
|
||
struct class_level *level_chain;
|
||
|
||
/* The class instance variable, as a PARM_DECL. */
|
||
tree decl;
|
||
/* The class instance variable, as an object. */
|
||
tree object;
|
||
/* The virtual function table pointer
|
||
for the class instance variable. */
|
||
tree vtable_decl;
|
||
|
||
/* Name of the current class. */
|
||
tree name;
|
||
/* Type of the current class. */
|
||
tree type;
|
||
|
||
/* Flags for this class level. */
|
||
int this_is_variable;
|
||
int memoized_lookups;
|
||
int save_memoized;
|
||
int unused;
|
||
};
|
||
|
||
tree current_class_decl, C_C_D; /* PARM_DECL: the class instance variable */
|
||
tree current_vtable_decl;
|
||
|
||
/* The following two can be derived from the previous one */
|
||
tree current_class_name; /* IDENTIFIER_NODE: name of current class */
|
||
tree current_class_type; /* _TYPE: the type of the current class */
|
||
tree prev_class_type; /* _TYPE: the previous type that was a class */
|
||
|
||
static tree get_vtable_name (), get_vfield_name ();
|
||
tree the_null_vtable_entry;
|
||
|
||
/* Way of stacking langauge names. */
|
||
static tree *current_lang_base, *current_lang_stack;
|
||
static int current_lang_stacksize;
|
||
|
||
/* Names of languages we recognize. */
|
||
tree lang_name_c, lang_name_cplusplus;
|
||
tree current_lang_name;
|
||
|
||
tree minus_one_node;
|
||
|
||
/* When layout out an aggregate type, the size of the
|
||
basetypes (virtual and non-virtual) is passed to layout_record
|
||
via this node. */
|
||
static tree base_layout_decl;
|
||
|
||
#if 0
|
||
/* Make sure that the tag NAME is defined *in the current binding level*
|
||
at least as a forward reference.
|
||
CODE says which kind of tag NAME ought to be.
|
||
|
||
Not used for C++. Not maintained. */
|
||
|
||
tree
|
||
start_struct (code, name)
|
||
enum tree_code code;
|
||
tree name;
|
||
{
|
||
/* If there is already a tag defined at this binding level
|
||
(as a forward reference), just return it. */
|
||
register tree ref = 0;
|
||
|
||
if (name != 0)
|
||
ref = lookup_tag (code, name, current_binding_level, 1);
|
||
if (ref && TREE_CODE (ref) == code)
|
||
{
|
||
if (TYPE_FIELDS (ref))
|
||
error ((code == UNION_TYPE ? "redefinition of `union %s'"
|
||
: "redefinition of `struct %s'"),
|
||
IDENTIFIER_POINTER (name));
|
||
|
||
return ref;
|
||
}
|
||
|
||
/* Otherwise create a forward-reference just so the tag is in scope. */
|
||
|
||
ref = make_lang_type (code);
|
||
/* Must re-synch this with xref_tag if you are going to use it. */
|
||
assert (0);
|
||
pushtag (name, ref);
|
||
return ref;
|
||
}
|
||
#endif
|
||
|
||
/* Virtual baseclass things. */
|
||
tree
|
||
build_vbase_pointer (exp, type)
|
||
tree exp, type;
|
||
{
|
||
char *name;
|
||
|
||
name = (char *) alloca (TYPE_NAME_LENGTH (type) + sizeof (VBASE_NAME) + 1);
|
||
sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (type));
|
||
return build_component_ref (exp, get_identifier (name), 0, 0);
|
||
}
|
||
|
||
/* Build multi-level access to EXPR using hierarchy path PATH.
|
||
CODE is PLUS_EXPR if we are going with the grain,
|
||
and MINUS_EXPR if we are not (in which case, we cannot traverse
|
||
virtual baseclass links).
|
||
|
||
TYPE is the type we want this path to have on exit.
|
||
|
||
ALIAS_THIS is non-zero if EXPR in an expression involving `this'. */
|
||
tree
|
||
build_vbase_path (code, type, expr, path, alias_this)
|
||
enum tree_code code;
|
||
tree type;
|
||
tree expr;
|
||
tree path;
|
||
int alias_this;
|
||
{
|
||
register int changed = 0;
|
||
tree last = NULL_TREE, last_virtual = NULL_TREE;
|
||
int fixed_type_p = 0 && resolves_to_fixed_type_p (expr);
|
||
tree basetype;
|
||
tree offset = integer_zero_node;
|
||
|
||
if (TREE_CHAIN (path))
|
||
path = nreverse (copy_list (path));
|
||
|
||
basetype = TREE_VALUE (path);
|
||
while (path)
|
||
{
|
||
if (TREE_VIA_VIRTUAL (path))
|
||
{
|
||
last_virtual = TYPE_MAIN_VARIANT (TREE_VALUE (path));
|
||
if (code == PLUS_EXPR)
|
||
{
|
||
changed = ! fixed_type_p;
|
||
|
||
if (last)
|
||
expr = convert_pointer_to (TREE_VALUE (last), expr);
|
||
if (changed)
|
||
expr = build_vbase_pointer (build_indirect_ref (expr, 0),
|
||
last_virtual);
|
||
else
|
||
offset = ASSOC_OFFSET (value_member (last_virtual,
|
||
CLASSTYPE_VBASECLASSES (basetype)));
|
||
/* Happens in the case of parse errors. */
|
||
if (expr == error_mark_node)
|
||
return expr;
|
||
}
|
||
else
|
||
{
|
||
error_with_aggr_type (last_virtual, "cannot cast up from virtual baseclass `%s'");
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
last = path;
|
||
path = TREE_CHAIN (path);
|
||
}
|
||
/* LAST is now the last basetype on the path. */
|
||
last = TREE_VALUE (last);
|
||
|
||
/* If we go through any virtual base pointers, make sure that
|
||
casts to BASETYPE from the last virtual base class use
|
||
the right value for BASETYPE. */
|
||
if (changed)
|
||
{
|
||
tree intype = TREE_TYPE (TREE_TYPE (expr));
|
||
if (TYPE_MAIN_VARIANT (intype) == TYPE_MAIN_VARIANT (last))
|
||
basetype = intype;
|
||
else
|
||
{
|
||
basetype = get_base_type (last, TYPE_MAIN_VARIANT (intype), 0);
|
||
offset = CLASSTYPE_OFFSET (basetype);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (last_virtual && last != last_virtual)
|
||
basetype = get_base_type (last, last_virtual, 0);
|
||
else
|
||
basetype = last;
|
||
|
||
offset = genop (code, offset, CLASSTYPE_OFFSET (basetype));
|
||
/* 900324 JRV: If code was MINUS_EXPR, genop returned a negative
|
||
offset, so shouldn't the code always be PLUS_EXPR now? */
|
||
code = PLUS_EXPR;
|
||
}
|
||
|
||
if (TREE_INT_CST_LOW (offset))
|
||
{
|
||
/* For multiple inheritance: if `this' can be set by
|
||
any function, then it could be 0 on entry
|
||
to any function. Preserve such zeroness here.
|
||
Otherwise, only in the case of constructors need
|
||
we worry, and in those cases, it will be zero,
|
||
or initialized to some legal value to which we may
|
||
add. */
|
||
tree addr = TREE_CODE (expr) == ADDR_EXPR
|
||
? expr : save_expr (expr);
|
||
expr = build (code, type, addr, offset);
|
||
|
||
if (alias_this == 0 || flag_this_is_variable)
|
||
return build (COND_EXPR, type,
|
||
build (EQ_EXPR, integer_type_node, addr, integer_zero_node),
|
||
build1 (NOP_EXPR, type, addr),
|
||
expr);
|
||
}
|
||
return build1 (NOP_EXPR, type, expr);
|
||
}
|
||
|
||
/* Virtual function things. */
|
||
|
||
/* Virtual functions to be dealt with after laying out our
|
||
virtual base classes (only if the type has any). */
|
||
static tree pending_hard_virtuals;
|
||
|
||
/* The names of the entries in the virtual table structure. */
|
||
static tree delta_name, pfn_name;
|
||
|
||
/* Temporary assoc list to memoize lookups of the left-most non-virtual
|
||
baseclass B in a lattice topped by T. B can appear multiple times
|
||
in the lattice.
|
||
TREE_PURPOSE is B's TYPE_MAIN_VARIANT.
|
||
TREE_VALUE is the path by which B is reached from T.
|
||
TREE_TYPE is B's real type.
|
||
|
||
If TREE_TYPE is NULL_TREE, it means that B was reached via
|
||
a virtual baseclass.
|
||
N.B.: This list consists of nodes on the temporary obstack. */
|
||
static tree leftmost_baseclasses;
|
||
|
||
/* Build an entry in the virtual function table.
|
||
DELTA is the offset for the `this' pointer.
|
||
PFN is an ADDR_EXPR containing a pointer to the virtual function.
|
||
Note that the index (DELTA2) in the virtual function table
|
||
is always 0. */
|
||
tree
|
||
build_vtable_entry (delta, pfn)
|
||
tree delta, pfn;
|
||
{
|
||
tree elems = tree_cons (NULL_TREE, delta,
|
||
tree_cons (NULL_TREE, integer_zero_node,
|
||
build_tree_list (NULL_TREE, pfn)));
|
||
tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
|
||
TREE_LITERAL (entry) = 1;
|
||
TREE_STATIC (entry) = 1;
|
||
TREE_READONLY (entry) = 1;
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_vtable_entries += 1;
|
||
#endif
|
||
|
||
return entry;
|
||
}
|
||
|
||
/* Given an object INSTANCE, return an expression which yields
|
||
the virtual function corresponding to INDEX. There are many special
|
||
cases for INSTANCE which we take care of here, mainly to avoid
|
||
creating extra tree nodes when we don't have to. */
|
||
tree
|
||
build_vfn_ref (ptr_to_instptr, instance, index)
|
||
tree *ptr_to_instptr, instance;
|
||
tree index;
|
||
{
|
||
extern int building_cleanup;
|
||
tree vtbl, aref;
|
||
tree basetype = TREE_TYPE (instance);
|
||
|
||
if (TREE_CODE (basetype) == REFERENCE_TYPE)
|
||
basetype = TREE_TYPE (basetype);
|
||
|
||
if (instance == C_C_D)
|
||
{
|
||
if (current_vtable_decl == NULL_TREE
|
||
|| current_vtable_decl == error_mark_node
|
||
|| get_base_type (DECL_FCONTEXT (CLASSTYPE_VFIELD (current_class_type)), basetype, 0) == NULL_TREE)
|
||
vtbl = build_indirect_ref (build_vfield_ref (instance, basetype));
|
||
else
|
||
vtbl = current_vtable_decl;
|
||
}
|
||
else
|
||
{
|
||
if (optimize)
|
||
{
|
||
/* Try to figure out what a reference refers to, and
|
||
access its virtual function table directly. */
|
||
tree ref = 0;
|
||
|
||
if (TREE_CODE (instance) == INDIRECT_REF
|
||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (instance, 0))) == REFERENCE_TYPE)
|
||
ref = TREE_OPERAND (instance, 0);
|
||
else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
|
||
ref = instance;
|
||
|
||
if (ref && TREE_CODE (ref) == VAR_DECL
|
||
&& DECL_INITIAL (ref))
|
||
{
|
||
tree init = DECL_INITIAL (ref);
|
||
|
||
while (TREE_CODE (init) == NOP_EXPR
|
||
|| TREE_CODE (init) == REFERENCE_EXPR)
|
||
init = TREE_OPERAND (init, 0);
|
||
if (TREE_CODE (init) == ADDR_EXPR)
|
||
{
|
||
init = TREE_OPERAND (init, 0);
|
||
if (IS_AGGR_TYPE (TREE_TYPE (init))
|
||
&& (TREE_CODE (init) == PARM_DECL
|
||
|| TREE_CODE (init) == VAR_DECL))
|
||
instance = init;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (IS_AGGR_TYPE (instance)
|
||
&& (TREE_CODE (instance) == RESULT_DECL
|
||
|| TREE_CODE (instance) == PARM_DECL
|
||
|| TREE_CODE (instance) == VAR_DECL))
|
||
vtbl = CLASS_ASSOC_VTABLE (basetype);
|
||
else
|
||
vtbl = build_indirect_ref (build_vfield_ref (instance, basetype), 0);
|
||
}
|
||
aref = build_array_ref (vtbl, index);
|
||
if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF)
|
||
TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
|
||
|
||
*ptr_to_instptr = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
|
||
*ptr_to_instptr,
|
||
convert (integer_type_node, build_component_ref (aref, delta_name, 0, 0)));
|
||
return build_component_ref (aref, pfn_name, 0, 0);
|
||
}
|
||
|
||
/* Build a virtual function for type TYPE.
|
||
If ASSOC is non-NULL, build the vtable starting with the intial
|
||
approximation that it is the same as the one which is the head of
|
||
the assocation list. */
|
||
static tree
|
||
build_vtable (assoc, type)
|
||
tree assoc, type;
|
||
{
|
||
tree name = get_vtable_name (type);
|
||
tree virtuals, decl;
|
||
|
||
if (assoc)
|
||
{
|
||
virtuals = copy_list (ASSOC_VIRTUALS (assoc));
|
||
decl = build_decl (VAR_DECL, name, TREE_TYPE (ASSOC_VTABLE (assoc)));
|
||
}
|
||
else
|
||
{
|
||
virtuals = NULL_TREE;
|
||
decl = build_decl (VAR_DECL, name, void_type_node);
|
||
}
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_vtables += 1;
|
||
n_vtable_elems += list_length (virtuals);
|
||
#endif
|
||
|
||
if (write_virtuals >= 2)
|
||
{
|
||
if (CLASSTYPE_INTERFACE_UNKNOWN (type) == 0)
|
||
{
|
||
TREE_PUBLIC (decl) = CLASSTYPE_VTABLE_NEEDS_WRITING (type);
|
||
TREE_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
|
||
}
|
||
}
|
||
else if (write_virtuals > 0)
|
||
TREE_PUBLIC (decl) = 1;
|
||
else if (write_virtuals < 0)
|
||
TREE_EXTERNAL (decl) = 1;
|
||
|
||
IDENTIFIER_GLOBAL_VALUE (name) = decl = pushdecl_top_level (decl);
|
||
/* Initialize the association list for this type, based
|
||
on our first approximation. */
|
||
CLASS_ASSOC_VTABLE (type) = decl;
|
||
CLASS_ASSOC_VIRTUALS (type) = virtuals;
|
||
|
||
TREE_STATIC (decl) = 1;
|
||
DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
|
||
DECL_ALIGN (decl));
|
||
|
||
if (assoc && write_virtuals >= 0)
|
||
DECL_VIRTUAL_P (decl) = 1;
|
||
/* Remember which class this vtable is really for. */
|
||
DECL_VPARENT (decl) = type;
|
||
DECL_CONTEXT (decl) = type;
|
||
CLASSTYPE_MARKED3 (type) = 1;
|
||
CLASSTYPE_MARKED4 (type) = 1;
|
||
return decl;
|
||
}
|
||
|
||
/* Give TYPE a new virtual function table which is initialized
|
||
with a skeleton-copy of its original initialization. The only
|
||
entry that changes is the `delta' entry, so we can really
|
||
share a lot of structure.
|
||
|
||
FOR_TYPE is the derived type which caused this table to
|
||
be needed.
|
||
|
||
ASSOC is the type association which provided TYPE for FOR_TYPE.
|
||
|
||
The way we update BASE_ASSOC's vtable information is just to change the
|
||
association information in FOR_TYPE's association list. */
|
||
static void
|
||
prepare_fresh_vtable (assoc, base_assoc, for_type)
|
||
tree assoc, base_assoc, for_type;
|
||
{
|
||
tree basetype = ASSOC_TYPE (assoc);
|
||
tree orig_decl = ASSOC_VTABLE (assoc);
|
||
tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type);
|
||
tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
|
||
tree path;
|
||
int result;
|
||
|
||
assert (TREE_USED (assoc) == 0);
|
||
|
||
/* Remember which class this vtable is really for. */
|
||
DECL_VPARENT (new_decl) = ASSOC_TYPE (base_assoc);
|
||
DECL_CONTEXT (new_decl) = for_type;
|
||
|
||
TREE_STATIC (new_decl) = 1;
|
||
ASSOC_VTABLE (assoc) = pushdecl_top_level (new_decl);
|
||
DECL_VIRTUAL_P (new_decl) = 1;
|
||
DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);
|
||
|
||
/* Make fresh virtual list, so we can smash it later. */
|
||
assert (ASSOC_VIRTUALS (assoc));
|
||
ASSOC_VIRTUALS (assoc) = copy_list (ASSOC_VIRTUALS (assoc));
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_vtables += 1;
|
||
n_vtable_elems += list_length (ASSOC_VIRTUALS (assoc));
|
||
#endif
|
||
|
||
/* Set `new_decl's PUBLIC and EXTERNAL bits. */
|
||
if (write_virtuals >= 2)
|
||
{
|
||
if (CLASSTYPE_INTERFACE_UNKNOWN (for_type) == 0)
|
||
{
|
||
TREE_PUBLIC (new_decl) = CLASSTYPE_VTABLE_NEEDS_WRITING (for_type);
|
||
TREE_EXTERNAL (new_decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (for_type);
|
||
}
|
||
}
|
||
else if (write_virtuals > 0)
|
||
TREE_PUBLIC (new_decl) = 1;
|
||
else if (write_virtuals < 0)
|
||
TREE_EXTERNAL (new_decl) = 1;
|
||
|
||
CLASSTYPE_MARKED3 (basetype) = 1;
|
||
CLASSTYPE_MARKED4 (basetype) = 1;
|
||
|
||
/* Mark all types between FOR_TYPE and TYPE as having been
|
||
touched, so that if we change virtual function table entries,
|
||
new vtables will be initialized. We may reach the virtual
|
||
baseclass via ambiguous intervening baseclasses. This
|
||
loop makes sure we get through to the actual baseclass we marked. */
|
||
|
||
do
|
||
{
|
||
result = get_base_distance (basetype, for_type, 0, &path);
|
||
for_type = TREE_VALUE (path);
|
||
while (path)
|
||
{
|
||
CLASSTYPE_MARKED3 (TREE_VALUE (path)) = 1;
|
||
path = TREE_CHAIN (path);
|
||
}
|
||
}
|
||
while (result == -2);
|
||
}
|
||
|
||
/* Access the virtual function table entry that logically
|
||
contains BASE_FNDECL. VIRTUALS is the virtual function table's
|
||
initializer. */
|
||
static tree
|
||
get_vtable_entry (virtuals, base_fndecl)
|
||
tree virtuals, base_fndecl;
|
||
{
|
||
int i = (HOST_BITS_PER_INT >= BITS_PER_WORD
|
||
#ifdef VTABLE_USES_MASK
|
||
&& 0
|
||
#endif
|
||
? (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl))
|
||
& ((1<<(BITS_PER_WORD-1))-1))
|
||
: TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)));
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_vtable_searches += i;
|
||
#endif
|
||
|
||
while (i > 0)
|
||
{
|
||
virtuals = TREE_CHAIN (virtuals);
|
||
i -= 1;
|
||
}
|
||
return virtuals;
|
||
}
|
||
|
||
/* Put new entry ENTRY into virtual function table initializer
|
||
VIRTUALS. The virtual function table is for type CONTEXT.
|
||
|
||
Also update DECL_VINDEX (FNDECL). */
|
||
|
||
static void
|
||
modify_vtable_entry (old_entry_in_list, new_entry, fndecl, context)
|
||
tree old_entry_in_list, new_entry, fndecl, context;
|
||
{
|
||
tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list));
|
||
tree vindex;
|
||
|
||
/* We can't put in the really right offset information
|
||
here, since we have not yet laid out the class to
|
||
take into account virtual base classes. */
|
||
TREE_VALUE (old_entry_in_list) = new_entry;
|
||
vindex = DECL_VINDEX (TREE_OPERAND (base_pfn, 0));
|
||
if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
|
||
SET_DECL_VINDEX (fndecl, vindex);
|
||
else
|
||
{
|
||
if (! tree_int_cst_equal (DECL_VINDEX (fndecl), vindex))
|
||
{
|
||
tree elts = CONSTRUCTOR_ELTS (new_entry);
|
||
tree vfield = CLASSTYPE_VFIELD (context);
|
||
/* Compute the relative offset of vtable we are really looking for. */
|
||
TREE_VALUE (elts) = genop (PLUS_EXPR,
|
||
build_int (DECL_OFFSET (vfield)
|
||
/ DECL_SIZE_UNIT (vfield)),
|
||
TREE_VALUE (elts));
|
||
/* Say what index to use when we use that vtable. */
|
||
#ifndef VTABLE_USES_MASK
|
||
vindex = build_int_2 (TREE_INT_CST_LOW (vindex) & ~(1 << (BITS_PER_WORD -1)), 0);
|
||
#endif
|
||
TREE_VALUE (TREE_CHAIN (elts)) = vindex;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Modify virtual function tables in lattice topped by T to
|
||
place FNDECL in tables which previously held BASE_FNDECL.
|
||
PFN is just FNDECL wrapped in an ADDR_EXPR, so that it
|
||
is suitable for placement directly into an initializer.
|
||
|
||
All distinct virtual function tables that this type uses
|
||
must be updated. */
|
||
static void
|
||
modify_vtable_entries (t, fndecl, base_fndecl, pfn)
|
||
tree t;
|
||
tree fndecl, base_fndecl, pfn;
|
||
{
|
||
tree base_offset, offset;
|
||
tree context = DECL_CONTEXT (base_fndecl);
|
||
tree vfield = CLASSTYPE_VFIELD (t);
|
||
tree vfields, vbases;
|
||
|
||
DECL_VCONTEXT (fndecl) = DECL_VCONTEXT (base_fndecl);
|
||
|
||
if (DECL_CONTEXT (fndecl) == t
|
||
|| !(TYPE_USES_VIRTUAL_BASECLASSES (t)
|
||
|| TYPE_USES_MULTIPLE_INHERITANCE (t)))
|
||
offset = integer_zero_node;
|
||
else
|
||
{
|
||
tree assoc = virtual_member (DECL_CONTEXT (fndecl), CLASSTYPE_VBASECLASSES (t));
|
||
if (assoc == NULL_TREE)
|
||
assoc = assoc_value (DECL_CONTEXT (fndecl), t);
|
||
assert (assoc != NULL_TREE);
|
||
offset = ASSOC_OFFSET (assoc);
|
||
}
|
||
|
||
/* 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). */
|
||
for (vfields = CLASSTYPE_VFIELDS (t); vfields; vfields = TREE_CHAIN (vfields))
|
||
{
|
||
int normal = 1;
|
||
tree assoc, this_offset;
|
||
tree base, path;
|
||
|
||
/* Find the right base class for this derived class, call it BASE. */
|
||
base = TREE_VALUE (vfields);
|
||
|
||
if (base != context)
|
||
{
|
||
/* If BASE_FNDECL is not contained in the vtable accessed by
|
||
the vslot, don't try to modify the vtable.
|
||
|
||
Virtual functions from virtual baseclasses are not in derived
|
||
virtual function tables. This is an implementation decision;
|
||
it keeps there from being a combinatorial exposion in the
|
||
number of different vtables which must be maintained. */
|
||
|
||
if (get_base_distance (base, context, 0, 0) == -1)
|
||
continue;
|
||
|
||
/* BASE_FNDECL is defined in a class derived from
|
||
the base class owning this VFIELD. */
|
||
}
|
||
/* Get the path starting from the deepest base class CONTEXT
|
||
of T (i.e., first defn of BASE_FNDECL). */
|
||
get_base_distance (context, t, 0, &path);
|
||
|
||
/* Get our best approximation of what to use for constructing
|
||
the virtual function table for T. */
|
||
do
|
||
{
|
||
/* Walk from base toward derived, stopping at the
|
||
most derived baseclass that matters. */
|
||
if (TREE_VIA_VIRTUAL (path))
|
||
{
|
||
base = TREE_VALUE (path);
|
||
assoc = value_member (TYPE_MAIN_VARIANT (base), CLASSTYPE_VBASECLASSES (t));
|
||
break;
|
||
}
|
||
if (TREE_CHAIN (path) == NULL_TREE
|
||
|| (CLASSTYPE_BASECLASS (TREE_VALUE (TREE_CHAIN (path)), 1)
|
||
!= TREE_VALUE (path))
|
||
|| TREE_CHAIN (TREE_CHAIN (path)) == NULL_TREE)
|
||
{
|
||
base = TREE_VALUE (path);
|
||
assoc = assoc_value (TYPE_MAIN_VARIANT (base), t);
|
||
break;
|
||
}
|
||
path = TREE_CHAIN (path);
|
||
}
|
||
while (1);
|
||
|
||
/* Find the right offset for the this pointer based on the base
|
||
class we just found. */
|
||
base_offset = ASSOC_OFFSET (assoc);
|
||
if (base_offset == integer_zero_node)
|
||
this_offset = offset;
|
||
else
|
||
this_offset = genop (MINUS_EXPR, offset, base_offset);
|
||
|
||
/* Make sure we can modify the derived association with immunity. */
|
||
if (TREE_USED (CLASSTYPE_ASSOC (t)))
|
||
CLASSTYPE_ASSOC (t) = copy_assoc (CLASSTYPE_ASSOC (t));
|
||
|
||
/* 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 = (vfield != NULL_TREE
|
||
&& TREE_VALUE (vfields) == DECL_FCONTEXT (vfield)
|
||
&& (TREE_PURPOSE (vfields) == NULL_TREE
|
||
|| ! TREE_VIA_VIRTUAL (TREE_PURPOSE (vfields))));
|
||
|
||
if (normal && TREE_PURPOSE (vfields))
|
||
/* Everything looks normal so far...check that we are really
|
||
working from VFIELD's basetype, and not some other appearance
|
||
of that basetype in the lattice. */
|
||
normal = (TREE_PURPOSE (vfields) == get_base_type (TREE_VALUE (vfields), t, 0));
|
||
|
||
if (normal)
|
||
{
|
||
/* In this case, it is *type*'s vtable we are modifying. */
|
||
context = t;
|
||
if (! CLASSTYPE_MARKED4 (t))
|
||
build_vtable (assoc, t);
|
||
assoc = CLASSTYPE_ASSOC (t);
|
||
}
|
||
else
|
||
{
|
||
/* This is our very own copy of `basetype' to play with. */
|
||
if (! CLASSTYPE_MARKED4 (ASSOC_TYPE (assoc)))
|
||
prepare_fresh_vtable (assoc, CLASSTYPE_ASSOC (base), t);
|
||
}
|
||
|
||
modify_vtable_entry (get_vtable_entry (ASSOC_VIRTUALS (assoc), base_fndecl),
|
||
build_vtable_entry (this_offset, pfn),
|
||
fndecl, context);
|
||
}
|
||
for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases))
|
||
{
|
||
tree this_offset;
|
||
tree base, path;
|
||
|
||
if (! ASSOC_VTABLE (vbases))
|
||
/* There are only two ways that a type can fail to have
|
||
virtual functions: neither it nor any of its base
|
||
types define virtual functions (in which case
|
||
no updating need be done), or virtual functions
|
||
accessible to it come from virtual base classes
|
||
(in which case we have or will get them modified
|
||
in other passes of this loop). */
|
||
continue;
|
||
|
||
base = TREE_VALUE (vbases);
|
||
path = NULL_TREE;
|
||
|
||
if (base != context
|
||
&& get_base_distance (context, base, 0, &path) == -1)
|
||
continue;
|
||
|
||
/* Doesn't matter if not actually from this virtual base class,
|
||
but shouldn't come from deeper virtual baseclasses. The enclosing
|
||
loop should take care of such baseclasses. */
|
||
while (path)
|
||
{
|
||
if (TREE_VIA_VIRTUAL (path))
|
||
goto skip;
|
||
path = TREE_CHAIN (path);
|
||
}
|
||
|
||
base_offset = ASSOC_OFFSET (vbases);
|
||
if (base_offset == integer_zero_node)
|
||
this_offset = offset;
|
||
else
|
||
this_offset = genop (MINUS_EXPR, offset, base_offset);
|
||
|
||
/* Make sure we can modify the derived association with immunity. */
|
||
if (TREE_USED (CLASSTYPE_ASSOC (t)))
|
||
CLASSTYPE_ASSOC (t) = copy_assoc (CLASSTYPE_ASSOC (t));
|
||
|
||
/* This is our very own copy of `basetype' to play with. */
|
||
if (! CLASSTYPE_MARKED4 (ASSOC_TYPE (vbases)))
|
||
{
|
||
tree context_assoc = assoc_value (context, base);
|
||
prepare_fresh_vtable (vbases, context_assoc, t);
|
||
}
|
||
modify_vtable_entry (get_vtable_entry (ASSOC_VIRTUALS (vbases), base_fndecl),
|
||
build_vtable_entry (this_offset, pfn),
|
||
fndecl, context);
|
||
skip: {}
|
||
}
|
||
}
|
||
|
||
static tree
|
||
add_virtual_function (pending_virtuals, has_virtual, x, first)
|
||
tree pending_virtuals;
|
||
int *has_virtual;
|
||
tree x;
|
||
int first;
|
||
{
|
||
int debug_vbase = 1;
|
||
|
||
/* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely
|
||
convert to void *. Make such a conversion here. */
|
||
tree vfn = build1 (ADDR_EXPR, ptr_type_node, x);
|
||
TREE_LITERAL (vfn) = 1;
|
||
TREE_ADDRESSABLE (x) = CLASSTYPE_VTABLE_NEEDS_WRITING (current_class_type);
|
||
|
||
/* If the virtual function is a redefinition of a prior one,
|
||
figure out in which base class the new definition goes,
|
||
and if necessary, make a fresh virtual function table
|
||
to hold that entry. */
|
||
if (DECL_VINDEX (x) == NULL_TREE)
|
||
{
|
||
tree entry = build_vtable_entry (integer_zero_node, vfn);
|
||
|
||
/* Build a new INT_CST for this DECL_VINDEX. */
|
||
#ifdef VTABLE_USES_MASK
|
||
SET_DECL_VINDEX (x, build_int_2 (++(*has_virtual), 0));
|
||
#else
|
||
SET_DECL_VINDEX (x, build_int_2 (((1 << (BITS_PER_WORD - 1)) | ++(*has_virtual)), ~0));
|
||
#endif
|
||
pending_virtuals = tree_cons (DECL_VINDEX (x), entry, pending_virtuals);
|
||
}
|
||
/* Happens if declared twice in class. We will give error
|
||
later. */
|
||
else if (TREE_CODE (DECL_VINDEX (x)) == INTEGER_CST)
|
||
return pending_virtuals;
|
||
else if (debug_vbase && TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||
{
|
||
/* Need an entry in some other virtual function table.
|
||
Deal with this after we have laid out our virtual base classes. */
|
||
pending_hard_virtuals = temp_tree_cons (x, vfn, pending_hard_virtuals);
|
||
}
|
||
else
|
||
{
|
||
/* Need an entry in some other virtual function table.
|
||
We can do this now. */
|
||
tree base_fndecl_list = DECL_VINDEX (x), base_fndecls, prev = 0;
|
||
tree vtable_context = DECL_FCONTEXT (CLASSTYPE_VFIELD (current_class_type));
|
||
tree true_base_fndecl = 0;
|
||
|
||
/* First assign DECL_VINDEX from the base vfn with which
|
||
we share our vtable. */
|
||
base_fndecls = base_fndecl_list;
|
||
while (base_fndecls)
|
||
{
|
||
if (TREE_CHAIN (base_fndecls) == NULL_TREE
|
||
|| DECL_FCONTEXT (CLASSTYPE_VFIELD (DECL_CONTEXT (TREE_VALUE (base_fndecls)))) == vtable_context)
|
||
{
|
||
true_base_fndecl = TREE_VALUE (base_fndecls);
|
||
modify_vtable_entries (current_class_type, x,
|
||
true_base_fndecl, vfn);
|
||
if (prev)
|
||
TREE_CHAIN (prev) = TREE_CHAIN (base_fndecls);
|
||
else
|
||
base_fndecl_list = prev;
|
||
break;
|
||
}
|
||
prev = base_fndecls;
|
||
base_fndecls = TREE_CHAIN (base_fndecls);
|
||
}
|
||
|
||
/* Now fill in the rest of the vtables. */
|
||
base_fndecls = base_fndecl_list;
|
||
while (base_fndecls)
|
||
{
|
||
/* If we haven't found one we like, first one wins. */
|
||
if (true_base_fndecl == 0)
|
||
true_base_fndecl = TREE_VALUE (base_fndecls);
|
||
|
||
modify_vtable_entries (current_class_type, x,
|
||
TREE_VALUE (base_fndecls), vfn);
|
||
base_fndecls = TREE_CHAIN (base_fndecls);
|
||
}
|
||
|
||
DECL_VCONTEXT (x) = DECL_VCONTEXT (true_base_fndecl);
|
||
}
|
||
return pending_virtuals;
|
||
}
|
||
|
||
/* Obstack on which to build the vector of class methods. */
|
||
struct obstack class_obstack;
|
||
extern struct obstack *current_obstack;
|
||
|
||
/* Add method METHOD to class TYPE. This is used when a method
|
||
has been defined which did not initially appear in the class definition,
|
||
and helps cut down on spurious error messages.
|
||
|
||
FIELDS is the entry in the METHOD_VEC vector entry of the class type where
|
||
the method should be added. */
|
||
void
|
||
add_method (type, fields, method)
|
||
tree type, *fields, method;
|
||
{
|
||
/* We must make a copy of METHOD here, since we must be sure that
|
||
we have exclusive title to this method's TREE_CHAIN. */
|
||
int temp = allocation_temporary_p ();
|
||
tree decl;
|
||
|
||
if (temp)
|
||
end_temporary_allocation ();
|
||
{
|
||
decl = copy_node (method);
|
||
if (DECL_RTL (decl) == 0)
|
||
make_function_rtl (decl);
|
||
}
|
||
|
||
if (fields && *fields)
|
||
{
|
||
/* Take care not to hide destructor. */
|
||
TREE_CHAIN (decl) = TREE_CHAIN (*fields);
|
||
TREE_CHAIN (*fields) = decl;
|
||
}
|
||
else if (CLASSTYPE_METHOD_VEC (type) == 0)
|
||
{
|
||
tree method_vec = make_node (TREE_VEC);
|
||
if (DECL_NAME (TYPE_NAME (type)) == DECL_ORIGINAL_NAME (decl))
|
||
{
|
||
TREE_VEC_ELT (method_vec, 0) = decl;
|
||
TREE_VEC_LENGTH (method_vec) = 1;
|
||
}
|
||
else
|
||
{
|
||
obstack_free (current_obstack, method_vec);
|
||
obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *));
|
||
TREE_VEC_ELT (method_vec, 1) = decl;
|
||
TREE_VEC_LENGTH (method_vec) = 2;
|
||
obstack_finish (current_obstack);
|
||
}
|
||
CLASSTYPE_METHOD_VEC (type) = method_vec;
|
||
}
|
||
else
|
||
{
|
||
tree method_vec = CLASSTYPE_METHOD_VEC (type);
|
||
int len = TREE_VEC_LENGTH (method_vec);
|
||
|
||
/* Adding a new ctor or dtor. */
|
||
if (DECL_NAME (TYPE_NAME (type)) == DECL_ORIGINAL_NAME (decl))
|
||
TREE_VEC_ELT (method_vec, 0) = decl;
|
||
else
|
||
{
|
||
tree *end = (tree *)obstack_next_free (&class_obstack);
|
||
if (end != TREE_VEC_END (method_vec))
|
||
{
|
||
tree tmp_vec = copy_node (method_vec);
|
||
obstack_copy (current_obstack, &TREE_VEC_ELT (method_vec, 1), len);
|
||
obstack_blank (current_obstack, sizeof (tree *));
|
||
obstack_finish (current_obstack);
|
||
method_vec = tmp_vec;
|
||
}
|
||
else
|
||
{
|
||
/* We can easily extend the last such method_vec created. */
|
||
obstack_free (&class_obstack, method_vec);
|
||
obstack_blank (&class_obstack,
|
||
((char *)end - (char *)method_vec) + sizeof (tree *));
|
||
method_vec = (tree)obstack_base (&class_obstack);
|
||
obstack_finish (&class_obstack);
|
||
}
|
||
TREE_VEC_ELT (method_vec, len) = decl;
|
||
TREE_VEC_LENGTH (method_vec) = len + 1;
|
||
CLASSTYPE_METHOD_VEC (type) = method_vec;
|
||
|
||
if (CLASSTYPE_BASELINK_VEC (type))
|
||
{
|
||
/* ??? May be better to know whether these can be extended? */
|
||
tree baselink_vec = copy_node (CLASSTYPE_BASELINK_VEC (type));
|
||
|
||
obstack_copy (current_obstack, &TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), 1), len);
|
||
TREE_VEC_ELT (baselink_vec, len) = 0;
|
||
TREE_VEC_LENGTH (baselink_vec) = len + 1;
|
||
CLASSTYPE_BASELINK_VEC (type) = baselink_vec;
|
||
}
|
||
}
|
||
}
|
||
DECL_CONTEXT (decl) = type;
|
||
DECL_VCONTEXT (decl) = type;
|
||
|
||
if (temp)
|
||
resume_temporary_allocation ();
|
||
}
|
||
|
||
/* Subroutines of finish_struct. */
|
||
|
||
/* Look through the list of fields for this struct, deleting
|
||
duplicates as we go. This must be recursive to handle
|
||
anonymous unions.
|
||
|
||
FIELD is the field which may not appear anywhere in FIELDS.
|
||
FIELD_PTR, if non-null, is the starting point at which
|
||
chained deletions may take place.
|
||
The value returned is the first acceptable entry found
|
||
in FIELDS.
|
||
|
||
Note that anonymous fields which are not of UNION_TYPE are
|
||
not duplicates, they are just anonymous fields. This happens
|
||
when we have unnamed bitfields, for example. */
|
||
static tree
|
||
delete_duplicate_fields_1 (field, field_ptr, fields)
|
||
tree field, *field_ptr, fields;
|
||
{
|
||
tree x;
|
||
tree prev = field_ptr ? *field_ptr : 0;
|
||
if (DECL_NAME (field) == 0)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)
|
||
return fields;
|
||
|
||
for (x = TYPE_FIELDS (TREE_TYPE (field)); x; x = TREE_CHAIN (x))
|
||
fields = delete_duplicate_fields_1 (x, field_ptr, fields);
|
||
if (prev)
|
||
TREE_CHAIN (prev) = fields;
|
||
return fields;
|
||
}
|
||
else
|
||
{
|
||
for (x = fields; x; prev = x, x = TREE_CHAIN (x))
|
||
{
|
||
if (DECL_NAME (x) == 0)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (x)) != UNION_TYPE)
|
||
continue;
|
||
TYPE_FIELDS (TREE_TYPE (x))
|
||
= delete_duplicate_fields_1 (field, 0, TYPE_FIELDS (TREE_TYPE (x)));
|
||
if (TYPE_FIELDS (TREE_TYPE (x)) == 0)
|
||
{
|
||
if (prev == 0)
|
||
fields = TREE_CHAIN (fields);
|
||
else
|
||
TREE_CHAIN (prev) = TREE_CHAIN (x);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (DECL_NAME (field) == DECL_NAME (x))
|
||
{
|
||
if (TREE_CODE (field) == CONST_DECL
|
||
&& TREE_CODE (x) == CONST_DECL)
|
||
error_with_decl (x, "duplicate enum value `%s'");
|
||
else if (TREE_CODE (field) == CONST_DECL
|
||
|| TREE_CODE (x) == CONST_DECL)
|
||
error_with_decl (x, "duplicate field `%s' (as enum and non-enum)");
|
||
else
|
||
error_with_decl (x, "duplicate member `%s'");
|
||
if (prev == 0)
|
||
fields = TREE_CHAIN (fields);
|
||
else
|
||
TREE_CHAIN (prev) = TREE_CHAIN (x);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return fields;
|
||
}
|
||
|
||
static void
|
||
delete_duplicate_fields (fields)
|
||
tree fields;
|
||
{
|
||
tree x;
|
||
for (x = fields; x && TREE_CHAIN (x); x = TREE_CHAIN (x))
|
||
TREE_CHAIN (x) = delete_duplicate_fields_1 (x, &x, TREE_CHAIN (x));
|
||
}
|
||
|
||
/* Add OFFSET to all child types of T.
|
||
|
||
OFFSET, which is a type offset, is number of bytes.
|
||
|
||
Note that we don't have to worry about having two paths to the
|
||
same base type, since this type owns its association list. */
|
||
static void
|
||
propagate_basetype_offsets (for_type, t, offset)
|
||
tree for_type, t;
|
||
tree offset;
|
||
{
|
||
int i, n_baselinks = CLASSTYPE_N_BASECLASSES (t);
|
||
|
||
for (i = 1; i <= n_baselinks; i++)
|
||
if (! CLASSTYPE_VIA_VIRTUAL (t, i))
|
||
{
|
||
int j;
|
||
tree basetype = CLASSTYPE_BASECLASS (t, i);
|
||
tree assoc = assoc_value (TYPE_MAIN_VARIANT (basetype), for_type);
|
||
tree delta;
|
||
|
||
for (j = i+1; j <= n_baselinks; j++)
|
||
if (! CLASSTYPE_VIA_VIRTUAL (t, j))
|
||
{
|
||
/* The next basetype offset must take into account the space
|
||
between the classes, not just the size of each class. */
|
||
delta = genop (MINUS_EXPR,
|
||
CLASSTYPE_OFFSET (CLASSTYPE_BASECLASS (t, j)),
|
||
CLASSTYPE_OFFSET (basetype));
|
||
break;
|
||
}
|
||
|
||
if (CLASSTYPE_OFFSET (basetype) == integer_zero_node)
|
||
basetype = build_classtype_variant (basetype, offset, 0);
|
||
else
|
||
basetype = build_classtype_variant (basetype,
|
||
genop (PLUS_EXPR, CLASSTYPE_OFFSET (basetype), offset), 0);
|
||
/* Now make our own copy of this base type we can munge. */
|
||
basetype = copy_node (basetype);
|
||
copy_type_lang_specific (basetype);
|
||
|
||
CLASSTYPE_BASECLASS (t, i) = basetype;
|
||
ASSOC_TYPE (assoc) = basetype;
|
||
ASSOC_OFFSET (assoc) = CLASSTYPE_OFFSET (basetype);
|
||
TYPE_NAME (basetype) = copy_node (TYPE_NAME (basetype));
|
||
TREE_TYPE (TYPE_NAME (basetype)) = basetype;
|
||
DECL_OFFSET (TYPE_NAME (basetype))
|
||
= TREE_INT_CST_LOW (CLASSTYPE_OFFSET (basetype)) * BITS_PER_UNIT;
|
||
propagate_basetype_offsets (for_type, basetype, offset);
|
||
|
||
/* Go to our next class that counts for offset propagation. */
|
||
i = j;
|
||
if (i <= n_baselinks)
|
||
offset = genop (PLUS_EXPR, offset, delta);
|
||
}
|
||
}
|
||
|
||
/* Change the visibility of T::FDECL to VISIBILITY.
|
||
Return 1 if change was legit, otherwise return 0. */
|
||
static int
|
||
alter_visibility (t, fdecl, visibility)
|
||
tree t;
|
||
tree fdecl;
|
||
enum visibility_type visibility;
|
||
{
|
||
tree elem = purpose_member (t, DECL_VISIBILITY (fdecl));
|
||
if (elem && TREE_VALUE (elem) != (tree)visibility)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
|
||
{
|
||
error_with_decl (TREE_TYPE (fdecl), "conflicting visibility specifications for method `%s', ignored");
|
||
}
|
||
else error ("conflicting visibility specifications for field `%s', ignored", IDENTIFIER_POINTER (DECL_NAME (fdecl)));
|
||
}
|
||
else if (TREE_PRIVATE (fdecl) && visibility != visibility_private)
|
||
error_with_decl (fdecl, "cannot make private %s non-private");
|
||
else if (TREE_PROTECTED (fdecl) && visibility == visibility_public)
|
||
|
||
error_with_decl (fdecl, "cannot make protected %s public");
|
||
else if (elem == NULL_TREE)
|
||
{
|
||
DECL_VISIBILITY (fdecl) = tree_cons (t, (tree)visibility,
|
||
DECL_VISIBILITY (fdecl));
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* If FOR_TYPE needs to reinitialize virtual function table pointers
|
||
for TYPE's sub-objects, add such reinitializations to BASE_INIT_LIST.
|
||
Returns BASE_INIT_LIST appropriately modified. */
|
||
|
||
static tree
|
||
maybe_fixup_vptrs (for_type, type, base_init_list)
|
||
tree for_type, type, base_init_list;
|
||
{
|
||
/* Now reinitialize any slots that don't fall under our virtual
|
||
function table pointer. */
|
||
tree vfields = CLASSTYPE_VFIELDS (type);
|
||
while (vfields)
|
||
{
|
||
tree basetype = get_base_type (TREE_VALUE (vfields), for_type, 0);
|
||
if (CLASSTYPE_NEEDS_VIRTUAL_REINIT (basetype)
|
||
&& ((DECL_OFFSET (CLASSTYPE_VFIELD (basetype))
|
||
+ DECL_OFFSET (TYPE_NAME (basetype)))
|
||
!= DECL_OFFSET (CLASSTYPE_VFIELD (for_type)))
|
||
&& ((DECL_OFFSET (CLASSTYPE_VFIELD (basetype))
|
||
+ DECL_OFFSET (TYPE_NAME (basetype)))
|
||
!= (DECL_OFFSET (CLASSTYPE_VFIELD (type))
|
||
+ DECL_OFFSET (TYPE_NAME (type)))))
|
||
base_init_list = tree_cons (error_mark_node, basetype,
|
||
base_init_list);
|
||
vfields = TREE_CHAIN (vfields);
|
||
}
|
||
return base_init_list;
|
||
}
|
||
|
||
/* If TYPE does not have a constructor, then the compiler must
|
||
manually deal with all of the initialization this type requires.
|
||
|
||
If a base initializer exists only to fill in the virtual function
|
||
table pointer, then we mark that fact with the TREE_VIRTUAL bit.
|
||
This way, we avoid multiple initializations of the same field by
|
||
each virtual function table up the class hierarchy.
|
||
|
||
Virtual base class pointers are not initialized here. They are
|
||
initialized only at the "top level" of object creation. If we
|
||
initialized them here, we would have to skip a lot of work. */
|
||
|
||
static void
|
||
build_class_init_list (type)
|
||
tree type;
|
||
{
|
||
tree base_init_list = NULL_TREE;
|
||
tree member_init_list = NULL_TREE;
|
||
|
||
/* Since we build member_init_list and base_init_list using
|
||
tree_cons, backwards fields the all through work. */
|
||
tree x;
|
||
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
|
||
|
||
for (x = TYPE_FIELDS (type); x; x = TREE_CHAIN (x))
|
||
{
|
||
if (TREE_CODE (x) != FIELD_DECL)
|
||
continue;
|
||
|
||
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (x))
|
||
|| DECL_INITIAL (x) != NULL_TREE)
|
||
member_init_list = tree_cons (x, type, member_init_list);
|
||
}
|
||
member_init_list = nreverse (member_init_list);
|
||
|
||
/* We will end up doing this last. Need special marker
|
||
to avoid infinite regress. */
|
||
if (TYPE_VIRTUAL_P (type))
|
||
{
|
||
base_init_list = build_tree_list (error_mark_node, type);
|
||
if (CLASSTYPE_NEEDS_VIRTUAL_REINIT (type) == 0)
|
||
TREE_VALUE (base_init_list) = NULL_TREE;
|
||
TREE_ADDRESSABLE (base_init_list) = 1;
|
||
}
|
||
|
||
/* Each base class which needs to have initialization
|
||
of some kind gets to make such requests known here. */
|
||
for (i = n_baseclasses; i > 0; i--)
|
||
{
|
||
tree basetype = CLASSTYPE_BASECLASS (type, i);
|
||
tree blist;
|
||
|
||
/* Don't initialize virtual baseclasses this way. */
|
||
if (TREE_VIA_VIRTUAL (basetype))
|
||
continue;
|
||
|
||
if (TYPE_HAS_CONSTRUCTOR (basetype))
|
||
{
|
||
/* ...and the last shall come first... */
|
||
base_init_list = maybe_fixup_vptrs (type, basetype, base_init_list);
|
||
base_init_list = tree_cons (NULL_TREE, basetype,
|
||
base_init_list);
|
||
continue;
|
||
}
|
||
|
||
if ((blist = CLASSTYPE_BASE_INIT_LIST (basetype)) == NULL_TREE)
|
||
/* Nothing to initialize. */
|
||
continue;
|
||
|
||
/* ...ditto... */
|
||
base_init_list = maybe_fixup_vptrs (type, basetype, base_init_list);
|
||
|
||
/* This is normally true for single inheritance.
|
||
The win is we can shrink the chain of initializations
|
||
to be done by only converting to the actual type
|
||
we are interested in. */
|
||
if (TREE_VALUE (blist)
|
||
&& TREE_CODE (TREE_VALUE (blist)) == RECORD_TYPE
|
||
&& (DECL_OFFSET (TYPE_NAME (basetype))
|
||
== DECL_OFFSET (TYPE_NAME (TREE_VALUE (blist)))))
|
||
{
|
||
if (base_init_list)
|
||
{
|
||
/* Does it do more than just fill in a
|
||
virtual function table pointer? */
|
||
if (! TREE_ADDRESSABLE (blist))
|
||
base_init_list = build_tree_list (blist, base_init_list);
|
||
/* Can we get by just with the virtual function table
|
||
pointer that it fills in? */
|
||
else if (TREE_ADDRESSABLE (base_init_list)
|
||
&& TREE_VALUE (base_init_list) == 0)
|
||
base_init_list = blist;
|
||
/* Maybe, but it is not obvious as the previous case. */
|
||
else if (! CLASSTYPE_NEEDS_VIRTUAL_REINIT (type))
|
||
{
|
||
tree last = tree_last (base_init_list);
|
||
while (TREE_VALUE (last)
|
||
&& TREE_CODE (TREE_VALUE (last)) == TREE_LIST)
|
||
last = tree_last (TREE_VALUE (last));
|
||
if (TREE_VALUE (last) == 0)
|
||
base_init_list = build_tree_list (blist, base_init_list);
|
||
}
|
||
}
|
||
else
|
||
base_init_list = blist;
|
||
}
|
||
else
|
||
{
|
||
/* The function expand_aggr_init knows how to do the
|
||
initialization of `basetype' without getting
|
||
an explicit `blist'. */
|
||
if (base_init_list)
|
||
base_init_list = tree_cons (NULL_TREE, basetype, base_init_list);
|
||
else
|
||
base_init_list = CLASSTYPE_AS_LIST (basetype);
|
||
}
|
||
}
|
||
|
||
if (base_init_list)
|
||
if (member_init_list)
|
||
CLASSTYPE_BASE_INIT_LIST (type) = build_tree_list (base_init_list, member_init_list);
|
||
else
|
||
CLASSTYPE_BASE_INIT_LIST (type) = base_init_list;
|
||
else if (member_init_list)
|
||
CLASSTYPE_BASE_INIT_LIST (type) = member_init_list;
|
||
}
|
||
|
||
struct base_info
|
||
{
|
||
int has_virtual;
|
||
int max_has_virtual;
|
||
int n_ancestors;
|
||
tree vfield;
|
||
tree vfields;
|
||
char needs_default_ctor;
|
||
char cant_have_default_ctor;
|
||
char needs_const_ctor;
|
||
char cant_have_const_ctor;
|
||
};
|
||
|
||
/* Record information about type T derived from its base classes.
|
||
Store most of that information in T itself, and place the
|
||
remaining information in the struct BASE_INFO.
|
||
|
||
Returns the index of the first base class to have virtual functions,
|
||
or zero if no such base class. */
|
||
|
||
static int
|
||
finish_base_struct (t, b)
|
||
tree t;
|
||
struct base_info *b;
|
||
{
|
||
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
|
||
int first_vfn_base_index = 0;
|
||
|
||
bzero (b, sizeof (struct base_info));
|
||
|
||
for (i = 1; i <= n_baseclasses; i++)
|
||
{
|
||
tree basetype = CLASSTYPE_BASECLASS (t, i);
|
||
|
||
/* If the type of basetype is incomplete, then
|
||
we already complained about that fact
|
||
(and we should have fixed it up as well). */
|
||
if (TYPE_SIZE (basetype) == 0)
|
||
{
|
||
int j;
|
||
/* The base type is of incomplete type. It is
|
||
probably best to pretend that it does not
|
||
exist. */
|
||
if (i == n_baseclasses)
|
||
CLASSTYPE_BASECLASS (t, i) = NULL_TREE;
|
||
CLASSTYPE_N_BASECLASSES (t) -= 1;
|
||
n_baseclasses -= 1;
|
||
for (j = i; j < n_baseclasses; j++)
|
||
{
|
||
CLASSTYPE_BASECLASS (t, j) = CLASSTYPE_BASECLASS (t, j+1);
|
||
SET_CLASSTYPE_VIAS (t, j,
|
||
CLASSTYPE_VIA_PUBLIC (t, j+1),
|
||
CLASSTYPE_VIA_VIRTUAL (t, j+1));
|
||
}
|
||
}
|
||
|
||
if (TYPE_WRAP_TYPE (t) == NULL_TREE)
|
||
TYPE_WRAP_TYPE (t) = TYPE_WRAP_TYPE (basetype);
|
||
else if (TYPE_WRAP_TYPE (basetype)
|
||
&& TYPE_WRAP_TYPE (t) != TYPE_WRAP_TYPE (basetype))
|
||
/* Must have its own. */
|
||
TYPE_WRAP_TYPE (t) = error_mark_node;
|
||
|
||
if (TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype))
|
||
b->needs_default_ctor = 1;
|
||
else if (TYPE_HAS_CONSTRUCTOR (basetype))
|
||
b->cant_have_default_ctor = 1;
|
||
if (TYPE_GETS_CONST_INIT_REF (basetype))
|
||
b->needs_const_ctor = 1;
|
||
else if (TYPE_GETS_INIT_REF (basetype))
|
||
b->cant_have_const_ctor = 1;
|
||
|
||
CLASSTYPE_ALTERS_VISIBILITIES_P (t)
|
||
|= CLASSTYPE_ALTERS_VISIBILITIES_P (basetype);
|
||
|
||
b->n_ancestors += CLASSTYPE_N_SUPERCLASSES (basetype);
|
||
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
|
||
TYPE_NEEDS_CONSTRUCTOR (t) |= TYPE_NEEDS_CONSTRUCTOR (basetype);
|
||
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (basetype);
|
||
TYPE_ANY_ASSIGNS_THIS (t) |= TYPE_ANY_ASSIGNS_THIS (basetype);
|
||
TYPE_GETS_ASSIGNMENT (t) |= TYPE_GETS_ASSIGNMENT (basetype);
|
||
TYPE_GETS_INIT_REF (t) |= TYPE_GETS_INIT_REF (basetype);
|
||
|
||
TYPE_OVERLOADS_CALL_EXPR (t) |= TYPE_OVERLOADS_CALL_EXPR (basetype);
|
||
TYPE_OVERLOADS_ARRAY_REF (t) |= TYPE_OVERLOADS_ARRAY_REF (basetype);
|
||
|
||
if (CLASSTYPE_OFFSET (basetype) != integer_zero_node)
|
||
{
|
||
/* Completely unshare potentially shared data, and
|
||
update what is ours. */
|
||
tree assoc = assoc_value (TYPE_MAIN_VARIANT (basetype), t);
|
||
basetype = copy_node (basetype);
|
||
copy_type_lang_specific (basetype);
|
||
CLASSTYPE_BASECLASS (t, i) = basetype;
|
||
ASSOC_TYPE (assoc) = basetype;
|
||
|
||
/* Propagate this offset through all the children. Do this
|
||
before uniquizing baseclasses for virtual functions. */
|
||
CLASSTYPE_ASSOC (basetype) = copy_assoc (CLASSTYPE_ASSOC (TYPE_MAIN_VARIANT (basetype)));
|
||
|
||
propagate_basetype_offsets (basetype, basetype, CLASSTYPE_OFFSET (basetype));
|
||
}
|
||
|
||
if (! CLASSTYPE_VIA_VIRTUAL (t, i))
|
||
CLASSTYPE_N_SUPERCLASSES (t) += 1;
|
||
|
||
if (TYPE_VIRTUAL_P (basetype))
|
||
{
|
||
if (CLASSTYPE_VSIZE (basetype) > b->max_has_virtual)
|
||
b->max_has_virtual = CLASSTYPE_VSIZE (basetype);
|
||
|
||
/* Don't borrow virtuals from virtual baseclasses. */
|
||
if (TREE_VIA_VIRTUAL (basetype))
|
||
continue;
|
||
|
||
if (first_vfn_base_index == 0)
|
||
{
|
||
first_vfn_base_index = i;
|
||
|
||
b->has_virtual = CLASSTYPE_VSIZE (basetype);
|
||
b->vfield = CLASSTYPE_VFIELD (basetype);
|
||
b->vfields = CLASSTYPE_VFIELDS (basetype);
|
||
CLASSTYPE_VFIELD (t) = b->vfield;
|
||
}
|
||
else
|
||
{
|
||
/* Only add unique vfields, and flatten them out as we go. */
|
||
tree vfields = CLASSTYPE_VFIELDS (basetype);
|
||
while (vfields)
|
||
{
|
||
if (TREE_PURPOSE (vfields) == NULL_TREE
|
||
|| ! TREE_VIA_VIRTUAL (TREE_PURPOSE (vfields)))
|
||
{
|
||
tree value = TREE_VALUE (vfields);
|
||
if (TYPE_MAIN_VARIANT (basetype) == value)
|
||
b->vfields = tree_cons (basetype, value, b->vfields);
|
||
else
|
||
b->vfields = tree_cons (get_base_type (value, basetype, 0),
|
||
value, b->vfields);
|
||
TREE_TYPE (b->vfields) = basetype;
|
||
}
|
||
vfields = TREE_CHAIN (vfields);
|
||
}
|
||
|
||
if (b->has_virtual == 0)
|
||
{
|
||
first_vfn_base_index = i;
|
||
b->has_virtual = CLASSTYPE_VSIZE (basetype);
|
||
b->vfield = CLASSTYPE_VFIELD (basetype);
|
||
CLASSTYPE_VFIELD (t) = b->vfield;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (b->vfield == 0)
|
||
/* If all virtual functions come only from virtual baseclasses. */
|
||
return 0;
|
||
return first_vfn_base_index;
|
||
}
|
||
|
||
static int
|
||
typecode_p (type, code)
|
||
tree type;
|
||
enum tree_code code;
|
||
{
|
||
return (TREE_CODE (type) == code
|
||
|| (TREE_CODE (type) == REFERENCE_TYPE
|
||
&& TREE_CODE (TREE_TYPE (type)) == code));
|
||
}
|
||
|
||
/* Set memoizing fields and bits of T (and its variants) for later use.
|
||
FIRST_VFN_BASE_INDEX is the first baseclass of T with virtual functions.
|
||
MAX_HAS_VIRTUAL is the largest size of any T's virtual function tables. */
|
||
static void
|
||
finish_struct_bits (t, first_vfn_base_index, max_has_virtual)
|
||
tree t;
|
||
int first_vfn_base_index, max_has_virtual;
|
||
{
|
||
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
|
||
tree method_vec = CLASSTYPE_METHOD_VEC (t);
|
||
|
||
/* Fix up variants (if any). */
|
||
tree variants = TYPE_NEXT_VARIANT (t);
|
||
while (variants)
|
||
{
|
||
TYPE_NEEDS_CONSTRUCTOR (variants) = TYPE_NEEDS_CONSTRUCTOR (t);
|
||
TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
|
||
TYPE_NEEDS_DESTRUCTOR (variants) = TYPE_NEEDS_DESTRUCTOR (t);
|
||
variants = TYPE_NEXT_VARIANT (variants);
|
||
}
|
||
|
||
if (n_baseclasses && max_has_virtual)
|
||
{
|
||
/* Done by `finish_struct' for classes without baseclasses. */
|
||
int has_abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (t) != 0;
|
||
if (has_abstract_virtuals == 0)
|
||
for (i = CLASSTYPE_N_BASECLASSES (t); i >= 1; i--)
|
||
has_abstract_virtuals
|
||
|= (CLASSTYPE_ABSTRACT_VIRTUALS (CLASSTYPE_BASECLASS (t, i)) != 0);
|
||
if (has_abstract_virtuals)
|
||
CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
|
||
}
|
||
|
||
if (n_baseclasses)
|
||
{
|
||
/* Notice whether this class has type conversion functions defined.
|
||
Also report whether joining two types yields an ambiguity in the
|
||
virtual function table, e.g.,
|
||
|
||
struct A { virtual int f (); };
|
||
struct B { virtual int f (); };
|
||
struct C : A, B { / * no f (); * / }; / / error, ambiguous
|
||
*/
|
||
tree basetypes = CLASSTYPE_VBASECLASSES (t), basetype;
|
||
int n_vbases = list_length (basetypes), j;
|
||
|
||
build_mi_virtuals (n_baseclasses + (n_vbases*n_baseclasses), max_has_virtual);
|
||
/* Fill in virutal function table with values which do not come
|
||
"normal"ly, i.e., those which come from virtual and/or
|
||
non-leftmost base classes. */
|
||
for (i = n_baseclasses; basetypes; basetypes = TREE_CHAIN (basetypes))
|
||
{
|
||
basetype = TREE_VALUE (basetypes);
|
||
if (CLASSTYPE_VSIZE (basetype))
|
||
for (j = n_baseclasses; j > 0; j--)
|
||
{
|
||
tree this_base = CLASSTYPE_BASECLASS (t, j);
|
||
if (get_base_distance (basetype, TYPE_MAIN_VARIANT (this_base), 0, 0) != -1)
|
||
add_mi_virtuals (++i, TREE_CHAIN (ASSOC_VIRTUALS (basetypes)));
|
||
}
|
||
}
|
||
for (i = n_baseclasses; i > 0; i--)
|
||
{
|
||
basetype = CLASSTYPE_BASECLASS (t, i);
|
||
|
||
if (TYPE_HAS_CONVERSION (basetype))
|
||
{
|
||
TYPE_HAS_CONVERSION (t) = 1;
|
||
TYPE_HAS_INT_CONVERSION (t) |= TYPE_HAS_INT_CONVERSION (basetype);
|
||
TYPE_HAS_REAL_CONVERSION (t) |= TYPE_HAS_REAL_CONVERSION (basetype);
|
||
}
|
||
if (TREE_VIA_VIRTUAL (basetype))
|
||
/* Virtual functions from virtual baseclasses are done above. */;
|
||
else if (i == first_vfn_base_index)
|
||
add_mi_virtuals (i, TREE_CHAIN (CLASS_ASSOC_VIRTUALS (t)));
|
||
else if (CLASSTYPE_VSIZE (basetype) != 0)
|
||
add_mi_virtuals (i, TREE_CHAIN (CLASS_ASSOC_VIRTUALS (basetype)));
|
||
}
|
||
report_ambiguous_mi_virtuals (n_baseclasses + (n_vbases*n_baseclasses), t);
|
||
#if 0
|
||
/* Now that we know what the virtual functiond table looks like,
|
||
fix up offsets in the presence of virtual base classes. */
|
||
if (n_vbases)
|
||
fixup_vbase_offsets (t);
|
||
#endif
|
||
}
|
||
|
||
/* Need to test METHOD_VEC here in case all methods
|
||
(conversions and otherwise) are inherited. */
|
||
if (TYPE_HAS_CONVERSION (t) && method_vec != NULL_TREE)
|
||
{
|
||
tree first_conversions[last_conversion_type];
|
||
tree last_conversions[last_conversion_type];
|
||
enum conversion_type conv_index;
|
||
tree *tmp;
|
||
int i;
|
||
|
||
bzero (first_conversions, sizeof (first_conversions));
|
||
for (tmp = &TREE_VEC_ELT (method_vec, 1);
|
||
tmp != TREE_VEC_END (method_vec); tmp += 1)
|
||
{
|
||
if (OPERATOR_TYPENAME_P (DECL_ORIGINAL_NAME (*tmp)))
|
||
{
|
||
tree fntype = TREE_TYPE (*tmp);
|
||
tree return_type = TREE_TYPE (fntype);
|
||
assert (TREE_CODE (fntype) == METHOD_TYPE);
|
||
|
||
if (typecode_p (return_type, POINTER_TYPE))
|
||
{
|
||
if (TREE_READONLY (TREE_TYPE (return_type)))
|
||
conv_index = constptr_conv;
|
||
else
|
||
conv_index = ptr_conv;
|
||
}
|
||
else if (typecode_p (return_type, INTEGER_TYPE))
|
||
{
|
||
TYPE_HAS_INT_CONVERSION (t) = 1;
|
||
conv_index = int_conv;
|
||
}
|
||
else if (typecode_p (return_type, REAL_TYPE))
|
||
{
|
||
TYPE_HAS_REAL_CONVERSION (t) = 1;
|
||
conv_index = real_conv;
|
||
}
|
||
else
|
||
continue;
|
||
|
||
if (first_conversions[(int) conv_index] == NULL_TREE)
|
||
first_conversions[(int) conv_index] = *tmp;
|
||
last_conversions[(int) conv_index] = *tmp;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < (int) last_conversion_type; i++)
|
||
if (first_conversions[i] != last_conversions[i])
|
||
CLASSTYPE_CONVERSION (t, i) = error_mark_node;
|
||
else
|
||
CLASSTYPE_CONVERSION (t, i) = first_conversions[i];
|
||
}
|
||
|
||
/* If this type has constructors, force its mode to be BLKmode,
|
||
and force its TREE_ADDRESSABLE bit to be nonzero. */
|
||
if (TYPE_NEEDS_CONSTRUCTING (t) || TYPE_NEEDS_DESTRUCTOR (t))
|
||
{
|
||
tree variants = t;
|
||
|
||
if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
|
||
DECL_MODE (TYPE_NAME (t)) = BLKmode;
|
||
while (variants)
|
||
{
|
||
TYPE_MODE (variants) = BLKmode;
|
||
TREE_ADDRESSABLE (variants) = 1;
|
||
variants = TYPE_NEXT_VARIANT (variants);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
|
||
(or C++ class declaration).
|
||
|
||
For C++, we must handle the building of derived classes.
|
||
Also, C++ allows static class members. The way that this is
|
||
handled is to keep the field name where it is (as the DECL_NAME
|
||
of the field), and place the overloaded decl in the DECL_OFFSET
|
||
of the field. layout_record and layout_union will know about this.
|
||
|
||
More C++ hair: inline functions have text in their
|
||
DECL_PENDING_INLINE_INFO nodes which must somehow be parsed into
|
||
meaningful tree structure. After the struct has been laid out, set
|
||
things up so that this can happen.
|
||
|
||
And still more: virtual functions. In the case of single inheritance,
|
||
when a new virtual function is seen which redefines a virtual function
|
||
from the base class, the new virtual function is placed into
|
||
the virtual function table at exactly the same address that
|
||
it had in the base class. When this is extended to multiple
|
||
inheritance, the same thing happens, except that multiple virtual
|
||
function tables must be maintained. The first virtual function
|
||
table is treated in exactly the same way as in the case of single
|
||
inheritance. Additional virtual function tables have different
|
||
DELTAs, which tell how to adjust `this' to point to the right thing.
|
||
|
||
LIST_OF_FIELDLISTS is just that. The elements of the list are
|
||
TREE_LIST elements, whose TREE_PURPOSE field tells what visibility
|
||
the list has, and the TREE_VALUE slot gives the actual fields.
|
||
|
||
EMPTY is non-zero if this structure has no declarations following it.
|
||
|
||
If flag_all_virtual == 1, then we lay all functions into
|
||
the virtual function table, as though they were declared
|
||
virtual. Constructors do not lay down in the virtual function table.
|
||
|
||
If flag_all_virtual == 2, then we lay all functions into
|
||
the virtual function table, such that virtual functions
|
||
occupy a space by themselves, and then all functions
|
||
of the class occupy a space by themselves. This is illustrated
|
||
in the following diagram:
|
||
|
||
class A; class B : A;
|
||
|
||
Class A's vtbl: Class B's vtbl:
|
||
--------------------------------------------------------------------
|
||
| A's virtual functions| | B's virtual funcitions |
|
||
| | | (may inherit some from A). |
|
||
--------------------------------------------------------------------
|
||
| All of A's functions | | All of A's functions |
|
||
| (such as a->A::f). | | (such as b->A::f) |
|
||
--------------------------------------------------------------------
|
||
| B's new virtual functions |
|
||
| (not defined in A.) |
|
||
-------------------------------
|
||
| All of B's functions |
|
||
| (such as b->B::f) |
|
||
-------------------------------
|
||
|
||
this allows the program to make references to any function, virtual
|
||
or otherwise in a type-consistant manner. */
|
||
|
||
tree
|
||
finish_struct (t, list_of_fieldlists, empty, warn_anon)
|
||
tree t;
|
||
tree list_of_fieldlists;
|
||
int empty;
|
||
int warn_anon;
|
||
{
|
||
extern int interface_only, interface_unknown;
|
||
int old;
|
||
int round_up_size = 1;
|
||
/* Set non-zero to debug using default functions.
|
||
Not set by program. */
|
||
static int debug_default_functions = 0;
|
||
|
||
enum tree_code code = TREE_CODE (t);
|
||
register tree x, y, method_vec;
|
||
int needs_ctor = 0, needs_dtor = 0;
|
||
int members_need_dtors = 0;
|
||
tree name = TYPE_NAME (t), fields, fn_fields, tail;
|
||
enum visibility_type visibility;
|
||
int all_virtual;
|
||
int has_virtual;
|
||
int max_has_virtual;
|
||
tree pending_virtuals = NULL_TREE;
|
||
tree abstract_virtuals = NULL_TREE;
|
||
tree vfield;
|
||
tree vfields;
|
||
int needs_default_ctor;
|
||
int cant_have_default_ctor;
|
||
int needs_const_ctor;
|
||
int cant_have_const_ctor;
|
||
|
||
/* The index of the first base class which has virtual
|
||
functions. Only applied to non-virtual baseclasses. */
|
||
int first_vfn_base_index;
|
||
|
||
int i, n_baseclasses;
|
||
int any_default_members = 0;
|
||
char *err_name;
|
||
int const_sans_init = 0;
|
||
int ref_sans_init = 0;
|
||
int nonprivate_method = 0;
|
||
|
||
if (TREE_CODE (name) == TYPE_DECL)
|
||
{
|
||
extern int lineno;
|
||
|
||
DECL_SOURCE_FILE (name) = input_filename;
|
||
DECL_SOURCE_LINE (name) = lineno;
|
||
name = DECL_NAME (name);
|
||
}
|
||
err_name = IDENTIFIER_POINTER (name);
|
||
|
||
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (name))
|
||
{
|
||
warning ("un-usable class ignored (anonymous classes and unions are useless)");
|
||
err_name = "(anon)";
|
||
}
|
||
|
||
leftmost_baseclasses = NULL_TREE;
|
||
if (TYPE_SIZE (t))
|
||
{
|
||
if (TREE_CODE (t) == UNION_TYPE)
|
||
error ("redefinition of `union %s'", err_name);
|
||
else if (TREE_CODE (t) == RECORD_TYPE)
|
||
error ("redefinition of `struct %s'", err_name);
|
||
else
|
||
assert (0);
|
||
popclass (0);
|
||
return t;
|
||
}
|
||
|
||
#ifdef FIELD_XREF
|
||
FIELD_xref_decl(current_function_decl,t);
|
||
#endif
|
||
|
||
/* If this type was previously laid out as a forward reference,
|
||
make sure we lay it out again. */
|
||
|
||
TYPE_SIZE (t) = 0;
|
||
CLASSTYPE_GOT_SEMICOLON (t) = 0;
|
||
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
|
||
CLASSTYPE_INTERFACE_UNKNOWN (t) = interface_unknown;
|
||
|
||
old = suspend_momentary ();
|
||
|
||
/* Install struct as DECL_FIELD_CONTEXT of each field decl.
|
||
Also process specified field sizes.
|
||
Set DECL_SIZE_UNIT to the specified size, or 0 if none specified.
|
||
The specified size is found in the DECL_INITIAL.
|
||
Store 0 there, except for ": 0" fields (so we can find them
|
||
and delete them, below). */
|
||
|
||
n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
|
||
if (n_baseclasses >= 1)
|
||
{
|
||
struct base_info base_info;
|
||
|
||
/* If using multiple inheritance, this may cause variants of our
|
||
basetypes to be used (instead of their canonical forms). */
|
||
fields = layout_basetypes (t);
|
||
y = tree_last (fields);
|
||
|
||
first_vfn_base_index = finish_base_struct (t, &base_info);
|
||
has_virtual = base_info.has_virtual;
|
||
max_has_virtual = base_info.max_has_virtual;
|
||
CLASSTYPE_N_SUPERCLASSES (t) += base_info.n_ancestors;
|
||
vfield = base_info.vfield;
|
||
vfields = base_info.vfields;
|
||
needs_default_ctor = base_info.needs_default_ctor;
|
||
cant_have_default_ctor = base_info.cant_have_default_ctor;
|
||
needs_const_ctor = base_info.needs_const_ctor;
|
||
cant_have_const_ctor = base_info.cant_have_const_ctor;
|
||
n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
|
||
}
|
||
else
|
||
{
|
||
first_vfn_base_index = 0;
|
||
has_virtual = 0;
|
||
max_has_virtual = 0;
|
||
vfield = NULL_TREE;
|
||
vfields = NULL_TREE;
|
||
fields = NULL_TREE;
|
||
y = NULL_TREE;
|
||
needs_default_ctor = 0;
|
||
cant_have_default_ctor = 0;
|
||
needs_const_ctor = 0;
|
||
cant_have_const_ctor = 0;
|
||
}
|
||
|
||
if (write_virtuals == 3 && ! CLASSTYPE_INTERFACE_UNKNOWN (t))
|
||
{
|
||
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
|
||
CLASSTYPE_VTABLE_NEEDS_WRITING (t) = ! interface_only;
|
||
}
|
||
|
||
/* The three of these are approximations which may later be
|
||
modified. Needed at this point to make add_virtual_function
|
||
and modify_vtable_entries work. */
|
||
CLASSTYPE_ASSOC (t) = make_assoc (integer_zero_node, t,
|
||
0, 0, CLASSTYPE_ASSOC (t));
|
||
CLASSTYPE_VFIELDS (t) = vfields;
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
|
||
fn_fields = NULL_TREE;
|
||
tail = NULL_TREE;
|
||
if (y && list_of_fieldlists)
|
||
TREE_CHAIN (y) = TREE_VALUE (list_of_fieldlists);
|
||
|
||
#ifdef SOS
|
||
if (flag_all_virtual == 2)
|
||
all_virtual = 2;
|
||
else
|
||
#endif
|
||
{
|
||
if (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (t))
|
||
all_virtual = 1;
|
||
else
|
||
all_virtual = 0;
|
||
}
|
||
|
||
if (CLASSTYPE_DECLARED_CLASS (t) == 0)
|
||
{
|
||
nonprivate_method = 1;
|
||
if (list_of_fieldlists
|
||
&& TREE_PURPOSE (list_of_fieldlists) == (tree)visibility_default)
|
||
TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_public;
|
||
}
|
||
else if (list_of_fieldlists
|
||
&& TREE_PURPOSE (list_of_fieldlists) == (tree)visibility_default)
|
||
TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_private;
|
||
|
||
while (list_of_fieldlists)
|
||
{
|
||
visibility = (enum visibility_type)TREE_PURPOSE (list_of_fieldlists);
|
||
|
||
for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
|
||
{
|
||
TREE_PRIVATE (x) = visibility == visibility_private;
|
||
TREE_PROTECTED (x) = visibility == visibility_protected;
|
||
#ifdef FIELD_XREF
|
||
FIELD_xref_member(current_class_name,x);
|
||
#endif
|
||
|
||
if (TREE_CODE (x) == FUNCTION_DECL)
|
||
{
|
||
/* Clear out this flag.
|
||
|
||
@@ Doug may figure out how to break
|
||
@@ this with nested classes and friends. */
|
||
DECL_IN_AGGR_P (x) = 0;
|
||
|
||
nonprivate_method |= ! TREE_PRIVATE (x);
|
||
|
||
/* If this was an evil function, don't keep it in class. */
|
||
if (IDENTIFIER_ERROR_LOCUS (DECL_NAME (x)))
|
||
continue;
|
||
|
||
if (y) TREE_CHAIN (y) = TREE_CHAIN (x);
|
||
if (! fn_fields) fn_fields = x;
|
||
else TREE_CHAIN (tail) = x;
|
||
tail = x;
|
||
if (DECL_CONTEXT (x))
|
||
continue;
|
||
|
||
DECL_CONTEXT (x) = t;
|
||
DECL_VCONTEXT (x) = t;
|
||
|
||
DECL_SIZE_UNIT (x) = 0;
|
||
|
||
/* The name of the field is the original field name
|
||
Save this in auxiliary field for later overloading. */
|
||
if (DECL_VIRTUAL_P (x)
|
||
|| (all_virtual == 1 && ! DECL_CONSTRUCTOR_P (x)))
|
||
{
|
||
pending_virtuals = add_virtual_function (pending_virtuals,
|
||
&has_virtual, x,
|
||
first_vfn_base_index);
|
||
if (DECL_ABSTRACT_VIRTUAL_P (x))
|
||
abstract_virtuals = tree_cons (NULL_TREE, x, abstract_virtuals);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* Handle visibility declarations. */
|
||
if (DECL_NAME (x) && TREE_CODE (DECL_NAME (x)) == SCOPE_REF)
|
||
{
|
||
tree fdecl = TREE_OPERAND (DECL_NAME (x), 1);
|
||
|
||
if (y) TREE_CHAIN (y) = TREE_CHAIN (x);
|
||
/* Make type T see field decl FDECL with
|
||
the visibility VISIBILITY. */
|
||
if (TREE_CODE (fdecl) == TREE_LIST)
|
||
{
|
||
fdecl = TREE_VALUE (fdecl);
|
||
while (fdecl)
|
||
{
|
||
if (alter_visibility (t, fdecl, visibility) == 0)
|
||
break;
|
||
fdecl = TREE_CHAIN (fdecl);
|
||
}
|
||
}
|
||
else alter_visibility (t, fdecl, visibility);
|
||
CLASSTYPE_ALTERS_VISIBILITIES_P (t) = 1;
|
||
continue;
|
||
}
|
||
|
||
/* Perform error checking that did not get done in grokdeclarator. */
|
||
if (TREE_CODE (TREE_TYPE (x)) == FUNCTION_TYPE)
|
||
{
|
||
error_with_decl (x, "field `%s' invalidly declared function type");
|
||
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
|
||
}
|
||
else if (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE)
|
||
{
|
||
error_with_decl (x, "field `%s' invalidly declared method type");
|
||
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
|
||
}
|
||
else if (TREE_CODE (TREE_TYPE (x)) == OFFSET_TYPE)
|
||
{
|
||
error_with_decl (x, "field `%s' invalidly declared offset type");
|
||
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
|
||
}
|
||
/* If this is of reference type, check if it needs an init. */
|
||
if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE
|
||
&& DECL_INITIAL (x) == 0)
|
||
ref_sans_init = 1;
|
||
|
||
/* When this goes into scope, it will be a non-local reference. */
|
||
TREE_NONLOCAL (x) = 1;
|
||
|
||
if (TREE_CODE (x) == FIELD_DECL)
|
||
{
|
||
/* Never let anything with uninheritable virutals
|
||
make it through without complaint. */
|
||
if (TYPE_LANG_SPECIFIC (TREE_TYPE (x))
|
||
&& CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (x)))
|
||
abstract_virtuals_error (x, TREE_TYPE (x));
|
||
|
||
if (TYPE_LANG_SPECIFIC (TREE_TYPE (x)))
|
||
{
|
||
if (TYPE_HAS_DEFAULT_CONSTRUCTOR (TREE_TYPE (x)))
|
||
needs_default_ctor = 1;
|
||
if (TYPE_GETS_CONST_INIT_REF (TREE_TYPE (x)))
|
||
needs_const_ctor = 1;
|
||
else if (TYPE_GETS_INIT_REF (TREE_TYPE (x)))
|
||
cant_have_const_ctor = 1;
|
||
}
|
||
else if (DECL_INITIAL (x) == NULL_TREE
|
||
&& (TYPE_HAS_CONSTRUCTOR (TREE_TYPE (x))
|
||
|| TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE))
|
||
cant_have_default_ctor = 1;
|
||
|
||
/* If any field is const, the structure type is pseudo-const. */
|
||
if (TREE_READONLY (x))
|
||
{
|
||
C_TYPE_FIELDS_READONLY (t) = 1;
|
||
if (DECL_INITIAL (x) == 0)
|
||
const_sans_init = 1;
|
||
}
|
||
else
|
||
{
|
||
/* A field that is pseudo-const makes the structure likewise. */
|
||
tree t1 = TREE_TYPE (x);
|
||
while (TREE_CODE (t1) == ARRAY_TYPE)
|
||
t1 = TREE_TYPE (t1);
|
||
if (IS_AGGR_TYPE (t1))
|
||
{
|
||
if (C_TYPE_FIELDS_READONLY (t1))
|
||
C_TYPE_FIELDS_READONLY (t) = 1;
|
||
if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (t1))
|
||
const_sans_init = 1;
|
||
}
|
||
}
|
||
}
|
||
else if (TREE_STATIC (x) && TREE_CODE (t) == UNION_TYPE)
|
||
/* Unions cannot have static members. */
|
||
error_with_decl (x, "field `%s' declared static in union");
|
||
|
||
if (! fields) fields = x;
|
||
DECL_FIELD_CONTEXT (x) = t;
|
||
DECL_SIZE_UNIT (x) = 0;
|
||
|
||
if (TREE_PACKED (x))
|
||
{
|
||
/* Invalid bit-field size done by grokfield. */
|
||
/* Detect invalid bit-field type. */
|
||
if (DECL_INITIAL (x)
|
||
&& TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE
|
||
&& TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
|
||
{
|
||
error_with_decl (x, "bit-field `%s' has invalid type");
|
||
DECL_INITIAL (x) = NULL;
|
||
}
|
||
if (DECL_INITIAL (x) && pedantic
|
||
&& TREE_TYPE (x) != integer_type_node
|
||
&& TREE_TYPE (x) != unsigned_type_node)
|
||
warning_with_decl (x, "bit-field `%s' type invalid in ANSI C");
|
||
|
||
/* Detect and ignore out of range field width. */
|
||
if (DECL_INITIAL (x))
|
||
{
|
||
register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
|
||
|
||
if (width < 0)
|
||
{
|
||
DECL_INITIAL (x) = NULL;
|
||
warning_with_decl (x, "negative width in bit-field `%s'");
|
||
}
|
||
else if (width == 0 && DECL_NAME (x) != 0)
|
||
{
|
||
error_with_decl (x, "zero width for bit-field `%s'");
|
||
DECL_INITIAL (x) = NULL;
|
||
}
|
||
else if (width > TYPE_PRECISION (TREE_TYPE (x)))
|
||
{
|
||
DECL_INITIAL (x) = NULL;
|
||
warning_with_decl (x, "width of `%s' exceeds its type");
|
||
}
|
||
}
|
||
|
||
/* Process valid field width. */
|
||
if (DECL_INITIAL (x))
|
||
{
|
||
register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
|
||
|
||
if (width == 0)
|
||
{
|
||
/* field size 0 => mark following field as "aligned" */
|
||
if (TREE_CHAIN (x))
|
||
DECL_ALIGN (TREE_CHAIN (x))
|
||
= MAX (DECL_ALIGN (TREE_CHAIN (x)), EMPTY_FIELD_BOUNDARY);
|
||
/* field of size 0 at the end => round up the size. */
|
||
else
|
||
round_up_size = EMPTY_FIELD_BOUNDARY;
|
||
}
|
||
else
|
||
{
|
||
DECL_INITIAL (x) = NULL_TREE;
|
||
DECL_SIZE_UNIT (x) = width;
|
||
TREE_PACKED (x) = 1;
|
||
/* Traditionally a bit field is unsigned
|
||
even if declared signed. */
|
||
if (flag_traditional
|
||
&& TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE)
|
||
TREE_TYPE (x) = unsigned_type_node;
|
||
}
|
||
}
|
||
else
|
||
/* Non-bit-fields are aligned for their type. */
|
||
DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
|
||
}
|
||
else if (TREE_CODE (x) == FIELD_DECL)
|
||
{
|
||
tree type = TREE_TYPE (x);
|
||
if (TREE_CODE (type) == ARRAY_TYPE)
|
||
type = TREE_TYPE (type);
|
||
if (code == UNION_TYPE)
|
||
{
|
||
if (TYPE_NEEDS_CONSTRUCTING (type))
|
||
error ("member %s::%s with constructor not allowed in union",
|
||
IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (DECL_NAME (x)));
|
||
if (TYPE_NEEDS_DESTRUCTOR (type))
|
||
error ("member %s::%s with destructor (also) not allowed in union",
|
||
IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (DECL_NAME (x)));
|
||
}
|
||
else if (code == RECORD_TYPE)
|
||
{
|
||
/* Array of record type doesn't matter for this bit. */
|
||
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
|
||
if (IS_AGGR_TYPE (type))
|
||
{
|
||
needs_ctor |= TYPE_NEEDS_CONSTRUCTOR (type);
|
||
needs_dtor |= TYPE_NEEDS_DESTRUCTOR (type);
|
||
members_need_dtors |= TYPE_NEEDS_DESTRUCTOR (type);
|
||
TYPE_GETS_ASSIGNMENT (t) |= TYPE_GETS_ASSIGNMENT (type);
|
||
TYPE_GETS_INIT_REF (t) |= TYPE_GETS_INIT_REF (type);
|
||
TYPE_GETS_CONST_INIT_REF (t) |= TYPE_GETS_CONST_INIT_REF (type);
|
||
}
|
||
}
|
||
if (DECL_INITIAL (x) != NULL_TREE)
|
||
{
|
||
/* `build_class_init_list' does not recognize non-FIELD_DECLs. */
|
||
if (code == UNION_TYPE && any_default_members != 0)
|
||
error ("multiple fields in union initialized");
|
||
any_default_members = 1;
|
||
}
|
||
}
|
||
y = x;
|
||
}
|
||
list_of_fieldlists = TREE_CHAIN (list_of_fieldlists);
|
||
/* link the tail while we have it! */
|
||
if (y)
|
||
{
|
||
TREE_CHAIN (y) = NULL_TREE;
|
||
|
||
if (list_of_fieldlists
|
||
&& TREE_VALUE (list_of_fieldlists)
|
||
&& TREE_CODE (TREE_VALUE (list_of_fieldlists)) != FUNCTION_DECL)
|
||
TREE_CHAIN (y) = TREE_VALUE (list_of_fieldlists);
|
||
}
|
||
}
|
||
|
||
if (tail) TREE_CHAIN (tail) = NULL_TREE;
|
||
|
||
/* If this type has any constant members which did not come
|
||
with their own initialization, mark that fact here. It is
|
||
not an error here, since such types can be saved either by their
|
||
constructors, or by fortuitous initialization. */
|
||
CLASSTYPE_READONLY_FIELDS_NEED_INIT (t) = const_sans_init;
|
||
CLASSTYPE_REF_FIELDS_NEED_INIT (t) = ref_sans_init;
|
||
CLASSTYPE_ABSTRACT_VIRTUALS (t) = abstract_virtuals;
|
||
|
||
if (vfield == 0
|
||
&& (has_virtual
|
||
#ifdef SOS
|
||
|| TYPE_DYNAMIC (t)
|
||
#endif
|
||
))
|
||
{
|
||
/* We build this decl with ptr_type_node, and
|
||
change the type when we know what it should be. */
|
||
vfield = build_decl (FIELD_DECL, get_vfield_name (t), ptr_type_node);
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
DECL_VIRTUAL_P (vfield) = 1;
|
||
DECL_FIELD_CONTEXT (vfield) = t;
|
||
SET_DECL_FCONTEXT (vfield, t);
|
||
DECL_SIZE_UNIT (vfield) = 0;
|
||
if (y)
|
||
{
|
||
assert (TREE_CHAIN (y) == 0);
|
||
TREE_CHAIN (y) = vfield;
|
||
y = vfield;
|
||
}
|
||
else fields = vfield;
|
||
vfields = chainon (vfields, CLASSTYPE_AS_LIST (t));
|
||
}
|
||
|
||
/* Now DECL_INITIAL is null on all members except for zero-width bit-fields.
|
||
And they have already done their work.
|
||
|
||
C++: maybe we will support default field initialization some day... */
|
||
|
||
/* Delete all zero-width bit-fields from the front of the fieldlist */
|
||
while (fields && TREE_PACKED (fields)
|
||
&& DECL_INITIAL (fields))
|
||
fields = TREE_CHAIN (fields);
|
||
/* Delete all such fields from the rest of the fields. */
|
||
for (x = fields; x;)
|
||
{
|
||
if (TREE_CHAIN (x) && TREE_PACKED (TREE_CHAIN (x))
|
||
&& DECL_INITIAL (TREE_CHAIN (x)))
|
||
TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
|
||
else x = TREE_CHAIN (x);
|
||
}
|
||
/* Delete all duplicate fields from the fields */
|
||
delete_duplicate_fields (fields);
|
||
|
||
/* Now we have the final fieldlist for the data fields. Record it,
|
||
then lay out the structure or union (including the fields). */
|
||
|
||
TYPE_FIELDS (t) = fields;
|
||
|
||
/* If there's a :0 field at the end, round the size to the
|
||
EMPTY_FIELD_BOUNDARY. */
|
||
TYPE_ALIGN (t) = round_up_size;
|
||
|
||
if (debug_default_functions)
|
||
{
|
||
if ((TYPE_NEEDS_CONSTRUCTOR (t) || TYPE_HAS_CONSTRUCTOR (t) || needs_ctor)
|
||
&& ! TYPE_HAS_INIT_REF (t))
|
||
{
|
||
tree default_fn = cons_up_default_function (t, name, 1);
|
||
TREE_CHAIN (default_fn) = fn_fields;
|
||
DECL_CONTEXT (default_fn) = t;
|
||
DECL_VCONTEXT (default_fn) = t;
|
||
fn_fields = default_fn;
|
||
TYPE_HAS_INIT_REF (t) = 1;
|
||
default_fn = cons_up_default_function (t, name, 3);
|
||
TREE_CHAIN (default_fn) = fn_fields;
|
||
DECL_CONTEXT (default_fn) = t;
|
||
DECL_VCONTEXT (default_fn) = t;
|
||
fn_fields = default_fn;
|
||
nonprivate_method = 1;
|
||
}
|
||
|
||
if (! TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
|
||
&& needs_default_ctor && ! cant_have_default_ctor)
|
||
{
|
||
tree default_fn = cons_up_default_function (t, name, 2);
|
||
TREE_CHAIN (default_fn) = fn_fields;
|
||
DECL_CONTEXT (default_fn) = t;
|
||
DECL_VCONTEXT (default_fn) = t;
|
||
fn_fields = default_fn;
|
||
TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1;
|
||
nonprivate_method = 1;
|
||
}
|
||
}
|
||
/* Warn about duplicate methods in fn_fields. Also compact
|
||
method lists so that lookup can be made faster.
|
||
|
||
Algorithm: Outer loop builds lists by method name.
|
||
Inner loop checks for redundant method names within a list.
|
||
|
||
Data Structure: List of method lists. The outer list
|
||
is a TREE_LIST, whose TREE_PURPOSE field is the field name
|
||
and the TREE_VALUE is the TREE_CHAIN of the FUNCTION_DECLs.
|
||
Friends are chained in the same way as member functions, but
|
||
they live in the TREE_TYPE field of the outer list.
|
||
That allows them to be quicky deleted, and requires
|
||
no extra storage.
|
||
|
||
If there are any constructors/destructors, they are moved to
|
||
the front of the list. This makes pushclass more efficient.
|
||
|
||
We also link each field which has shares a name with its
|
||
baseclass to the head of the list of fields for that base class.
|
||
This allows us to reduce search time in places like `build_method_call'
|
||
to consider only reasonably likely functions. */
|
||
|
||
if (fn_fields)
|
||
{
|
||
/* Now prepare to gather fn_fields into vector. */
|
||
struct obstack *ambient_obstack = current_obstack;
|
||
current_obstack = &class_obstack;
|
||
method_vec = make_node (TREE_VEC);
|
||
/* Room has been saved for constructors and destructors. */
|
||
current_obstack = ambient_obstack;
|
||
/* Now make this a live vector. */
|
||
obstack_free (&class_obstack, method_vec);
|
||
obstack_blank (&class_obstack, sizeof (struct tree_vec));
|
||
|
||
while (fn_fields)
|
||
{
|
||
/* NEXT Pointer, TEST Pointer, and BASE Pointer. */
|
||
tree nextp, *testp;
|
||
|
||
nextp = TREE_CHAIN (fn_fields);
|
||
TREE_CHAIN (fn_fields) = NULL_TREE;
|
||
/* Constrcutors are handled easily in search routines.
|
||
Besides, we know we wont find any, so do not bother looking. */
|
||
if (DECL_ORIGINAL_NAME (fn_fields) == name
|
||
&& TREE_VEC_ELT (method_vec, 0) == 0)
|
||
TREE_VEC_ELT (method_vec, 0) = fn_fields;
|
||
else
|
||
{
|
||
testp = &TREE_VEC_ELT (method_vec, 0);
|
||
if (*testp == NULL_TREE)
|
||
testp++;
|
||
while ((int)testp < (int)obstack_next_free (&class_obstack)
|
||
&& DECL_ORIGINAL_NAME (*testp) != DECL_ORIGINAL_NAME (fn_fields))
|
||
testp++;
|
||
if ((int)testp < (int)obstack_next_free (&class_obstack))
|
||
{
|
||
for (x = *testp; x; x = TREE_CHAIN (x))
|
||
{
|
||
if (DECL_NAME (fn_fields) == DECL_NAME (x))
|
||
{
|
||
/* We complain about multiple destructors on sight,
|
||
so we do not repeat the warning here. Friend-friend
|
||
ambiguities are warned about outside this loop. */
|
||
if (! DESTRUCTOR_NAME_P (DECL_NAME (fn_fields)))
|
||
error_with_file_and_line (DECL_SOURCE_FILE (fn_fields),
|
||
DECL_SOURCE_LINE (fn_fields),
|
||
"ambiguous method `%s' in structure",
|
||
lang_printable_name (fn_fields));
|
||
break;
|
||
}
|
||
y = x;
|
||
}
|
||
if (x == 0)
|
||
if (*testp)
|
||
TREE_CHAIN (y) = fn_fields;
|
||
else
|
||
*testp = fn_fields;
|
||
}
|
||
else
|
||
{
|
||
obstack_ptr_grow (&class_obstack, fn_fields);
|
||
method_vec = (tree)obstack_base (&class_obstack);
|
||
}
|
||
}
|
||
fn_fields = nextp;
|
||
}
|
||
|
||
TREE_VEC_LENGTH (method_vec)
|
||
= (tree *)obstack_next_free (&class_obstack) - (&TREE_VEC_ELT (method_vec, 0));
|
||
obstack_finish (&class_obstack);
|
||
CLASSTYPE_METHOD_VEC (t) = method_vec;
|
||
|
||
if (nonprivate_method == 0
|
||
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
|
||
&& DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
|
||
{
|
||
for (i = 0; i <= n_baseclasses; i++)
|
||
if (CLASSTYPE_VIA_PUBLIC (t, i))
|
||
{
|
||
nonprivate_method = 1;
|
||
break;
|
||
}
|
||
if (nonprivate_method == 0)
|
||
warning ("all class member functions are private");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
method_vec = 0;
|
||
|
||
/* Just in case these got accidently
|
||
filled in by syntax errors. */
|
||
TYPE_HAS_CONSTRUCTOR (t) = 0;
|
||
TYPE_HAS_DESTRUCTOR (t) = 0;
|
||
}
|
||
|
||
/* If there are constructors (and destructors), they are at the
|
||
front. Place destructors at very front. Also warn if all
|
||
constructors and/or destructors are private (in which case this
|
||
class is effectively unusable. */
|
||
if (TYPE_HAS_DESTRUCTOR (t))
|
||
{
|
||
tree dtor, prev;
|
||
|
||
for (dtor = TREE_VEC_ELT (method_vec, 0); dtor; prev = dtor, dtor = TREE_CHAIN (dtor))
|
||
{
|
||
if (DESTRUCTOR_NAME_P (DECL_NAME (dtor)))
|
||
{
|
||
if (TREE_PRIVATE (dtor)
|
||
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
|
||
&& DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
|
||
warning_with_decl (TYPE_NAME (t), "class `%s' only defines a private destructor and has no friends");
|
||
break;
|
||
}
|
||
}
|
||
/* Wild parse errors can cause this to happen. */
|
||
if (dtor == NULL_TREE)
|
||
TYPE_HAS_DESTRUCTOR (t) = 0;
|
||
else if (dtor != TREE_VEC_ELT (method_vec, 0))
|
||
{
|
||
TREE_CHAIN (prev) = TREE_CHAIN (dtor);
|
||
TREE_CHAIN (dtor) = TREE_VEC_ELT (method_vec, 0);
|
||
TREE_VEC_ELT (method_vec, 0) = dtor;
|
||
}
|
||
}
|
||
else if (members_need_dtors
|
||
|| TYPE_USES_VIRTUAL_BASECLASSES (t)
|
||
|| TYPE_USES_MULTIPLE_INHERITANCE (t))
|
||
{
|
||
/* Here we must cons up a destructor on the fly. */
|
||
tree dtor = cons_up_default_function (t, name, 0);
|
||
|
||
/* If we couldn't make it work, then pretend we didn't need it. */
|
||
if (dtor == void_type_node)
|
||
TYPE_NEEDS_DESTRUCTOR (t) = 0;
|
||
else
|
||
{
|
||
DECL_CONTEXT (dtor) = t;
|
||
DECL_VCONTEXT (dtor) = t;
|
||
if (DECL_VIRTUAL_P (dtor))
|
||
pending_virtuals = add_virtual_function (pending_virtuals,
|
||
&has_virtual, dtor);
|
||
if (TYPE_HAS_CONSTRUCTOR (t))
|
||
TREE_CHAIN (dtor) = TREE_VEC_ELT (method_vec, 0);
|
||
else if (method_vec == 0)
|
||
{
|
||
/* Now prepare to gather fn_fields into vector. */
|
||
struct obstack *ambient_obstack = current_obstack;
|
||
current_obstack = &class_obstack;
|
||
method_vec = make_node (TREE_VEC);
|
||
/* Room has been saved for constructors and destructors. */
|
||
current_obstack = ambient_obstack;
|
||
TREE_VEC_LENGTH (method_vec) = 1;
|
||
CLASSTYPE_METHOD_VEC (t) = method_vec;
|
||
}
|
||
TREE_VEC_ELT (method_vec, 0) = dtor;
|
||
TYPE_HAS_DESTRUCTOR (t) = 1;
|
||
}
|
||
}
|
||
if (TYPE_HAS_CONSTRUCTOR (t)
|
||
&& ! CLASSTYPE_DECLARED_EXCEPTION (t)
|
||
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
|
||
&& DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
|
||
{
|
||
int nonprivate_ctor = 0;
|
||
tree ctor;
|
||
|
||
for (ctor = TREE_VEC_ELT (method_vec, 0); ctor; ctor = TREE_CHAIN (ctor))
|
||
if (! TREE_PRIVATE (ctor))
|
||
{
|
||
nonprivate_ctor = 1;
|
||
break;
|
||
}
|
||
if (nonprivate_ctor == 0)
|
||
warning ("class %s only defines private constructors and has no friends",
|
||
TYPE_NAME_STRING (t));
|
||
}
|
||
|
||
/* Now for each member function (except for constructors and
|
||
destructors), compute where member functions of the same
|
||
name reside in base classes. */
|
||
if (n_baseclasses != 0
|
||
&& method_vec != NULL_TREE
|
||
&& TREE_VEC_LENGTH (method_vec) > 1)
|
||
{
|
||
int len = TREE_VEC_LENGTH (method_vec);
|
||
tree baselink_vec = make_tree_vec (len);
|
||
int any_links = 0;
|
||
|
||
for (i = 1; i < len; i++)
|
||
{
|
||
TREE_VEC_ELT (baselink_vec, i)
|
||
= get_baselinks (t, DECL_ORIGINAL_NAME (TREE_VEC_ELT (method_vec, i)));
|
||
if (TREE_VEC_ELT (baselink_vec, i) != 0)
|
||
any_links = 1;
|
||
}
|
||
if (any_links != 0)
|
||
CLASSTYPE_BASELINK_VEC (t) = baselink_vec;
|
||
else
|
||
obstack_free (current_obstack, baselink_vec);
|
||
}
|
||
|
||
/* We can't know this information until we have seen all of the
|
||
constructors. */
|
||
TYPE_NONE_ASSIGN_THIS (t) = 0;
|
||
|
||
/* Pass layout information about base classes to layout_type, if any. */
|
||
|
||
if (n_baseclasses)
|
||
{
|
||
tree pseudo_basetype = TREE_TYPE (base_layout_decl);
|
||
|
||
TREE_CHAIN (base_layout_decl) = TYPE_FIELDS (t);
|
||
TYPE_FIELDS (t) = base_layout_decl;
|
||
|
||
TYPE_SIZE (pseudo_basetype) = CLASSTYPE_SIZE (t);
|
||
TYPE_SIZE_UNIT (pseudo_basetype) = TYPE_SIZE_UNIT (t);
|
||
TYPE_MODE (pseudo_basetype) = TYPE_MODE (t);
|
||
TYPE_ALIGN (pseudo_basetype) = CLASSTYPE_ALIGN (t);
|
||
DECL_ALIGN (base_layout_decl) = TYPE_ALIGN (pseudo_basetype);
|
||
}
|
||
|
||
layout_type (t);
|
||
|
||
if (n_baseclasses)
|
||
TYPE_FIELDS (t) = TREE_CHAIN (TYPE_FIELDS (t));
|
||
|
||
/* C++: do not let empty structures exist. */
|
||
if (integer_zerop (TYPE_SIZE (t)))
|
||
TYPE_SIZE (t) = TYPE_SIZE (char_type_node);
|
||
|
||
/* Set the TYPE_DECL for this type to contain the right
|
||
value for DECL_OFFSET, so that we can use it as part
|
||
of a COMPONENT_REF for multiple inheritance. */
|
||
|
||
if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
|
||
layout_decl (TYPE_NAME (t));
|
||
|
||
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
|
||
{
|
||
tree vbases;
|
||
|
||
max_has_virtual = layout_vbasetypes (t, max_has_virtual);
|
||
vbases = CLASSTYPE_VBASECLASSES (t);
|
||
CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases);
|
||
|
||
/* Now fix up any virtual base class types that we
|
||
left lying around. We must get these done
|
||
before we try to lay out the virtual function table. */
|
||
pending_hard_virtuals = nreverse (pending_hard_virtuals);
|
||
#if 1
|
||
/* This loop makes all the entries in the virtual function tables
|
||
of interest contain the "latest" version of the functions
|
||
we have defined. */
|
||
|
||
while (vbases)
|
||
{
|
||
tree virtuals = ASSOC_VIRTUALS (vbases);
|
||
|
||
if (virtuals)
|
||
virtuals = TREE_CHAIN (virtuals);
|
||
|
||
while (virtuals != NULL_TREE)
|
||
{
|
||
tree pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
|
||
tree base_fndecl = TREE_OPERAND (pfn, 0);
|
||
tree decl = get_first_matching_virtual (t, base_fndecl, 0);
|
||
tree context = DECL_CONTEXT (decl);
|
||
if (decl != base_fndecl && context != t)
|
||
{
|
||
tree assoc = NULL_TREE, these_virtuals;
|
||
int i = TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)) & ((1<<(BITS_PER_WORD-1))-1);
|
||
|
||
if (TYPE_USES_VIRTUAL_BASECLASSES (context))
|
||
assoc = virtual_member (DECL_CONTEXT (base_fndecl),
|
||
CLASSTYPE_VBASECLASSES (context));
|
||
if (assoc == NULL_TREE)
|
||
assoc = assoc_value (DECL_CONTEXT (base_fndecl), context);
|
||
if (assoc != NULL_TREE)
|
||
{
|
||
these_virtuals = ASSOC_VIRTUALS (assoc);
|
||
|
||
while (i-- > 0)
|
||
these_virtuals = TREE_CHAIN (these_virtuals);
|
||
pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (these_virtuals));
|
||
modify_vtable_entries (t, decl, base_fndecl, pfn);
|
||
}
|
||
}
|
||
virtuals = TREE_CHAIN (virtuals);
|
||
}
|
||
vbases = TREE_CHAIN (vbases);
|
||
}
|
||
#endif /* 1 */
|
||
while (pending_hard_virtuals)
|
||
{
|
||
/* Need an entry in some other virtual function table. */
|
||
tree base_fndecls = DECL_VINDEX (TREE_PURPOSE (pending_hard_virtuals));
|
||
while (base_fndecls)
|
||
{
|
||
modify_vtable_entries (t, TREE_PURPOSE (pending_hard_virtuals),
|
||
TREE_VALUE (base_fndecls),
|
||
TREE_VALUE (pending_hard_virtuals));
|
||
base_fndecls = TREE_CHAIN (base_fndecls);
|
||
}
|
||
pending_hard_virtuals = TREE_CHAIN (pending_hard_virtuals);
|
||
}
|
||
}
|
||
else
|
||
CLASSTYPE_VBASE_SIZE (t) = integer_zero_node;
|
||
|
||
if (pending_virtuals)
|
||
{
|
||
pending_virtuals = nreverse (pending_virtuals);
|
||
/* We must enter these virtuals into the table. */
|
||
if (first_vfn_base_index == 0)
|
||
{
|
||
pending_virtuals = tree_cons (NULL_TREE, the_null_vtable_entry,
|
||
pending_virtuals);
|
||
build_vtable (0, t);
|
||
}
|
||
else
|
||
{
|
||
/* Here we know enough to change the type of our virtual
|
||
function table, but we will wait until later this function. */
|
||
if (! CLASSTYPE_MARKED4 (t))
|
||
build_vtable (assoc_value (TYPE_MAIN_VARIANT (CLASSTYPE_BASECLASS (t, first_vfn_base_index)), t), t);
|
||
}
|
||
|
||
/* If this type has basetypes with constructors, then those
|
||
constructors might clobber the virtual function table. But
|
||
they don't if the derived class shares the exact vtable of the base
|
||
class. */
|
||
|
||
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
|
||
}
|
||
else if (first_vfn_base_index)
|
||
{
|
||
tree basetype = get_base_type (DECL_FIELD_CONTEXT (vfield), t, 0);
|
||
tree assoc;
|
||
|
||
if (TREE_VIA_VIRTUAL (basetype))
|
||
assoc = virtual_member (DECL_FIELD_CONTEXT (vfield), CLASSTYPE_VBASECLASSES (t));
|
||
else
|
||
assoc = assoc_value (TYPE_MAIN_VARIANT (basetype), t);
|
||
|
||
/* This class contributes nothing new to the virtual function
|
||
table. However, it may have declared functions which
|
||
went into the virtual function table "inherited" from the
|
||
base class. If so, we grab a copy of those updated functions,
|
||
and pretend they are ours. */
|
||
|
||
#ifdef SOS
|
||
/* Don't define this ahead of time if we have more
|
||
fields to add later. */
|
||
if (all_virtual == 2 && fn_fields != NULL_TREE)
|
||
;
|
||
else
|
||
#endif
|
||
{
|
||
/* See if we should steal the virtual info from base class. */
|
||
if (CLASS_ASSOC_VTABLE (t) == NULL_TREE)
|
||
CLASS_ASSOC_VTABLE (t) = ASSOC_VTABLE (assoc);
|
||
if (CLASS_ASSOC_VIRTUALS (t) == NULL_TREE)
|
||
CLASS_ASSOC_VIRTUALS (t) = ASSOC_VIRTUALS (assoc);
|
||
}
|
||
if (CLASS_ASSOC_VTABLE (t) != ASSOC_VTABLE (assoc))
|
||
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
|
||
}
|
||
|
||
if (has_virtual > max_has_virtual)
|
||
max_has_virtual = has_virtual;
|
||
if (max_has_virtual || first_vfn_base_index)
|
||
{
|
||
#ifdef VTABLE_USES_MASK
|
||
if (max_has_virtual >= VINDEX_MAX)
|
||
{
|
||
error ("too many virtual functions for class `%s' (VINDEX_MAX < %d)", TYPE_NAME_STRING (t), has_virtual);
|
||
}
|
||
#endif
|
||
TYPE_VIRTUAL_P (t) = 1;
|
||
CLASSTYPE_VSIZE (t) = has_virtual;
|
||
if (first_vfn_base_index)
|
||
{
|
||
if (pending_virtuals)
|
||
CLASS_ASSOC_VIRTUALS (t) = chainon (CLASS_ASSOC_VIRTUALS (t),
|
||
pending_virtuals);
|
||
}
|
||
else if (has_virtual)
|
||
{
|
||
CLASS_ASSOC_VIRTUALS (t) = pending_virtuals;
|
||
if (write_virtuals >= 0)
|
||
DECL_VIRTUAL_P (CLASS_ASSOC_VTABLE (t)) = 1;
|
||
}
|
||
}
|
||
|
||
#ifdef SOS
|
||
if (all_virtual == 2 && (max_has_virtual || method_vec))
|
||
{
|
||
/* Now that we know the size of the virtual table, lay out
|
||
the absolute table following it. */
|
||
int i;
|
||
tree tmp;
|
||
tree pending_absolutes = NULL_TREE;
|
||
int has_absolute = has_virtual;
|
||
|
||
/* Local variables for building a table filled with strings
|
||
containing the names of interesting things. */
|
||
tree decl, init;
|
||
tree start = NULL_TREE, next = NULL_TREE;
|
||
tree *outer = &TREE_VEC_ELT (method_vec, 0);
|
||
|
||
while (outer != TREE_VEC_END (method_vec))
|
||
{
|
||
tree inner;
|
||
for (inner = *outer; inner; inner = TREE_CHAIN (inner))
|
||
{
|
||
tree entry;
|
||
tree fn;
|
||
|
||
/* Don't bother with functions which appear
|
||
for visibility reasons. */
|
||
if (DECL_FIELD_CONTEXT (inner) != t)
|
||
continue;
|
||
|
||
/* Must lay this function into its absolute table as well.
|
||
This forces an inline function to be written out. */
|
||
fn = build1 (ADDR_EXPR, ptr_type_node, inner);
|
||
TREE_LITERAL (fn) = 1;
|
||
DECL_DINDEX (inner) = build_int_2 (++has_absolute, 0);
|
||
entry = build_vtable_entry (integer_zero_node, fn);
|
||
pending_absolutes = tree_cons (DECL_DINDEX (inner), entry,
|
||
pending_absolutes);
|
||
}
|
||
outer++;
|
||
}
|
||
|
||
CLASS_ASSOC_VIRTUALS (t) = chainon (CLASS_ASSOC_VIRTUALS (t),
|
||
nreverse (pending_absolutes));
|
||
if (TYPE_DYNAMIC (t))
|
||
{
|
||
for (outer = &TREE_VEC_ELT (method_vec, 0);
|
||
outer != TREE_VEC_END (method_vec);
|
||
outer++)
|
||
{
|
||
tree inner;
|
||
for (inner = *outer; inner; inner = TREE_CHAIN (inner))
|
||
{
|
||
tree str = make_node (STRING_CST);
|
||
TREE_STRING_LENGTH (str) = IDENTIFIER_LENGTH (DECL_NAME (inner));
|
||
TREE_STRING_POINTER (str) = IDENTIFIER_POINTER (DECL_NAME (inner));
|
||
TREE_LITERAL (str) = 1;
|
||
TREE_STATIC (str) = 1;
|
||
TREE_TYPE (str)
|
||
= build_cplus_array_type (char_type_node,
|
||
build_index_type (build_int_2 (TREE_STRING_LENGTH (str) - 1, 0)));
|
||
|
||
if (start)
|
||
{
|
||
TREE_CHAIN (next) = build_tree_list (NULL_TREE, str);
|
||
next = TREE_CHAIN (next);
|
||
}
|
||
else
|
||
{
|
||
start = build_tree_list (NULL_TREE, str);
|
||
next = start;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Lay out dynamic link table for SOS. */
|
||
|
||
decl = finish_table (get_linktable_name (t),
|
||
string_type_node, start, 0);
|
||
}
|
||
has_virtual = has_absolute;
|
||
CLASSTYPE_VSIZE (t) = has_virtual;
|
||
if (has_virtual > max_has_virtual)
|
||
max_has_virtual = has_virtual;
|
||
if (vfield == 0)
|
||
{
|
||
/* We build this decl with ptr_type_node, and
|
||
change the type when we know what it should be. */
|
||
vfield = build_decl (FIELD_DECL, get_vfield_name (t), ptr_type_node);
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
DECL_VIRTUAL_P (vfield) = 1;
|
||
DECL_FIELD_CONTEXT (vfield) = t;
|
||
SET_DECL_FCONTEXT (vfield, t);
|
||
DECL_SIZE_UNIT (vfield) = 0;
|
||
y = tree_last (fields);
|
||
if (y)
|
||
TREE_CHAIN (y) = vfield;
|
||
else
|
||
fields = vfield;
|
||
vfields = chainon (vfields, CLASSTYPE_AS_LIST (t));
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* Now lay out the virtual function table. */
|
||
if (has_virtual)
|
||
{
|
||
tree atype, itype;
|
||
|
||
if (TREE_TYPE (vfield) == ptr_type_node)
|
||
{
|
||
/* We must create a pointer to this table because
|
||
the one inherited from base class does not exist.
|
||
We will fill in the type when we know what it
|
||
should really be. */
|
||
itype = build_index_type (build_int_2 (has_virtual, 0));
|
||
atype = build_array_type (vtable_entry_type, itype);
|
||
layout_type (atype);
|
||
TREE_TYPE (vfield) = build_pointer_type (atype);
|
||
}
|
||
else
|
||
{
|
||
atype = TREE_TYPE (TREE_TYPE (vfield));
|
||
|
||
if (has_virtual != TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))))
|
||
{
|
||
/* We must extend (or create) the boundaries on this array,
|
||
because we picked up virtual functions from multiple
|
||
base classes. */
|
||
itype = build_index_type (build_int_2 (has_virtual, 0));
|
||
atype = build_array_type (vtable_entry_type, itype);
|
||
layout_type (atype);
|
||
vfield = copy_node (vfield);
|
||
TREE_TYPE (vfield) = build_pointer_type (atype);
|
||
#if 0
|
||
/* In the case of single inheritance, we can
|
||
just move up the tree, since we share the
|
||
same vptr slot. */
|
||
if (TREE_CHAIN (vfields) == NULL_TREE)
|
||
vfields = CLASSTYPE_AS_LIST (t);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
if (TREE_TYPE (CLASS_ASSOC_VTABLE (t)) != atype)
|
||
{
|
||
TREE_TYPE (CLASS_ASSOC_VTABLE (t)) = atype;
|
||
layout_decl (CLASS_ASSOC_VTABLE (t));
|
||
DECL_ALIGN (CLASS_ASSOC_VTABLE (t))
|
||
= MAX (TYPE_ALIGN (double_type_node),
|
||
DECL_ALIGN (CLASS_ASSOC_VTABLE (t)));
|
||
}
|
||
}
|
||
else if (first_vfn_base_index)
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
CLASSTYPE_VFIELDS (t) = vfields;
|
||
|
||
/* Set all appropriate CLASSTYPE_... flags for this type
|
||
and its variants. */
|
||
TYPE_NEEDS_CONSTRUCTOR (t) |= needs_ctor || TYPE_HAS_CONSTRUCTOR (t);
|
||
TYPE_NEEDS_CONSTRUCTING (t)
|
||
|= ((TYPE_NEEDS_CONSTRUCTOR (t)|TYPE_USES_VIRTUAL_BASECLASSES (t))
|
||
|| (has_virtual | first_vfn_base_index)
|
||
|| any_default_members);
|
||
TYPE_NEEDS_DESTRUCTOR (t) |= needs_dtor || TYPE_HAS_DESTRUCTOR (t);
|
||
finish_struct_bits (t, first_vfn_base_index, max_has_virtual);
|
||
|
||
/* Promote each bit-field's type to int if it is narrower than that.
|
||
Also warn (or error) if static members are specified for a class
|
||
which takes a constructor. */
|
||
for (x = fields; x; x = TREE_CHAIN (x))
|
||
{
|
||
if (TREE_PACKED (x)
|
||
&& TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE
|
||
&& (TREE_INT_CST_LOW (DECL_SIZE (x)) * DECL_SIZE_UNIT (x)
|
||
< TYPE_PRECISION (integer_type_node)))
|
||
TREE_TYPE (x) = integer_type_node;
|
||
}
|
||
|
||
if (TYPE_HAS_CONSTRUCTOR (t))
|
||
{
|
||
tree vfields = CLASSTYPE_VFIELDS (t);
|
||
|
||
while (vfields)
|
||
{
|
||
/* Mark the fact that constructor for T
|
||
could affect anybody inheriting from T
|
||
who wants to initialize vtables for VFIELDS's type. */
|
||
if (TREE_TYPE (vfields))
|
||
TREE_ADDRESSABLE (vfields) = 1;
|
||
vfields = TREE_CHAIN (vfields);
|
||
}
|
||
if (any_default_members != 0)
|
||
build_class_init_list (t);
|
||
}
|
||
else if (TYPE_NEEDS_CONSTRUCTING (t))
|
||
build_class_init_list (t);
|
||
|
||
if (current_lang_name == lang_name_cplusplus)
|
||
{
|
||
if (! CLASSTYPE_DECLARED_EXCEPTION (t))
|
||
embrace_waiting_friends (t);
|
||
|
||
/* Write out inline function definitions. */
|
||
do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
|
||
CLASSTYPE_INLINE_FRIENDS (t) = 0;
|
||
}
|
||
|
||
if (CLASSTYPE_VSIZE (t) != 0)
|
||
{
|
||
TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (CLASS_ASSOC_VTABLE (t)), vfield);
|
||
|
||
if ((flag_this_is_variable & 1) == 0)
|
||
{
|
||
tree vtbl_ptr = build_decl (VAR_DECL, get_identifier (VPTR_NAME),
|
||
TREE_TYPE (vfield));
|
||
TREE_REGDECL (vtbl_ptr) = 1;
|
||
CLASSTYPE_VTBL_PTR (t) = vtbl_ptr;
|
||
}
|
||
if (DECL_FIELD_CONTEXT (vfield) != t)
|
||
{
|
||
tree assoc = assoc_value (DECL_FIELD_CONTEXT (vfield), t);
|
||
tree offset = ASSOC_OFFSET (assoc);
|
||
|
||
vfield = copy_node (vfield);
|
||
|
||
if (! integer_zerop (offset))
|
||
offset = convert_units (offset, BITS_PER_UNIT, 1);
|
||
if (DECL_OFFSET (vfield))
|
||
offset = genop (PLUS_EXPR, offset, build_int (DECL_OFFSET (vfield)));
|
||
DECL_FIELD_CONTEXT (vfield) = t;
|
||
DECL_OFFSET (vfield) = TREE_INT_CST_LOW (offset);
|
||
CLASSTYPE_VFIELD (t) = vfield;
|
||
}
|
||
}
|
||
|
||
/* Make the rtl for any new vtables we have created, and unmark
|
||
the base types we marked. */
|
||
unmark_finished_struct (t);
|
||
|
||
/* Now out of this class's scope. However, if this class defined
|
||
any new typedefs, then we must export those to the outer
|
||
binding level. This is unpleasant. */
|
||
x = gettags ();
|
||
|
||
popclass (0);
|
||
|
||
#if 0
|
||
/* Remove aggregate types from the list of tags,
|
||
since these appear at global scope. */
|
||
while (x && IS_AGGR_TYPE (TREE_VALUE (x)))
|
||
x = TREE_CHAIN (x);
|
||
CLASSTYPE_TAGS (t) = x;
|
||
y = x;
|
||
while (x)
|
||
{
|
||
if (IS_AGGR_TYPE (TREE_VALUE (x)))
|
||
TREE_CHAIN (y) = TREE_CHAIN (x);
|
||
x = TREE_CHAIN (x);
|
||
}
|
||
#endif
|
||
|
||
hack_incomplete_structures (t);
|
||
|
||
resume_momentary (old);
|
||
|
||
if (flag_cadillac)
|
||
cadillac_finish_struct (t);
|
||
|
||
return t;
|
||
}
|
||
|
||
/* Return non-zero if the effective type of INSTANCE is static.
|
||
Used to determine whether the virtual function table is needed
|
||
or not. */
|
||
int
|
||
resolves_to_fixed_type_p (instance)
|
||
tree instance;
|
||
{
|
||
switch (TREE_CODE (instance))
|
||
{
|
||
case ADDR_EXPR:
|
||
return resolves_to_fixed_type_p (TREE_OPERAND (instance, 0));
|
||
|
||
case COMPONENT_REF:
|
||
/* Don't let pointers to members look like they hold a fixed type. */
|
||
if (TREE_CODE (TREE_OPERAND (instance, 1)) != FIELD_DECL)
|
||
return 0;
|
||
|
||
case VAR_DECL:
|
||
case PARM_DECL:
|
||
case NEW_EXPR:
|
||
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
|
||
return 1;
|
||
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* Ordering function for overload resolution. */
|
||
int
|
||
rank_for_overload (x, y)
|
||
struct candidate *x, *y;
|
||
{
|
||
if (y->evil - x->evil)
|
||
return y->evil - x->evil;
|
||
if ((y->harshness[0] & 128) ^ (x->harshness[0] & 128))
|
||
return y->harshness[0] - x->harshness[0];
|
||
if (y->user - x->user)
|
||
return y->user - x->user;
|
||
if (y->b_or_d - x->b_or_d)
|
||
return y->b_or_d - x->b_or_d;
|
||
return y->easy - x->easy;
|
||
}
|
||
|
||
/* TYPE is the type we wish to convert to. PARM is the parameter
|
||
we have to work with. We use a somewhat arbitrary cost function
|
||
to measure this conversion. */
|
||
static int
|
||
convert_harshness (type, parmtype, parm)
|
||
register tree type, parmtype;
|
||
tree parm;
|
||
{
|
||
register enum tree_code codel = TREE_CODE (type);
|
||
register enum tree_code coder = TREE_CODE (parmtype);
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_convert_harshness++;
|
||
#endif
|
||
|
||
if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type))
|
||
return 0;
|
||
|
||
if (coder == ERROR_MARK)
|
||
return 1;
|
||
|
||
if (codel == POINTER_TYPE
|
||
&& (coder == METHOD_TYPE || coder == FUNCTION_TYPE))
|
||
{
|
||
tree p1, p2;
|
||
int harshness, new_harshness;
|
||
|
||
/* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be. */
|
||
type = TREE_TYPE (type);
|
||
|
||
if (coder != TREE_CODE (type))
|
||
return 1;
|
||
|
||
harshness = 0;
|
||
|
||
/* We allow the default conversion between function type
|
||
and pointer-to-function type for free. */
|
||
if (type == parmtype)
|
||
return 0;
|
||
|
||
/* Compare return types. */
|
||
harshness |= convert_harshness (TREE_TYPE (type), TREE_TYPE (parmtype), 0);
|
||
if (harshness & 1)
|
||
return 1;
|
||
p1 = TYPE_ARG_TYPES (type);
|
||
p2 = TYPE_ARG_TYPES (parmtype);
|
||
while (p1 && p2)
|
||
{
|
||
new_harshness = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2), 0);
|
||
if (new_harshness & 1)
|
||
return 1;
|
||
if ((new_harshness & 7) == 0)
|
||
harshness += new_harshness;
|
||
else
|
||
harshness |= new_harshness;
|
||
p1 = TREE_CHAIN (p1);
|
||
p2 = TREE_CHAIN (p2);
|
||
}
|
||
if (p1 == p2)
|
||
return harshness;
|
||
if (p2)
|
||
return 1;
|
||
if (p1)
|
||
return harshness | (TREE_PURPOSE (p1) == NULL_TREE);
|
||
}
|
||
else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
|
||
{
|
||
int harshness;
|
||
|
||
/* Get to the OFFSET_TYPE that this might be. */
|
||
type = TREE_TYPE (type);
|
||
|
||
if (coder != TREE_CODE (type))
|
||
return 1;
|
||
|
||
harshness = 0;
|
||
|
||
if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype))
|
||
harshness = 0;
|
||
else if (get_base_type (TYPE_OFFSET_BASETYPE (type),
|
||
TYPE_OFFSET_BASETYPE (parmtype), 0))
|
||
harshness = (1<<3);
|
||
else
|
||
return 1;
|
||
/* Now test the OFFSET_TYPE's target compatability. */
|
||
type = TREE_TYPE (type);
|
||
parmtype = TREE_TYPE (parmtype);
|
||
}
|
||
|
||
if (coder == UNKNOWN_TYPE)
|
||
{
|
||
if (codel == FUNCTION_TYPE
|
||
|| codel == METHOD_TYPE
|
||
|| (codel == POINTER_TYPE
|
||
&& (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|
||
|| TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)))
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
if (coder == VOID_TYPE)
|
||
return 1;
|
||
|
||
if (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE)
|
||
{
|
||
/* Control equivalence of ints an enums. */
|
||
|
||
if (codel == ENUMERAL_TYPE
|
||
&& flag_int_enum_equivalence == 0)
|
||
{
|
||
/* Enums can be converted to ints, but not vice-versa. */
|
||
if (coder != ENUMERAL_TYPE
|
||
|| TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (parmtype))
|
||
return 1;
|
||
}
|
||
|
||
/* else enums and ints (almost) freely interconvert. */
|
||
|
||
if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
|
||
{
|
||
int easy = TREE_UNSIGNED (type) ^ TREE_UNSIGNED (parmtype);
|
||
if (codel != coder)
|
||
easy += 1;
|
||
if (TYPE_MODE (type) != TYPE_MODE (parmtype))
|
||
easy += 2;
|
||
return (easy << 4);
|
||
}
|
||
else if (coder == REAL_TYPE)
|
||
return (4<<4);
|
||
}
|
||
|
||
if (codel == REAL_TYPE)
|
||
if (coder == REAL_TYPE)
|
||
/* Shun converting between float and double if a choice exists. */
|
||
{
|
||
if (TYPE_MODE (type) != TYPE_MODE (parmtype))
|
||
return (2<<4);
|
||
return 0;
|
||
}
|
||
else if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
|
||
return (4<<4);
|
||
|
||
/* convert arrays which have not previously been converted. */
|
||
if (codel == ARRAY_TYPE)
|
||
codel = POINTER_TYPE;
|
||
if (coder == ARRAY_TYPE)
|
||
coder = POINTER_TYPE;
|
||
|
||
/* Conversions among pointers */
|
||
if (codel == POINTER_TYPE && coder == POINTER_TYPE)
|
||
{
|
||
register tree ttl = TYPE_MAIN_VARIANT (TREE_TYPE (type));
|
||
register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
|
||
int penalty = 4 * (ttl != ttr);
|
||
/* Anything converts to void *. void * converts to anything.
|
||
Since these may be `const void *' (etc.) use VOID_TYPE
|
||
instead of void_type_node.
|
||
Otherwise, the targets must be the same,
|
||
except that we do allow (at some cost) conversion
|
||
between signed and unsinged pointer types. */
|
||
|
||
if ((TREE_CODE (ttl) == METHOD_TYPE
|
||
|| TREE_CODE (ttl) == FUNCTION_TYPE)
|
||
&& TREE_CODE (ttl) == TREE_CODE (ttr))
|
||
{
|
||
if (comptypes (ttl, ttr, -1))
|
||
return penalty<<4;
|
||
return 1;
|
||
}
|
||
|
||
if (!(TREE_CODE (ttl) == VOID_TYPE
|
||
|| TREE_CODE (ttr) == VOID_TYPE
|
||
|| (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (ttr)
|
||
&& (ttl = unsigned_type (ttl),
|
||
ttr = unsigned_type (ttr),
|
||
penalty = 10, 0))
|
||
|| (comp_target_types (ttl, ttr, 0))))
|
||
return 1;
|
||
|
||
if (ttr == ttl)
|
||
return 4;
|
||
|
||
if (IS_AGGR_TYPE (ttl) && IS_AGGR_TYPE (ttr))
|
||
{
|
||
int b_or_d = get_base_distance (ttl, ttr, 0, 0);
|
||
if (b_or_d < 0)
|
||
return 1;
|
||
return (b_or_d<<3) | 4;
|
||
}
|
||
|
||
return (penalty<<4);
|
||
}
|
||
|
||
if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
|
||
{
|
||
/* This is not a bad match, but don't let it beat
|
||
integer-enum combinations. */
|
||
if (parm && integer_zerop (parm))
|
||
return (4<<4);
|
||
}
|
||
|
||
/* C++: one of the types must be a reference type. */
|
||
{
|
||
tree ttl, ttr;
|
||
register tree intype = TYPE_MAIN_VARIANT (parmtype);
|
||
register enum tree_code form = TREE_CODE (intype);
|
||
int penalty;
|
||
|
||
if (codel == REFERENCE_TYPE || coder == REFERENCE_TYPE)
|
||
{
|
||
ttl = TYPE_MAIN_VARIANT (type);
|
||
|
||
if (codel == REFERENCE_TYPE)
|
||
{
|
||
ttl = TYPE_MAIN_VARIANT (TREE_TYPE (ttl));
|
||
|
||
if (form == OFFSET_TYPE)
|
||
{
|
||
intype = TREE_TYPE (intype);
|
||
form = TREE_CODE (intype);
|
||
}
|
||
|
||
if (form == REFERENCE_TYPE)
|
||
{
|
||
intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
|
||
|
||
if (ttl == intype)
|
||
return 0;
|
||
penalty = 2;
|
||
}
|
||
else
|
||
{
|
||
/* Can reference be built up? */
|
||
if (ttl == intype)
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
penalty = 2;
|
||
}
|
||
}
|
||
else if (form == REFERENCE_TYPE)
|
||
{
|
||
if (parm)
|
||
{
|
||
tree tmp = convert_from_reference (parm);
|
||
intype = TYPE_MAIN_VARIANT (TREE_TYPE (tmp));
|
||
}
|
||
else
|
||
{
|
||
intype = parmtype;
|
||
do
|
||
{
|
||
intype = TREE_TYPE (intype);
|
||
}
|
||
while (TREE_CODE (intype) == REFERENCE_TYPE);
|
||
intype = TYPE_MAIN_VARIANT (intype);
|
||
}
|
||
|
||
if (ttl == intype)
|
||
return 0;
|
||
else
|
||
penalty = 2;
|
||
}
|
||
|
||
if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
|
||
{
|
||
ttl = unsigned_type (ttl);
|
||
intype = unsigned_type (intype);
|
||
penalty += 2;
|
||
}
|
||
|
||
ttr = intype;
|
||
|
||
/* If the initializer is not an lvalue, then it does not
|
||
matter if we make life easier for the programmer
|
||
by creating a temporary variable with which to
|
||
hold the result. */
|
||
if (parm && (coder == INTEGER_TYPE
|
||
|| coder == ENUMERAL_TYPE
|
||
|| coder == REAL_TYPE)
|
||
&& ! lvalue_p (parm))
|
||
return (convert_harshness (ttl, ttr, 0) | (penalty << 4));
|
||
|
||
if (ttl == ttr)
|
||
return 4;
|
||
|
||
/* Pointers to voids always convert for pointers. But
|
||
make them less natural than more specific matches. */
|
||
if (TREE_CODE (ttl) == POINTER_TYPE && TREE_CODE (ttr) == POINTER_TYPE)
|
||
if (TREE_TYPE (ttl) == void_type_node
|
||
|| TREE_TYPE (ttr) == void_type_node)
|
||
return ((penalty+1)<<4);
|
||
|
||
if (parm && codel != REFERENCE_TYPE)
|
||
return (convert_harshness (ttl, ttr, 0) | (penalty << 4));
|
||
|
||
/* Here it does matter. If this conversion is from
|
||
derived to base, allow it. Otherwise, types must
|
||
be compatible in the strong sense. */
|
||
if (IS_AGGR_TYPE (ttl) && IS_AGGR_TYPE (ttr))
|
||
{
|
||
int b_or_d = get_base_distance (ttl, ttr, 0, 0);
|
||
if (b_or_d < 0)
|
||
return 1;
|
||
#if AMBIGUOUS_WORKING
|
||
if (ttl == TYPE_MAIN_VARIANT (type)
|
||
&& TYPE_GETS_INIT_REF (type))
|
||
return (b_or_d<<3) | 6;
|
||
#endif
|
||
return (b_or_d<<3) | 4;
|
||
}
|
||
|
||
if (comp_target_types (ttl, intype, 1))
|
||
return (penalty<<4);
|
||
}
|
||
}
|
||
if (codel == RECORD_TYPE && coder == RECORD_TYPE)
|
||
{
|
||
int b_or_d = get_base_distance (type, parmtype, 0, 0);
|
||
if (b_or_d < 0)
|
||
return 1;
|
||
#if AMBIGUOUS_WORKING
|
||
if (TYPE_GETS_INIT_REF (type))
|
||
return (b_or_d<<3) | 6;
|
||
#endif
|
||
return (b_or_d<<3) | 4;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/* Algorithm: Start out with no stikes against. For each argument
|
||
which requires a (subjective) hard conversion (such as between
|
||
floating point and integer), issue a strike. If there are the same
|
||
number of formal and actual parameters in the list, there will be at
|
||
least on strike, otherwise an exact match would have been found. If
|
||
there are not the same number of arguments in the type lists, we are
|
||
not dead yet: a `...' means that we can have more parms then were
|
||
declared, and if we wind up in the default argument section of the
|
||
list those can be used as well. If an exact match could be found for
|
||
one of those cases, return it immediately. Otherwise, Rank the fields
|
||
so that fields with fewer strikes are tried first.
|
||
|
||
Conversions between builtin and user-defined types are allowed, but
|
||
no function involving such a conversion is prefered to one which
|
||
does not require such a conversion. Furthermore, such conversions
|
||
must be unique. */
|
||
|
||
void
|
||
compute_conversion_costs (function, tta_in, cp, arglen)
|
||
tree function;
|
||
tree tta_in;
|
||
struct candidate *cp;
|
||
int arglen;
|
||
{
|
||
tree ttf_in = TYPE_ARG_TYPES (TREE_TYPE (function));
|
||
tree ttf = ttf_in;
|
||
tree tta = tta_in;
|
||
|
||
/* Start out with no strikes against. */
|
||
int evil_strikes = 0;
|
||
int user_strikes = 0;
|
||
int b_or_d_strikes = 0;
|
||
int easy_strikes = 0;
|
||
|
||
int strike_index = 0, win, lose;
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_compute_conversion_costs++;
|
||
#endif
|
||
|
||
cp->function = function;
|
||
cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
|
||
cp->u.bad_arg = 0; /* optimistic! */
|
||
|
||
bzero (cp->harshness, (arglen+1) * sizeof (short));
|
||
|
||
while (ttf && tta)
|
||
{
|
||
int harshness;
|
||
|
||
if (ttf == void_list_node)
|
||
break;
|
||
|
||
if (type_unknown_p (TREE_VALUE (tta)))
|
||
{
|
||
/* Must perform some instantiation here. */
|
||
tree rhs = TREE_VALUE (tta);
|
||
tree lhstype = TREE_VALUE (ttf);
|
||
|
||
/* @@ This is to undo what `grokdeclarator' does to
|
||
parameter types. It really should go through
|
||
something more general. */
|
||
|
||
TREE_TYPE (tta) = unknown_type_node;
|
||
if (TREE_CODE (rhs) == OP_IDENTIFIER)
|
||
rhs = build_instantiated_decl (lhstype, rhs);
|
||
else
|
||
{
|
||
/* Keep quiet about possible contravariance violations. */
|
||
extern int inhibit_warnings;
|
||
int old_inhibit_warnings = inhibit_warnings;
|
||
inhibit_warnings = 1;
|
||
|
||
rhs = instantiate_type (lhstype, rhs, 0);
|
||
|
||
inhibit_warnings = old_inhibit_warnings;
|
||
}
|
||
|
||
if (TREE_CODE (rhs) == ERROR_MARK)
|
||
harshness = 1;
|
||
else
|
||
{
|
||
harshness = convert_harshness (lhstype, TREE_TYPE (rhs), rhs);
|
||
/* harshness |= 2; */
|
||
}
|
||
}
|
||
else
|
||
harshness = convert_harshness (TREE_VALUE (ttf), TREE_TYPE (TREE_VALUE (tta)), TREE_VALUE (tta));
|
||
|
||
cp->harshness[strike_index] = harshness;
|
||
if (harshness & 1)
|
||
{
|
||
cp->u.bad_arg = strike_index;
|
||
evil_strikes = 1;
|
||
}
|
||
else if (harshness & 2)
|
||
{
|
||
user_strikes += 1;
|
||
}
|
||
else if (harshness & 4)
|
||
{
|
||
b_or_d_strikes += (harshness >> 3);
|
||
}
|
||
else
|
||
easy_strikes += harshness >> 4;
|
||
ttf = TREE_CHAIN (ttf);
|
||
tta = TREE_CHAIN (tta);
|
||
strike_index += 1;
|
||
}
|
||
|
||
if (tta)
|
||
{
|
||
/* ran out of formals, and parmlist is fixed size. */
|
||
if (ttf /* == void_type_node */)
|
||
{
|
||
cp->evil = 1;
|
||
cp->u.bad_arg = -1;
|
||
return;
|
||
}
|
||
}
|
||
else if (ttf && ttf != void_list_node)
|
||
{
|
||
/* ran out of actuals, and no defaults. */
|
||
if (TREE_PURPOSE (ttf) == NULL_TREE)
|
||
{
|
||
cp->evil = 1;
|
||
cp->u.bad_arg = -2;
|
||
return;
|
||
}
|
||
/* Store index of first default. */
|
||
cp->harshness[arglen] = strike_index+1;
|
||
}
|
||
else cp->harshness[arglen] = 0;
|
||
|
||
/* Argument list lengths work out, so don't need to check them again. */
|
||
if (evil_strikes)
|
||
{
|
||
/* We do not check for derived->base conversions here, since in
|
||
no case would they give evil strike counts, unless such conversions
|
||
are somehow ambiguous. */
|
||
|
||
/* See if any user-defined conversions apply.
|
||
But make sure that we do not loop. */
|
||
static int dont_convert_types = 0;
|
||
|
||
if (dont_convert_types)
|
||
{
|
||
cp->evil = 1;
|
||
return;
|
||
}
|
||
|
||
win = 0; /* Only get one chance to win. */
|
||
ttf = TYPE_ARG_TYPES (TREE_TYPE (function));
|
||
tta = tta_in;
|
||
strike_index = 0;
|
||
evil_strikes = 0;
|
||
|
||
while (ttf && tta)
|
||
{
|
||
if (ttf == void_list_node)
|
||
break;
|
||
|
||
lose = cp->harshness[strike_index];
|
||
if (lose&1)
|
||
{
|
||
tree actual_type = TREE_TYPE (TREE_VALUE (tta));
|
||
tree formal_type = TREE_VALUE (ttf);
|
||
|
||
dont_convert_types = 1;
|
||
|
||
if (TREE_CODE (formal_type) == REFERENCE_TYPE)
|
||
formal_type = TREE_TYPE (formal_type);
|
||
if (TREE_CODE (actual_type) == REFERENCE_TYPE)
|
||
actual_type = TREE_TYPE (actual_type);
|
||
|
||
if (formal_type != error_mark_node
|
||
&& actual_type != error_mark_node)
|
||
{
|
||
formal_type = TYPE_MAIN_VARIANT (formal_type);
|
||
actual_type = TYPE_MAIN_VARIANT (actual_type);
|
||
|
||
if (TYPE_HAS_CONSTRUCTOR (formal_type))
|
||
{
|
||
/* If it has a constructor for this type, try to use it. */
|
||
if (convert_to_aggr (formal_type, TREE_VALUE (tta), 0, 1)
|
||
!= error_mark_node)
|
||
{
|
||
/* @@ There is no way to save this result yet.
|
||
@@ So success is NULL_TREE for now. */
|
||
win++;
|
||
}
|
||
}
|
||
if (TYPE_LANG_SPECIFIC (actual_type) && TYPE_HAS_CONVERSION (actual_type))
|
||
{
|
||
if (TREE_CODE (formal_type) == INTEGER_TYPE
|
||
&& TYPE_HAS_INT_CONVERSION (actual_type))
|
||
win++;
|
||
else if (TREE_CODE (formal_type) == REAL_TYPE
|
||
&& TYPE_HAS_REAL_CONVERSION (actual_type))
|
||
win++;
|
||
else
|
||
{
|
||
tree conv = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_VALUE (tta), 0);
|
||
if (conv)
|
||
{
|
||
if (conv == error_mark_node)
|
||
win += 2;
|
||
else
|
||
win++;
|
||
}
|
||
else if (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE)
|
||
{
|
||
conv = build_type_conversion (CALL_EXPR, formal_type, TREE_VALUE (tta), 0);
|
||
if (conv)
|
||
{
|
||
if (conv == error_mark_node)
|
||
win += 2;
|
||
else
|
||
win++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
dont_convert_types = 0;
|
||
|
||
if (win == 1)
|
||
{
|
||
user_strikes += 1;
|
||
cp->harshness[strike_index] = 2;
|
||
win = 0;
|
||
}
|
||
else
|
||
{
|
||
if (cp->u.bad_arg > strike_index)
|
||
cp->u.bad_arg = strike_index;
|
||
|
||
evil_strikes = win ? 2 : 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ttf = TREE_CHAIN (ttf);
|
||
tta = TREE_CHAIN (tta);
|
||
strike_index += 1;
|
||
}
|
||
}
|
||
|
||
/* Calling a non-const member function from a const member function
|
||
is probably invalid, but for now we let it only draw a warning.
|
||
We indicate that such a mismatch has occured by setting the
|
||
harshness to a maximum value. */
|
||
if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE
|
||
&& TREE_CODE (TREE_TYPE (TREE_VALUE (tta_in))) == POINTER_TYPE
|
||
&& (TREE_READONLY (TREE_TYPE (TREE_TYPE (TREE_VALUE (tta_in))))
|
||
> TREE_READONLY (TREE_TYPE (TREE_VALUE (ttf_in)))))
|
||
cp->harshness[0] |= 128;
|
||
|
||
cp->evil = evil_strikes;
|
||
cp->user = user_strikes;
|
||
cp->b_or_d = b_or_d_strikes;
|
||
cp->easy = easy_strikes;
|
||
}
|
||
|
||
struct candidate *
|
||
ideal_candidate (basetype, candidates, n_candidates, parms, len)
|
||
tree basetype;
|
||
struct candidate *candidates;
|
||
int n_candidates;
|
||
tree parms;
|
||
int len;
|
||
{
|
||
struct candidate *cp = candidates + n_candidates;
|
||
int index, i;
|
||
tree ttf;
|
||
|
||
qsort (candidates, /* char *base */
|
||
n_candidates, /* int nel */
|
||
sizeof (struct candidate), /* int width */
|
||
rank_for_overload); /* int (*compar)() */
|
||
|
||
/* If the best candidate requires user-defined conversions,
|
||
and its user-defined conversions are a strict subset
|
||
of all other candidates requiring user-defined conversions,
|
||
then it is, in fact, the best. */
|
||
for (i = -1; cp + i != candidates; i--)
|
||
if (cp[i].user == 0)
|
||
break;
|
||
|
||
if (i < -1)
|
||
{
|
||
tree ttf0;
|
||
|
||
/* Check that every other candidate requires those conversions
|
||
as a strict subset of their conversions. */
|
||
if (cp[i].user == cp[-1].user)
|
||
goto non_subset;
|
||
|
||
/* Look at subset relationship more closely. */
|
||
while (i != -1)
|
||
{
|
||
for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)),
|
||
ttf0 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function)),
|
||
index = 0;
|
||
index < len;
|
||
ttf = TREE_CHAIN (ttf), ttf0 = TREE_CHAIN (ttf0), index++)
|
||
if (cp[i].harshness[index] & 2)
|
||
{
|
||
/* If our "best" candidate also needs a conversion,
|
||
it must be the same one. */
|
||
if ((cp[-1].harshness[index] & 2)
|
||
&& TREE_VALUE (ttf) != TREE_VALUE (ttf0))
|
||
goto non_subset;
|
||
}
|
||
i++;
|
||
}
|
||
/* The best was the best. */
|
||
return cp - 1;
|
||
non_subset:
|
||
/* Use other rules for determining "bestness". */
|
||
;
|
||
}
|
||
|
||
/* If the best two candidates we find require user-defined
|
||
conversions, we may need to report and error message. */
|
||
if (cp[-1].user && cp[-2].user
|
||
&& (cp[-1].b_or_d || cp[-2].b_or_d == 0))
|
||
{
|
||
/* If the best two methods found involved user-defined
|
||
type conversions, then we must see whether one
|
||
of them is exactly what we wanted. If not, then
|
||
we have an ambiguity. */
|
||
int best = 0;
|
||
tree tta = parms;
|
||
tree f1, p1;
|
||
|
||
#if AMBIGUOUS_WORKING
|
||
if (cp[-1].b_or_d == 0
|
||
&& cp[-1].easy == 0
|
||
&& (cp[-2].b_or_d | cp[-2].easy) > 0)
|
||
return cp - 1;
|
||
#endif
|
||
|
||
/* Stash all of our parameters in safe places
|
||
so that we can perform type conversions in place. */
|
||
while (tta)
|
||
{
|
||
TREE_PURPOSE (tta) = TREE_VALUE (tta);
|
||
tta = TREE_CHAIN (tta);
|
||
}
|
||
|
||
i = 0;
|
||
do
|
||
{
|
||
int exact_conversions = 0;
|
||
|
||
i -= 1;
|
||
tta = parms;
|
||
if (DECL_STATIC_FUNCTION_P (cp[i].function))
|
||
tta = TREE_CHAIN (tta);
|
||
for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)), index = 0;
|
||
index < len;
|
||
tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
|
||
{
|
||
if (cp[i].harshness[index] & 2)
|
||
{
|
||
TREE_VALUE (tta)
|
||
= build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_PURPOSE (tta), 2);
|
||
if (TREE_VALUE (tta))
|
||
{
|
||
if (TREE_CODE (TREE_VALUE (tta)) != CONVERT_EXPR
|
||
&& (TREE_CODE (TREE_VALUE (tta)) != NOP_EXPR
|
||
|| comp_target_types (TREE_TYPE (TREE_VALUE (tta)),
|
||
TREE_TYPE (TREE_OPERAND (TREE_VALUE (tta), 0)), 1)))
|
||
exact_conversions += 1;
|
||
}
|
||
else if (IS_AGGR_TYPE (TREE_VALUE (ttf))
|
||
|| (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE
|
||
&& IS_AGGR_TYPE (TREE_TYPE (TREE_VALUE (ttf)))))
|
||
{
|
||
/* To get here we had to have succeeded via
|
||
a constructor. */
|
||
TREE_VALUE (tta) = TREE_PURPOSE (tta);
|
||
exact_conversions += 1;
|
||
}
|
||
}
|
||
}
|
||
if (exact_conversions == cp[i].user)
|
||
{
|
||
if (best == 0)
|
||
{
|
||
best = i;
|
||
f1 = cp[best].function;
|
||
p1 = TYPE_ARG_TYPES (TREE_TYPE (f1));
|
||
}
|
||
else
|
||
{
|
||
/* Don't complain if next best is from base class. */
|
||
tree f2 = cp[i].function;
|
||
tree p2 = TYPE_ARG_TYPES (TREE_TYPE (f2));
|
||
|
||
if (TREE_CODE (TREE_TYPE (f1)) == METHOD_TYPE
|
||
&& TREE_CODE (TREE_TYPE (f2)) == METHOD_TYPE
|
||
&& (cp[i].harshness[0] & 4) != 0
|
||
&& cp[best].harshness[0] < cp[i].harshness[0])
|
||
{
|
||
#if 0
|
||
/* For LUCID. */
|
||
if (! compparms (TREE_CHAIN (p1), TREE_CHAIN (p2), 1))
|
||
goto ret0;
|
||
else
|
||
#endif
|
||
continue;
|
||
}
|
||
else goto ret0;
|
||
}
|
||
}
|
||
} while (cp + i != candidates);
|
||
|
||
if (best)
|
||
{
|
||
int exact_conversions = cp[best].user;
|
||
tta = parms;
|
||
if (DECL_STATIC_FUNCTION_P (cp[best].function))
|
||
tta = TREE_CHAIN (parms);
|
||
for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[best].function)), index = 0;
|
||
exact_conversions > 0;
|
||
tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
|
||
{
|
||
if (cp[best].harshness[index] & 2)
|
||
{
|
||
/* We must now fill in the slot we left behind.
|
||
@@ This could be optimized to use the value previously
|
||
@@ computed by build_type_conversion in some cases. */
|
||
TREE_VALUE (tta) = convert (TREE_VALUE (ttf), TREE_PURPOSE (tta));
|
||
exact_conversions -= 1;
|
||
}
|
||
else TREE_VALUE (tta) = TREE_PURPOSE (tta);
|
||
}
|
||
return cp + best;
|
||
}
|
||
goto ret0;
|
||
}
|
||
/* If the best two candidates we find both use default parameters,
|
||
we may need to report and error. Don't need to worry if next-best
|
||
candidate is forced to use user-defined conversion when best is not. */
|
||
if (cp[-2].user == 0
|
||
&& cp[-1].harshness[len] != 0 && cp[-2].harshness[len] != 0)
|
||
{
|
||
tree tt1 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function));
|
||
tree tt2 = TYPE_ARG_TYPES (TREE_TYPE (cp[-2].function));
|
||
int i = cp[-1].harshness[len];
|
||
if (cp[-2].harshness[len] < i)
|
||
i = cp[-2].harshness[len];
|
||
while (--i > 0)
|
||
{
|
||
if (TYPE_MAIN_VARIANT (TREE_VALUE (tt1))
|
||
!= TYPE_MAIN_VARIANT (TREE_VALUE (tt2)))
|
||
/* These lists are not identical, so we can choose our best candidate. */
|
||
return cp - 1;
|
||
tt1 = TREE_CHAIN (tt1);
|
||
tt2 = TREE_CHAIN (tt2);
|
||
}
|
||
/* To get here, both lists had the same parameters up to the defaults
|
||
which were used. This is an ambiguous request. */
|
||
goto ret0;
|
||
}
|
||
|
||
/* Otherwise, return our best candidate. Note that if we get candidates
|
||
from independent base classes, we have an ambiguity, even if one
|
||
argument list look a little better than another one. */
|
||
if (cp[-1].b_or_d && basetype && TYPE_USES_MULTIPLE_INHERITANCE (basetype))
|
||
{
|
||
int i = n_candidates - 1, best;
|
||
tree base1 = NULL_TREE;
|
||
|
||
if (TREE_CODE (TREE_TYPE (candidates[i].function)) == FUNCTION_TYPE)
|
||
return cp - 1;
|
||
|
||
for (; i >= 0 && candidates[i].user == 0 && candidates[i].evil == 0; i--)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (candidates[i].function)) == METHOD_TYPE)
|
||
{
|
||
tree newbase = TYPE_METHOD_BASETYPE (TREE_TYPE (candidates[i].function));
|
||
|
||
if (base1 != NULL_TREE)
|
||
{
|
||
if (newbase != base1
|
||
&& ! get_base_type (newbase, base1, 0))
|
||
{
|
||
char *buf = (char *)alloca (8192);
|
||
error ("ambiguous request for function from distinct base classes of type `%s'", TYPE_NAME_STRING (basetype));
|
||
error ("first candidate is `%s'", fndecl_as_string (buf, 0, candidates[best].function, 1));
|
||
error ("second candidates is `%s'", fndecl_as_string (buf, 0, candidates[i].function, 1));
|
||
return cp - 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
best = i;
|
||
base1 = newbase;
|
||
}
|
||
}
|
||
else return cp - 1;
|
||
}
|
||
}
|
||
|
||
#if AMBIGUOUS_WORKING
|
||
if (cp[-1].user == cp[-2].user
|
||
&& cp[-1].b_or_d == cp[-2].b_or_d
|
||
&& cp[-1].easy == cp[-2].easy)
|
||
goto ret0;
|
||
#endif
|
||
|
||
return cp - 1;
|
||
|
||
ret0:
|
||
/* In the case where there is no ideal candidate, restore
|
||
TREE_VALUE slots of PARMS from TREE_PURPOSE slots. */
|
||
while (parms)
|
||
{
|
||
TREE_VALUE (parms) = TREE_PURPOSE (parms);
|
||
parms = TREE_CHAIN (parms);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Assume that if the class referred to is not in the
|
||
current class hierarchy, that it may be remote.
|
||
PARENT is assumed to be of aggregate type here. */
|
||
static int
|
||
may_be_remote (parent)
|
||
tree parent;
|
||
{
|
||
if (TYPE_OVERLOADS_METHOD_CALL_EXPR (parent) == 0)
|
||
return 0;
|
||
|
||
if (current_class_type == NULL_TREE)
|
||
return 0;
|
||
if (parent == current_class_type)
|
||
return 0;
|
||
|
||
if (get_base_type (parent, current_class_type, 0))
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
/* Return the number of bytes that the arglist in PARMS would
|
||
occupy on the stack. */
|
||
int
|
||
get_arglist_len_in_bytes (parms)
|
||
tree parms;
|
||
{
|
||
register tree parm;
|
||
register int bytecount = 0;
|
||
|
||
for (parm = parms; parm; parm = TREE_CHAIN (parm))
|
||
{
|
||
register tree pval = TREE_VALUE (parm);
|
||
register int used, size;
|
||
|
||
if (TREE_CODE (pval) == ERROR_MARK)
|
||
continue;
|
||
else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
|
||
{
|
||
used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval)));
|
||
#ifdef PUSH_ROUNDING
|
||
size = PUSH_ROUNDING (size);
|
||
#endif
|
||
used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
|
||
/ (PARM_BOUNDARY / BITS_PER_UNIT))
|
||
* (PARM_BOUNDARY / BITS_PER_UNIT));
|
||
}
|
||
else
|
||
{
|
||
register tree size = size_in_bytes (TREE_TYPE (pval));
|
||
register tree used_t = convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY),
|
||
PARM_BOUNDARY, BITS_PER_UNIT);
|
||
used = TREE_INT_CST_LOW (used_t);
|
||
}
|
||
bytecount += used;
|
||
}
|
||
return bytecount;
|
||
}
|
||
|
||
tree
|
||
build_vfield_ref (datum, type)
|
||
tree datum, type;
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
|
||
datum = convert_from_reference (datum);
|
||
|
||
if (! TYPE_USES_VIRTUAL_BASECLASSES (type))
|
||
return build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
|
||
datum, CLASSTYPE_VFIELD (type));
|
||
return build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), 0, 0);
|
||
}
|
||
|
||
/* Build a call to a member of an object. I.e., one that overloads
|
||
operator ()(), or is a pointer-to-function or pointer-to-method. */
|
||
static tree
|
||
build_field_call (basetype_path, instance_ptr, name, parms, err_name)
|
||
tree basetype_path;
|
||
tree instance_ptr, name, parms;
|
||
char *err_name;
|
||
{
|
||
tree field, instance;
|
||
|
||
if (instance_ptr == current_class_decl)
|
||
{
|
||
/* Check to see if we really have a reference to an instance variable
|
||
with `operator()()' overloaded. */
|
||
#if 1
|
||
field = IDENTIFIER_CLASS_VALUE (name);
|
||
#else
|
||
field = identifier_class_value (name);
|
||
#endif
|
||
|
||
if (field == NULL_TREE)
|
||
{
|
||
error ("`this' has no member named `%s'", err_name);
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_CODE (field) == FIELD_DECL)
|
||
{
|
||
/* If it's a field, try overloading operator (),
|
||
or calling if the field is a pointer-to-function. */
|
||
instance = build_component_ref_1 (C_C_D, field, 0, 1);
|
||
if (instance == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
|
||
&& TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (instance)))
|
||
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, instance, parms);
|
||
|
||
if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
|
||
if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
|
||
return build_function_call (instance, parms);
|
||
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
|
||
return build_function_call (instance, tree_cons (NULL_TREE, current_class_decl, parms));
|
||
}
|
||
return NULL_TREE;
|
||
}
|
||
|
||
/* Check to see if this is not really a reference to an instance variable
|
||
with `operator()()' overloaded. */
|
||
field = lookup_field (basetype_path, name, 1);
|
||
|
||
/* This can happen if the reference was ambiguous
|
||
or for visibility violations. */
|
||
if (field == error_mark_node)
|
||
return error_mark_node;
|
||
if (field)
|
||
{
|
||
tree basetype;
|
||
tree ftype = TREE_TYPE (field);
|
||
|
||
if (TYPE_LANG_SPECIFIC (ftype) && TYPE_OVERLOADS_CALL_EXPR (ftype))
|
||
{
|
||
/* Make the next search for this field very short. */
|
||
basetype = DECL_FIELD_CONTEXT (field);
|
||
instance_ptr = convert_pointer_to (basetype, instance_ptr);
|
||
|
||
instance = build_indirect_ref (instance_ptr, 0);
|
||
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
|
||
build_component_ref_1 (instance, field, 0, 0),
|
||
parms);
|
||
}
|
||
if (TREE_CODE (ftype) == POINTER_TYPE)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (ftype)) == FUNCTION_TYPE
|
||
|| TREE_CODE (TREE_TYPE (ftype)) == METHOD_TYPE)
|
||
{
|
||
/* This is a member which is a pointer to function. */
|
||
tree ref = build_component_ref_1 (build_indirect_ref (instance_ptr, 0, 0),
|
||
field, LOOKUP_COMPLAIN);
|
||
if (ref == error_mark_node)
|
||
return error_mark_node;
|
||
return build_function_call (ref, parms);
|
||
}
|
||
}
|
||
else if (TREE_CODE (ftype) == METHOD_TYPE)
|
||
{
|
||
error ("invalid call via pointer-to-member function");
|
||
return error_mark_node;
|
||
}
|
||
else
|
||
return NULL_TREE;
|
||
}
|
||
return NULL_TREE;
|
||
}
|
||
|
||
/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
|
||
This is how virtual function calls are avoided. */
|
||
tree
|
||
build_scoped_method_call (exp, scopes, name, parms)
|
||
tree exp;
|
||
tree scopes;
|
||
tree name;
|
||
tree parms;
|
||
{
|
||
/* Because this syntactic form does not allow
|
||
a pointer to a base class to be `stolen',
|
||
we need not protect the drived->base conversion
|
||
that happens here.
|
||
|
||
@@ But we do have to check visibility privileges later. */
|
||
tree basename = (TREE_CODE (scopes) == SCOPE_REF) ? TREE_OPERAND (scopes, 1) : scopes;
|
||
tree basetype, decl;
|
||
tree type = TREE_TYPE (exp);
|
||
|
||
if (type == error_mark_node
|
||
|| ! is_aggr_typedef (basename, 1))
|
||
return error_mark_node;
|
||
|
||
if (! IS_AGGR_TYPE (type))
|
||
{
|
||
error ("base object of scoped method call is not of aggregate type");
|
||
return error_mark_node;
|
||
}
|
||
|
||
basetype = TREE_TYPE (TREE_TYPE (basename));
|
||
|
||
if (basetype = basetype_or_else (basetype, type))
|
||
{
|
||
if (basetype == error_mark_node)
|
||
return error_mark_node;
|
||
if (TREE_CODE (exp) == INDIRECT_REF)
|
||
decl = build_indirect_ref (convert_pointer_to (basetype,
|
||
build_unary_op (ADDR_EXPR, exp, 0)), 0);
|
||
else
|
||
decl = build_scoped_ref (exp, scopes);
|
||
|
||
/* Call to a destructor. */
|
||
if (TREE_CODE (name) == BIT_NOT_EXPR)
|
||
{
|
||
/* Explicit call to destructor. */
|
||
name = TREE_OPERAND (name, 0);
|
||
if (! is_aggr_typedef (name, 1))
|
||
return error_mark_node;
|
||
if (TREE_TYPE (decl) != TREE_TYPE (TREE_TYPE (name)))
|
||
{
|
||
error_with_aggr_type (TREE_TYPE (decl),
|
||
"qualified type `%s' does not match destructor type `%s'",
|
||
IDENTIFIER_POINTER (name));
|
||
return error_mark_node;
|
||
}
|
||
if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
|
||
error_with_aggr_type (TREE_TYPE (decl), "type `%s' has no destructor");
|
||
return build_delete (TREE_TYPE (decl), decl, integer_two_node,
|
||
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
|
||
}
|
||
|
||
/* Call to a method. */
|
||
return build_method_call (decl, name, parms, NULL_TREE,
|
||
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
|
||
}
|
||
return error_mark_node;
|
||
}
|
||
|
||
/* Build something of the form ptr->method (args)
|
||
or object.method (args). This can also build
|
||
calls to constructors, and find friends.
|
||
|
||
Member functions always take their class variable
|
||
as a pointer.
|
||
|
||
INSTANCE is a class instance.
|
||
|
||
NAME is the NAME field of the struct, union, or class
|
||
whose type is that of INSTANCE.
|
||
|
||
PARMS help to figure out what that NAME really refers to.
|
||
|
||
BASETYPE_PATH, if non-NULL, tells which basetypes of INSTANCE
|
||
we should be traversed before starting our search. We need
|
||
this information to get protected accesses correct.
|
||
|
||
FLAGS is the logical disjunction of zero or more LOOKUP_
|
||
flags. See cplus-tree.h for more info.
|
||
|
||
If this is all OK, calls build_function_call with the resolved
|
||
member function.
|
||
|
||
This function must also handle being called to perform
|
||
initialization, promotion/coercion of arguments, and
|
||
instantiation of default parameters.
|
||
|
||
Note that NAME may refer to an instance variable name. If
|
||
`operator()()' is defined for the type of that field, then we return
|
||
that result. */
|
||
tree
|
||
build_method_call (instance, name, parms, basetype_path, flags)
|
||
tree instance, name, parms, basetype_path;
|
||
int flags;
|
||
{
|
||
register tree function, fntype, value_type;
|
||
register tree basetype, save_basetype;
|
||
register tree baselink, result, method_name, parmtypes, parm;
|
||
tree last;
|
||
int pass;
|
||
enum visibility_type visibility;
|
||
int rank_for_overload ();
|
||
|
||
/* Range of cases for vtable optimization. */
|
||
enum vtable_needs
|
||
{
|
||
not_needed, maybe_needed, unneeded, needed,
|
||
};
|
||
enum vtable_needs need_vtbl = not_needed;
|
||
|
||
char *err_name;
|
||
char *name_kind;
|
||
int ever_seen = 0;
|
||
int wrap;
|
||
tree wrap_type;
|
||
tree instance_ptr = NULL_TREE;
|
||
int all_virtual = flag_all_virtual;
|
||
int static_call_context;
|
||
tree saw_private = 0;
|
||
tree saw_protected = 0;
|
||
#ifdef SOS
|
||
/* If call is a call to a constructor, then `dtbl'
|
||
will first be initialized with the function table pointer
|
||
of the appropriate type (calling "sosFindCode" as a last
|
||
resort), the the call to the constructor will go through there. */
|
||
tree dtbl = (flags & LOOKUP_DYNAMIC) ? TREE_VALUE (parms) : NULL_TREE;
|
||
|
||
/* Flag saying whether or not `dtbl' has been inserted into the
|
||
parameter list. This is needed because we cannot tell (until
|
||
we have a match) whether this parameter should go in or not.
|
||
|
||
If 1, then `dtbl' is living naturally.
|
||
If 0, then `dtbl' is not among the parms that we know about.
|
||
If -1, the `dtbl' was place into the parms unnaturally.
|
||
|
||
Note that we may side-effect the parameter list, but in such a way
|
||
that the caller of this function would never know. */
|
||
int dtbl_inserted = (flags & LOOKUP_DYNAMIC);
|
||
#endif
|
||
|
||
/* Keep track of `const' and `volatile' objects. */
|
||
int constp, volatilep;
|
||
|
||
/* Know if this is explicit destructor call. */
|
||
int dtor_specd = 0;
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_build_method_call++;
|
||
#endif
|
||
|
||
if (instance == error_mark_node
|
||
|| name == error_mark_node
|
||
|| parms == error_mark_node
|
||
|| (instance != 0 && TREE_TYPE (instance) == error_mark_node))
|
||
return error_mark_node;
|
||
|
||
#if 0
|
||
/* C++ 2.1 does not allow this, but ANSI probably will. */
|
||
if (TREE_CODE (name) == BIT_NOT_EXPR)
|
||
{
|
||
error ("invalid call to destructor, use qualified name `%s::~%s'",
|
||
IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (name));
|
||
return error_mark_node;
|
||
}
|
||
#else
|
||
if (TREE_CODE (name) == BIT_NOT_EXPR)
|
||
{
|
||
flags |= LOOKUP_DESTRUCTOR;
|
||
name = TREE_OPERAND (name, 0);
|
||
if (! is_aggr_typedef (name, 1))
|
||
return error_mark_node;
|
||
if (parms)
|
||
error ("destructors take no parameters");
|
||
basetype = TREE_TYPE (TREE_TYPE (name));
|
||
if (! TYPE_HAS_DESTRUCTOR (basetype))
|
||
error_with_aggr_type (basetype, "type `%s' has no destructor");
|
||
instance = default_conversion (instance);
|
||
if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
|
||
instance_ptr = instance;
|
||
else
|
||
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
|
||
return build_delete (basetype, instance_ptr, integer_two_node,
|
||
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
|
||
}
|
||
#endif
|
||
|
||
if (TREE_CODE (name) == WRAPPER_EXPR)
|
||
{
|
||
wrap_type = TREE_OPERAND (name, 0);
|
||
name = TREE_OPERAND (name, 1);
|
||
wrap = 1;
|
||
}
|
||
else if (TREE_CODE (name) == ANTI_WRAPPER_EXPR)
|
||
{
|
||
wrap_type = TREE_OPERAND (name, 0);
|
||
name = TREE_OPERAND (name, 1);
|
||
wrap = -1;
|
||
}
|
||
else
|
||
{
|
||
wrap_type = NULL_TREE;
|
||
wrap = 0;
|
||
}
|
||
|
||
/* Initialize name for error reporting. */
|
||
if (TREE_CODE (name) == OP_IDENTIFIER)
|
||
name = build_operator_fnname (&name, parms, 1);
|
||
|
||
if (OPERATOR_NAME_P (name))
|
||
{
|
||
char *p = operator_name_string (name);
|
||
err_name = (char *)alloca (strlen (p) + 10);
|
||
sprintf (err_name, "operator %s", p);
|
||
}
|
||
else if (name == wrapper_name)
|
||
err_name = "wrapper";
|
||
else if (OPERATOR_TYPENAME_P (name))
|
||
err_name = "type conversion operator";
|
||
else if (TREE_CODE (name) == SCOPE_REF)
|
||
err_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));
|
||
else
|
||
err_name = IDENTIFIER_POINTER (name);
|
||
|
||
#ifdef FIELD_XREF
|
||
FIELD_xref_call(current_function_decl,err_name);
|
||
#endif
|
||
|
||
if (wrap)
|
||
{
|
||
char *p = (char *)alloca (strlen (err_name) + 32);
|
||
sprintf (p, "%s for `%s'", wrap < 0 ? "anti-wrapper" : "wrapper", err_name);
|
||
err_name = p;
|
||
}
|
||
|
||
if (instance == NULL_TREE)
|
||
{
|
||
static_call_context = 0;
|
||
|
||
basetype = NULL_TREE;
|
||
/* Check cases where this is really a call to raise
|
||
an exception. */
|
||
if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)
|
||
{
|
||
basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));
|
||
if (basetype)
|
||
basetype = TREE_VALUE (basetype);
|
||
}
|
||
else if (TREE_CODE (name) == SCOPE_REF
|
||
&& TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
|
||
{
|
||
if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))
|
||
return error_mark_node;
|
||
basetype = purpose_member (TREE_OPERAND (name, 1),
|
||
CLASSTYPE_TAGS (TREE_TYPE (TREE_TYPE (TREE_OPERAND (name, 0)))));
|
||
if (basetype)
|
||
basetype = TREE_VALUE (basetype);
|
||
}
|
||
|
||
if (basetype != NULL_TREE)
|
||
;
|
||
/* call to a constructor... */
|
||
else if (TREE_TYPE (name))
|
||
basetype = TREE_TYPE (TREE_TYPE (name));
|
||
else
|
||
{
|
||
tree typedef_name = lookup_name (name);
|
||
if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)
|
||
{
|
||
/* Cannonicalize the typedef name. */
|
||
basetype = TREE_TYPE (typedef_name);
|
||
name = DECL_NAME (TYPE_NAME (basetype));
|
||
}
|
||
else
|
||
{
|
||
error ("no constructor named `%s' in visible scope",
|
||
IDENTIFIER_POINTER (name));
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
if (wrap_type && wrap_type != basetype)
|
||
{
|
||
error_with_aggr_type (wrap_type, "invalid constructor `%s::%s'",
|
||
TYPE_NAME_STRING (basetype));
|
||
return error_mark_node;
|
||
}
|
||
if (TYPE_VIRTUAL_P (basetype))
|
||
{
|
||
wrap_type = basetype;
|
||
}
|
||
|
||
if (! IS_AGGR_TYPE (basetype))
|
||
{
|
||
non_aggr_error:
|
||
if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
|
||
error ("request for member `%s' in something not a structure or union", err_name);
|
||
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
else if (instance == C_C_D || instance == current_class_decl)
|
||
{
|
||
extern tree ctor_label, dtor_label;
|
||
|
||
/* When doing initialization, we side-effect the TREE_TYPE of
|
||
C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE. */
|
||
basetype = TREE_TYPE (C_C_D);
|
||
|
||
/* Anything manifestly `this' in constructors and destructors
|
||
has a known type, so virtual function tables are not needed. */
|
||
if (TYPE_VIRTUAL_P (basetype)
|
||
&& !(flags & LOOKUP_NONVIRTUAL)
|
||
&& wrap_type == NULL_TREE)
|
||
need_vtbl = (dtor_label || ctor_label)
|
||
? unneeded : maybe_needed;
|
||
|
||
static_call_context = 0;
|
||
instance = C_C_D;
|
||
instance_ptr = current_class_decl;
|
||
result = build_field_call (CLASSTYPE_AS_LIST (current_class_type),
|
||
instance_ptr, name, parms, err_name);
|
||
|
||
if (result)
|
||
return result;
|
||
}
|
||
else if (TREE_CODE (instance) == RESULT_DECL)
|
||
{
|
||
static_call_context = 0;
|
||
basetype = TREE_TYPE (instance);
|
||
if (wrap_type)
|
||
{
|
||
if (basetype_or_else (basetype, wrap_type))
|
||
basetype = wrap_type;
|
||
else
|
||
return error_mark_node;
|
||
}
|
||
/* Should we ever have to make a virtual function reference
|
||
from a RESULT_DECL, know that it must be of fixed type
|
||
within the scope of this function. */
|
||
else if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
|
||
need_vtbl = maybe_needed;
|
||
instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (basetype), instance);
|
||
}
|
||
else if (instance == current_exception_object)
|
||
{
|
||
instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (current_exception_type),
|
||
TREE_OPERAND (current_exception_object, 0));
|
||
mark_addressable (TREE_OPERAND (current_exception_object, 0));
|
||
result = build_field_call (CLASSTYPE_AS_LIST (current_exception_type),
|
||
instance_ptr, name, parms, err_name);
|
||
if (result)
|
||
return result;
|
||
error ("exception member `%s' cannot be invoked", err_name);
|
||
return error_mark_node;
|
||
}
|
||
else
|
||
{
|
||
/* The MAIN_VARIANT of the type that `instance_ptr' winds up being. */
|
||
tree inst_ptr_basetype;
|
||
|
||
/* from the file "cplus-typeck.c". */
|
||
extern tree unary_complex_lvalue ();
|
||
|
||
static_call_context = (TREE_CODE (instance) == NOP_EXPR
|
||
&& TREE_OPERAND (instance, 0) == error_mark_node);
|
||
|
||
/* the base type of an instance variable is pointer to class */
|
||
basetype = TREE_TYPE (instance);
|
||
|
||
if (TREE_CODE (basetype) == REFERENCE_TYPE)
|
||
{
|
||
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (basetype));
|
||
if (! IS_AGGR_TYPE (basetype))
|
||
goto non_aggr_error;
|
||
/* Call to convert not needed because we are remaining
|
||
within the same type. */
|
||
instance_ptr = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), instance);
|
||
inst_ptr_basetype = basetype;
|
||
}
|
||
else
|
||
{
|
||
if (TREE_CODE (basetype) == POINTER_TYPE)
|
||
{
|
||
basetype = TREE_TYPE (basetype);
|
||
instance_ptr = instance;
|
||
}
|
||
|
||
if (! IS_AGGR_TYPE (basetype))
|
||
goto non_aggr_error;
|
||
|
||
if (! instance_ptr)
|
||
{
|
||
if ((lvalue_p (instance)
|
||
&& (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
|
||
|| (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
|
||
{
|
||
if (instance_ptr == error_mark_node)
|
||
return error_mark_node;
|
||
}
|
||
else if (TREE_CODE (instance) == NOP_EXPR
|
||
|| TREE_CODE (instance) == CONSTRUCTOR)
|
||
{
|
||
/* A cast is not an lvalue. Initialize a fresh temp
|
||
with the value we are casting from, and proceed with
|
||
that temporary. We can't cast to a reference type,
|
||
so that simplifies the initialization to something
|
||
we can manage. */
|
||
tree temp = get_temp_name (TREE_TYPE (instance), 0);
|
||
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
|
||
expand_aggr_init (temp, instance, 0);
|
||
else
|
||
{
|
||
store_init_value (temp, instance);
|
||
expand_decl_init (temp);
|
||
}
|
||
instance = temp;
|
||
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
|
||
}
|
||
else
|
||
{
|
||
assert (TREE_CODE (instance) == CALL_EXPR);
|
||
if (TYPE_NEEDS_CONSTRUCTOR (basetype))
|
||
instance = build_cplus_new (basetype, instance);
|
||
else
|
||
{
|
||
instance = get_temp_name (basetype, 0);
|
||
TREE_ADDRESSABLE (instance) = 1;
|
||
}
|
||
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
|
||
}
|
||
/* @@ Should we call comp_target_types here? */
|
||
inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
|
||
if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
|
||
basetype = inst_ptr_basetype;
|
||
else
|
||
instance_ptr = convert (TYPE_POINTER_TO (basetype), instance_ptr);
|
||
}
|
||
else
|
||
inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
|
||
}
|
||
|
||
if (basetype_path == NULL_TREE)
|
||
basetype_path = CLASSTYPE_AS_LIST (inst_ptr_basetype);
|
||
|
||
result = build_field_call (basetype_path, instance_ptr, name, parms, err_name);
|
||
if (result)
|
||
return result;
|
||
|
||
if (wrap_type)
|
||
{
|
||
if (basetype_or_else (basetype, wrap_type))
|
||
basetype = wrap_type;
|
||
else
|
||
return error_mark_node;
|
||
}
|
||
else if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
|
||
{
|
||
if (TREE_VOLATILE (instance_ptr))
|
||
{
|
||
/* This action is needed because the instance is needed
|
||
for providing the base of the virtual function table.
|
||
Without using a SAVE_EXPR, the function we are building
|
||
may be called twice, or side effects on the instance
|
||
variable (such as a post-increment), may happen twice. */
|
||
instance_ptr = save_expr (instance_ptr);
|
||
instance = build_indirect_ref (instance_ptr, 0);
|
||
}
|
||
else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
|
||
{
|
||
/* This happens when called for operator new (). */
|
||
instance = build_indirect_ref (instance, 0);
|
||
}
|
||
|
||
need_vtbl = maybe_needed;
|
||
}
|
||
}
|
||
|
||
if (TYPE_SIZE (basetype) == 0)
|
||
{
|
||
/* This is worth complaining about, I think. */
|
||
error_with_aggr_type (basetype, "cannot lookup method in incomplete type `%s'");
|
||
return error_mark_node;
|
||
}
|
||
|
||
/* Are we building a non-virtual wrapper? */
|
||
if (flags & LOOKUP_NONVIRTUAL)
|
||
{
|
||
if (all_virtual)
|
||
sorry ("non-virtual call with -fall-virtual");
|
||
if (wrap)
|
||
wrap_type = basetype;
|
||
}
|
||
|
||
save_basetype = basetype;
|
||
|
||
if (all_virtual == 1
|
||
&& (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT,
|
||
OPERATOR_METHOD_LENGTH)
|
||
|| instance_ptr == NULL_TREE
|
||
|| (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0
|
||
&& TYPE_NEEDS_WRAPPER (basetype) == 0)))
|
||
all_virtual = 0;
|
||
|
||
last = NULL_TREE;
|
||
for (parmtypes = 0, parm = parms; parm; parm = TREE_CHAIN (parm))
|
||
{
|
||
tree t = TREE_TYPE (TREE_VALUE (parm));
|
||
if (TREE_CODE (t) == OFFSET_TYPE)
|
||
{
|
||
/* Convert OFFSET_TYPE entities to their normal selves. */
|
||
TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
|
||
t = TREE_TYPE (TREE_VALUE (parm));
|
||
}
|
||
if (TREE_CODE (t) == ARRAY_TYPE)
|
||
{
|
||
/* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
|
||
This eliminates needless calls to `compute_conversion_costs'. */
|
||
TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
|
||
t = TREE_TYPE (TREE_VALUE (parm));
|
||
}
|
||
if (t == error_mark_node)
|
||
return error_mark_node;
|
||
last = build_tree_list (NULL_TREE, t);
|
||
parmtypes = chainon (parmtypes, last);
|
||
}
|
||
|
||
if (instance)
|
||
{
|
||
constp = TREE_READONLY (instance);
|
||
volatilep = TREE_THIS_VOLATILE (instance);
|
||
parms = tree_cons (NULL_TREE, instance_ptr, parms);
|
||
}
|
||
else
|
||
{
|
||
/* Raw constructors are always in charge. */
|
||
if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
|
||
&& ! (flags & LOOKUP_HAS_IN_CHARGE))
|
||
{
|
||
flags |= LOOKUP_HAS_IN_CHARGE;
|
||
parms = tree_cons (NULL_TREE, integer_one_node, parms);
|
||
parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
|
||
}
|
||
|
||
if (flag_this_is_variable)
|
||
{
|
||
constp = 0;
|
||
volatilep = 0;
|
||
parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms);
|
||
}
|
||
else
|
||
{
|
||
constp = 0;
|
||
volatilep = 0;
|
||
instance_ptr = build_new (NULL_TREE, basetype, void_type_node, 0);
|
||
if (instance_ptr == error_mark_node)
|
||
return error_mark_node;
|
||
instance_ptr = save_expr (instance_ptr);
|
||
TREE_CALLS_NEW (instance_ptr) = 1;
|
||
instance = build_indirect_ref (instance_ptr, 0);
|
||
parms = tree_cons (NULL_TREE, instance_ptr, parms);
|
||
}
|
||
}
|
||
parmtypes = tree_cons (NULL_TREE,
|
||
build_pointer_type (build_type_variant (basetype, constp, volatilep)),
|
||
parmtypes);
|
||
if (last == NULL_TREE)
|
||
last = parmtypes;
|
||
|
||
/* Look up function name in the structure type definition. */
|
||
|
||
if (wrap)
|
||
{
|
||
if (wrap > 0)
|
||
name_kind = "wrapper";
|
||
else
|
||
name_kind = "anti-wrapper";
|
||
baselink = get_wrapper (basetype);
|
||
}
|
||
else
|
||
{
|
||
if (TREE_TYPE (name)
|
||
&& TREE_CODE (TREE_TYPE (name)) == TYPE_DECL
|
||
&& IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (name))))
|
||
{
|
||
tree tmp = NULL_TREE;
|
||
if (TREE_TYPE (name) == TYPE_NAME (basetype))
|
||
tmp = basetype;
|
||
else
|
||
tmp = get_base_type (TREE_TYPE (TREE_TYPE (name)), basetype, 0);
|
||
if (tmp != 0)
|
||
{
|
||
name_kind = "constructor";
|
||
|
||
if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
|
||
&& ! (flags & LOOKUP_HAS_IN_CHARGE))
|
||
{
|
||
/* Constructors called for initialization
|
||
only are never in charge. */
|
||
tree tmplist;
|
||
|
||
flags |= LOOKUP_HAS_IN_CHARGE;
|
||
tmplist = tree_cons (NULL_TREE, integer_zero_node,
|
||
TREE_CHAIN (parms));
|
||
TREE_CHAIN (parms) = tmplist;
|
||
tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
|
||
TREE_CHAIN (parmtypes) = tmplist;
|
||
}
|
||
|
||
#ifdef SOS
|
||
if (TYPE_DYNAMIC (basetype) && dtbl_inserted == 0)
|
||
{
|
||
tree parm, parmtype;
|
||
dtbl = get_sos_dtable (basetype);
|
||
parm = tree_cons (NULL_TREE, dtbl, TREE_CHAIN (parms));
|
||
parmtype = tree_cons (NULL_TREE, build_pointer_type (ptr_type_node), TREE_CHAIN (parmtypes));
|
||
TREE_CHAIN (parms) = parm;
|
||
TREE_CHAIN (parmtypes) = parmtype;
|
||
dtbl_inserted = -1;
|
||
}
|
||
#endif
|
||
/* constructors are in very specific places. */
|
||
#ifdef SOS
|
||
if (dtbl_inserted == -1)
|
||
{
|
||
TREE_CHAIN (parmtypes) = TREE_CHAIN (TREE_CHAIN (parmtypes));
|
||
TREE_CHAIN (parms) = TREE_CHAIN (TREE_CHAIN (parms));
|
||
dtbl_inserted = 0;
|
||
}
|
||
#endif
|
||
basetype = tmp;
|
||
}
|
||
else
|
||
name_kind = "method";
|
||
}
|
||
else name_kind = "method";
|
||
|
||
if (basetype_path == NULL_TREE)
|
||
basetype_path = CLASSTYPE_AS_LIST (basetype);
|
||
result = lookup_fnfields (basetype_path, name,
|
||
(flags & LOOKUP_COMPLAIN));
|
||
if (result == error_mark_node)
|
||
return error_mark_node;
|
||
}
|
||
|
||
/* Now, go look for this method name. We do not find destructors here.
|
||
|
||
Putting `void_list_node' on the end of the parmtypes
|
||
fakes out `build_decl_overload' into doing the right thing. */
|
||
TREE_CHAIN (last) = void_list_node;
|
||
method_name = build_decl_overload (IDENTIFIER_POINTER (name),
|
||
parmtypes,
|
||
1 + (name == DECL_NAME (TYPE_NAME (save_basetype))));
|
||
TREE_CHAIN (last) = NULL_TREE;
|
||
|
||
for (pass = 0; pass < 2; pass++)
|
||
{
|
||
struct candidate *candidates;
|
||
struct candidate *cp;
|
||
int len, best = 2;
|
||
|
||
/* This increments every time we go up the type hierarchy.
|
||
The idea is to prefer a function of the derived class if possible. */
|
||
int b_or_d;
|
||
|
||
baselink = result;
|
||
|
||
if (pass > 0)
|
||
{
|
||
candidates = (struct candidate *) alloca ((ever_seen+1) * sizeof (struct candidate));
|
||
cp = candidates;
|
||
len = list_length (parms);
|
||
b_or_d = 0;
|
||
|
||
/* First see if a global function has a shot at it. */
|
||
if (flags & LOOKUP_GLOBAL)
|
||
{
|
||
tree friend_parms;
|
||
tree parm = TREE_VALUE (parms);
|
||
|
||
if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
|
||
friend_parms = parms;
|
||
else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
|
||
{
|
||
parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
|
||
parm = convert (build_reference_type (TREE_TYPE (parm)), parm);
|
||
friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
|
||
}
|
||
else
|
||
assert (0);
|
||
|
||
cp->harshness
|
||
= (unsigned short *)alloca ((len+1) * sizeof (short));
|
||
result = build_overload_call (name, friend_parms, 0, cp);
|
||
/* If it turns out to be the one we were actually looking for
|
||
(it was probably a friend function), the return the
|
||
good result. */
|
||
if (TREE_CODE (result) == CALL_EXPR)
|
||
return result;
|
||
|
||
while (cp->evil == 0)
|
||
{
|
||
/* non-standard uses: set the field to 0 to indicate
|
||
we are using a non-member function. */
|
||
cp->u.field = 0;
|
||
if (cp->harshness[len] == 0
|
||
&& cp->harshness[len] == 0
|
||
&& cp->user == 0 && cp->b_or_d == 0
|
||
&& cp->easy < best)
|
||
best = cp->easy;
|
||
cp += 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
while (baselink)
|
||
{
|
||
/* We have a hit (of sorts). If the parameter list is
|
||
"error_mark_node", or some variant thereof, it won't
|
||
match any methods. Since we have verified that the is
|
||
some method vaguely matching this one (in name at least),
|
||
silently return.
|
||
|
||
Don't stop for friends, however. */
|
||
tree basetypes = TREE_PURPOSE (baselink);
|
||
|
||
function = TREE_VALUE (baselink);
|
||
basetype = TREE_VALUE (basetypes);
|
||
|
||
/* Cast the instance variable to the approriate type. */
|
||
TREE_VALUE (parmtypes) = TYPE_POINTER_TO (basetype);
|
||
|
||
if (DESTRUCTOR_NAME_P (DECL_NAME (function)))
|
||
function = TREE_CHAIN (function);
|
||
|
||
for (; function; function = TREE_CHAIN (function))
|
||
{
|
||
#ifdef GATHER_STATISTICS
|
||
n_inner_fields_searched++;
|
||
#endif
|
||
ever_seen++;
|
||
|
||
/* Not looking for friends here. */
|
||
if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
|
||
&& ! DECL_STATIC_FUNCTION_P (function))
|
||
continue;
|
||
|
||
if (pass == 0
|
||
&& DECL_NAME (function) == method_name)
|
||
{
|
||
if (flags & LOOKUP_PROTECT)
|
||
{
|
||
visibility = compute_visibility (basetypes, function);
|
||
if (visibility == visibility_protected
|
||
&& flags & LOOKUP_PROTECTED_OK)
|
||
visibility = visibility_public;
|
||
}
|
||
|
||
if ((flags & LOOKUP_PROTECT) == 0
|
||
|| visibility == visibility_public)
|
||
goto found_and_ok;
|
||
else if (visibility == visibility_private)
|
||
saw_private = function;
|
||
else if (visibility == visibility_protected)
|
||
saw_protected = function;
|
||
/* If we fail on the exact match, we have
|
||
an immediate failure. */
|
||
goto found;
|
||
}
|
||
if (pass > 0)
|
||
{
|
||
tree these_parms = parms;
|
||
|
||
#ifdef GATHER_STATISTICS
|
||
n_inner_fields_searched++;
|
||
#endif
|
||
cp->harshness
|
||
= (unsigned short *)alloca ((len+1) * sizeof (short));
|
||
if (DECL_STATIC_FUNCTION_P (function))
|
||
these_parms = TREE_CHAIN (these_parms);
|
||
compute_conversion_costs (function, these_parms, cp, len);
|
||
cp->b_or_d += b_or_d;
|
||
if (cp->evil == 0)
|
||
{
|
||
cp->u.field = function;
|
||
cp->function = function;
|
||
if (flags & LOOKUP_PROTECT)
|
||
{
|
||
enum visibility_type this_v;
|
||
this_v = compute_visibility (basetypes, function);
|
||
if (this_v == visibility_protected
|
||
&& (flags & LOOKUP_PROTECTED_OK))
|
||
this_v = visibility_public;
|
||
if (this_v != visibility_public)
|
||
{
|
||
if (this_v == visibility_private)
|
||
saw_private = function;
|
||
else
|
||
saw_protected = function;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
/* No "two-level" conversions. */
|
||
if (flags & LOOKUP_NO_CONVERSION && cp->user != 0)
|
||
continue;
|
||
|
||
/* If we used default parameters, we must
|
||
check to see whether anyone else might
|
||
use them also, and report a possible
|
||
ambiguity. */
|
||
if (! TYPE_USES_MULTIPLE_INHERITANCE (save_basetype)
|
||
&& cp->harshness[len] == 0
|
||
&& (cp->harshness[0] & 128) == 0
|
||
&& cp->user == 0 && cp->b_or_d == 0
|
||
&& cp->easy < best)
|
||
{
|
||
if (! DECL_STATIC_FUNCTION_P (function))
|
||
TREE_VALUE (parms) = cp->arg;
|
||
if (best == 2)
|
||
goto found_and_maybe_warn;
|
||
}
|
||
cp++;
|
||
}
|
||
}
|
||
}
|
||
/* Now we have run through one link's member functions.
|
||
arrange to head-insert this link's links. */
|
||
baselink = next_baselink (baselink);
|
||
b_or_d += 1;
|
||
}
|
||
if (pass == 0)
|
||
{
|
||
/* No exact match could be found. Now try to find match
|
||
using default conversions. */
|
||
if ((flags & LOOKUP_GLOBAL) && IDENTIFIER_GLOBAL_VALUE (name))
|
||
if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (name)) == FUNCTION_DECL)
|
||
ever_seen += 1;
|
||
else if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (name)) == TREE_LIST)
|
||
ever_seen += list_length (IDENTIFIER_GLOBAL_VALUE (name));
|
||
|
||
if (ever_seen == 0)
|
||
{
|
||
if (flags & LOOKUP_GLOBAL)
|
||
error ("no global or member function `%s' defined", err_name);
|
||
else
|
||
error_with_aggr_type (save_basetype, "no member function `%s::%s'", err_name);
|
||
return error_mark_node;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
if (cp - candidates != 0)
|
||
{
|
||
/* Rank from worst to best. Then cp will point to best one.
|
||
Private fields have their bits flipped. For unsigned
|
||
numbers, this should make them look very large.
|
||
If the best alternate has a (signed) negative value,
|
||
then all we ever saw were private members. */
|
||
if (cp - candidates > 1)
|
||
{
|
||
cp = ideal_candidate (save_basetype, candidates,
|
||
cp - candidates, parms, len);
|
||
if (cp == 0)
|
||
{
|
||
error ("ambiguous type conversion requested for %s `%s'",
|
||
name_kind, err_name);
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
else if (cp[-1].evil == 2)
|
||
{
|
||
error ("ambiguous type conversion requested for %s `%s'",
|
||
name_kind, err_name);
|
||
return error_mark_node;
|
||
}
|
||
else cp--;
|
||
|
||
/* The global function was the best, so use it. */
|
||
if (cp->u.field == 0)
|
||
{
|
||
/* We must convert the instance pointer into a reference type.
|
||
Global overloaded functions can only either take
|
||
aggregate objects (which come for free from references)
|
||
or reference data types anyway. */
|
||
TREE_VALUE (parms) = copy_node (instance_ptr);
|
||
TREE_TYPE (TREE_VALUE (parms)) = build_reference_type (TREE_TYPE (TREE_TYPE (instance_ptr)));
|
||
return build_function_call (cp->function, parms);
|
||
}
|
||
|
||
function = cp->function;
|
||
if (DECL_STATIC_FUNCTION_P (function))
|
||
basetype = NULL_TREE;
|
||
else
|
||
{
|
||
basetype = TREE_TYPE (TREE_TYPE (cp->arg));
|
||
TREE_VALUE (parms) = cp->arg;
|
||
}
|
||
goto found_and_maybe_warn;
|
||
}
|
||
|
||
if ((flags & ~LOOKUP_GLOBAL) & (LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY))
|
||
{
|
||
char *tag_name, *buf;
|
||
|
||
if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
|
||
== LOOKUP_SPECULATIVELY)
|
||
return NULL_TREE;
|
||
|
||
if (DECL_STATIC_FUNCTION_P (cp->function))
|
||
parms = TREE_CHAIN (parms);
|
||
if (ever_seen)
|
||
{
|
||
if (((int)saw_protected|(int)saw_private) == 0)
|
||
{
|
||
if (flags & LOOKUP_SPECULATIVELY)
|
||
return NULL_TREE;
|
||
if (static_call_context && TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
|
||
error_with_aggr_type (TREE_TYPE (TREE_TYPE (instance_ptr)),
|
||
"object missing in call to `%s::%s'",
|
||
err_name);
|
||
else
|
||
report_type_mismatch (cp, parms, name_kind, err_name);
|
||
}
|
||
else
|
||
{
|
||
char buf[80];
|
||
char *msg;
|
||
tree seen = saw_private;
|
||
|
||
if (saw_private)
|
||
if (saw_protected)
|
||
msg = "%s %%s (and the like) are private or protected";
|
||
else
|
||
msg = "the %s %%s is private";
|
||
else
|
||
{
|
||
msg = "the %s %%s is protected";
|
||
seen = saw_protected;
|
||
}
|
||
sprintf (buf, msg, name_kind);
|
||
error_with_decl (seen, buf);
|
||
error ("within this context");
|
||
}
|
||
return error_mark_node;
|
||
}
|
||
|
||
if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
|
||
== LOOKUP_COMPLAIN)
|
||
{
|
||
if (TREE_CODE (save_basetype) == RECORD_TYPE)
|
||
tag_name = "structure";
|
||
else
|
||
tag_name = "union";
|
||
|
||
if (wrap)
|
||
buf = "%s has no appropriate wrapper function defined";
|
||
else
|
||
{
|
||
buf = (char *)alloca (30 + strlen (err_name));
|
||
strcpy (buf, "%s has no method named `%s'");
|
||
}
|
||
|
||
error (buf, tag_name, err_name);
|
||
return error_mark_node;
|
||
}
|
||
return NULL_TREE;
|
||
}
|
||
continue;
|
||
|
||
found_and_maybe_warn:
|
||
if (cp->harshness[0] & 128)
|
||
{
|
||
if (flags & LOOKUP_COMPLAIN)
|
||
{
|
||
error_with_decl (cp->function, "non-const member function `%s'");
|
||
error ("called for const object at this point in file");
|
||
}
|
||
/* Not good enough for a match. */
|
||
else return error_mark_node;
|
||
}
|
||
goto found_and_ok;
|
||
}
|
||
/* Silently return error_mark_node. */
|
||
return error_mark_node;
|
||
|
||
found:
|
||
if (visibility == visibility_private)
|
||
{
|
||
if (flags & LOOKUP_COMPLAIN)
|
||
error (TREE_PRIVATE (function)
|
||
? "%s `%s' is private"
|
||
: "%s `%s' is from private base class",
|
||
name_kind,
|
||
lang_printable_name (function));
|
||
return error_mark_node;
|
||
}
|
||
else if (visibility == visibility_protected)
|
||
{
|
||
if (flags & LOOKUP_COMPLAIN)
|
||
error (TREE_PROTECTED (function)
|
||
? "%s `%s' is protected"
|
||
: "%s `%s' has protected visibility from this point",
|
||
name_kind,
|
||
lang_printable_name (function));
|
||
return error_mark_node;
|
||
}
|
||
abort ();
|
||
|
||
found_and_ok:
|
||
|
||
/* From here on down, BASETYPE is the type that INSTANCE_PTR's
|
||
type (if it exists) is a pointer to. */
|
||
basetype = DECL_CONTEXT (function);
|
||
fntype = TREE_TYPE (function);
|
||
|
||
if (TREE_CODE (fntype) == POINTER_TYPE)
|
||
fntype = TREE_TYPE (fntype);
|
||
|
||
/* If we are referencing a virtual function from an object
|
||
of effectively static type, then there is no need
|
||
to go through the virtual function table. */
|
||
if (need_vtbl == maybe_needed)
|
||
{
|
||
int fixed_type = resolves_to_fixed_type_p (instance);
|
||
|
||
if (all_virtual == 1
|
||
&& DECL_VINDEX (function)
|
||
&& may_be_remote (basetype))
|
||
need_vtbl = needed;
|
||
else if (DECL_VIRTUAL_P (function))
|
||
need_vtbl = fixed_type ? unneeded : needed;
|
||
else
|
||
need_vtbl = not_needed;
|
||
|
||
if (fixed_type && DECL_ABSTRACT_VIRTUAL_P (function))
|
||
{
|
||
error_with_decl (function, "invalid call to abstract function `%s'");
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
|
||
if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context)
|
||
{
|
||
/* Let's be nice to the user for now, and give reasonable
|
||
default behavior. */
|
||
instance_ptr = current_class_decl;
|
||
if (instance_ptr)
|
||
{
|
||
if (basetype != current_class_type)
|
||
{
|
||
basetype = get_base_type (basetype, current_class_type, 1);
|
||
if (basetype == 0)
|
||
{
|
||
error_not_base_type (DECL_CONTEXT (function), current_class_type);
|
||
return error_mark_node;
|
||
}
|
||
else if (basetype == error_mark_node)
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error_with_aggr_type (basetype, "cannot call member function `%s::%s' without object",
|
||
err_name);
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
|
||
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
|
||
|
||
if (TYPE_SIZE (value_type) == 0)
|
||
{
|
||
if (flags & LOOKUP_COMPLAIN)
|
||
incomplete_type_error (0, value_type);
|
||
return error_mark_node;
|
||
}
|
||
|
||
/* We do not pass FUNCTION into `actualparameterlist', because by
|
||
now everything should be ok. If not, then we have a serious error. */
|
||
if (DECL_STATIC_FUNCTION_P (function))
|
||
parms = actualparameterlist (NULL_TREE, TYPE_ARG_TYPES (fntype),
|
||
TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL);
|
||
else if (need_vtbl == unneeded)
|
||
{
|
||
int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
|
||
basetype = TREE_TYPE (instance);
|
||
if (DECL_CONTEXT (function) != TYPE_MAIN_VARIANT (basetype)
|
||
&& (TYPE_USES_MULTIPLE_INHERITANCE (basetype)
|
||
|| TYPE_USES_VIRTUAL_BASECLASSES (basetype)))
|
||
{
|
||
basetype = DECL_CONTEXT (function);
|
||
instance_ptr = convert_pointer_to (basetype, instance_ptr);
|
||
instance = build_indirect_ref (instance_ptr, 0);
|
||
}
|
||
parms = tree_cons (NULL_TREE, instance_ptr,
|
||
actualparameterlist (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, sub_flags));
|
||
}
|
||
else
|
||
{
|
||
if ((flags & LOOKUP_NONVIRTUAL) == 0)
|
||
basetype = DECL_VCONTEXT (function);
|
||
|
||
/* First parm could be integer_zerop with casts like
|
||
((Object*)0)->Object::IsA() */
|
||
if (!integer_zerop (TREE_VALUE (parms)))
|
||
{
|
||
instance_ptr = convert_pointer_to (build_type_variant (basetype, constp, volatilep),
|
||
TREE_VALUE (parms));
|
||
if (TREE_CODE (instance_ptr) == COND_EXPR)
|
||
{
|
||
instance_ptr = save_expr (instance_ptr);
|
||
instance = build_indirect_ref (instance_ptr);
|
||
}
|
||
else if (TREE_CODE (instance_ptr) == NOP_EXPR
|
||
&& TREE_CODE (TREE_OPERAND (instance_ptr, 0)) == ADDR_EXPR
|
||
&& TREE_OPERAND (TREE_OPERAND (instance_ptr, 0), 0) == instance)
|
||
;
|
||
else if (instance == NULL_TREE
|
||
|| TREE_CODE (instance) != INDIRECT_REF
|
||
|| TREE_OPERAND (instance, 0) != instance_ptr)
|
||
instance = build_indirect_ref (instance_ptr);
|
||
}
|
||
parms = tree_cons (NULL_TREE, instance_ptr,
|
||
actualparameterlist (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL));
|
||
}
|
||
|
||
/* See if there is a wrapper for this thing. */
|
||
if (wrap < 0
|
||
|| static_call_context
|
||
|| name == wrapper_name
|
||
|| name == DECL_NAME (TYPE_NAME (basetype)))
|
||
;
|
||
else if (wrap > 0 || TYPE_NEEDS_WRAPPER (basetype))
|
||
{
|
||
flags &= ~LOOKUP_PROTECT;
|
||
if (wrap == 0)
|
||
{
|
||
wrap = TYPE_NEEDS_WRAPPER (basetype);
|
||
/* If no wrapper specified, wrapper may be virtual. */
|
||
flags &= ~LOOKUP_NONVIRTUAL;
|
||
}
|
||
|
||
if (wrap)
|
||
{
|
||
tree wrapped_result, unwrapped_result;
|
||
register int bytecount = get_arglist_len_in_bytes (parms);
|
||
|
||
if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
|
||
parm = build_unary_op (ADDR_EXPR, function, 0);
|
||
else
|
||
{
|
||
fntype = build_cplus_method_type (basetype, TREE_TYPE (fntype), TYPE_ARG_TYPES (fntype));
|
||
parm = build1 (NOP_EXPR, build_pointer_type (fntype), DECL_VINDEX (function));
|
||
}
|
||
|
||
if (TYPE_HAS_WRAPPER_PRED (basetype))
|
||
{
|
||
unwrapped_result = build_nt (CALL_EXPR, default_conversion (function), parms, NULL_TREE);
|
||
|
||
assert (TREE_OPERAND (unwrapped_result, 1) != error_mark_node);
|
||
|
||
TREE_TYPE (unwrapped_result) = value_type;
|
||
TREE_VOLATILE (unwrapped_result) = 1;
|
||
TREE_RAISES (unwrapped_result) = !! TYPE_RAISES_EXCEPTIONS (fntype);
|
||
}
|
||
|
||
/* If this pointer walked as a result of multiple inheritance,
|
||
keep its displaced value. */
|
||
parms = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
|
||
tree_cons (NULL_TREE, parm, TREE_CHAIN (parms)));
|
||
|
||
wrapped_result = get_wrapper (basetype);
|
||
assert (wrapped_result != NULL_TREE);
|
||
assert (wrapped_result != error_mark_node);
|
||
|
||
/* @@ Should BASETYPE_PATH get TREE_PURPOSE (wrapped_result) here? */
|
||
wrapped_result
|
||
= build_method_call (instance,
|
||
DECL_ORIGINAL_NAME (TREE_VALUE (wrapped_result)),
|
||
parms, basetype_path, flags);
|
||
#if 0
|
||
/* Do this if we want the result of operator->() to inherit
|
||
the type of the function it is subbing for. */
|
||
if (wrapped_result != error_mark_node)
|
||
TREE_TYPE (wrapped_result) = value_type;
|
||
#endif
|
||
|
||
if (TYPE_HAS_WRAPPER_PRED (basetype))
|
||
{
|
||
result = build_conditional_expr
|
||
(build_method_call (instance, wrapper_pred_name, build_tree_list (NULL_TREE, parm), basetype_path, LOOKUP_NORMAL),
|
||
wrapped_result,
|
||
unwrapped_result);
|
||
|
||
}
|
||
else
|
||
{
|
||
result = wrapped_result;
|
||
}
|
||
|
||
TREE_VOLATILE (result) = 1;
|
||
return result;
|
||
}
|
||
}
|
||
/* Constructors do not overload method calls. */
|
||
else if (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype)
|
||
&& name != DECL_NAME (TYPE_NAME (basetype))
|
||
&& (TREE_CODE (function) != FUNCTION_DECL
|
||
|| strncmp (IDENTIFIER_POINTER (DECL_NAME (function)),
|
||
OPERATOR_METHOD_FORMAT,
|
||
OPERATOR_METHOD_LENGTH))
|
||
#if 0
|
||
&& (may_be_remote (basetype)
|
||
|| (C_C_D ? TREE_TYPE (instance) != current_class_type : 1))
|
||
#else
|
||
/* This change by Larry Ketcham. */
|
||
&& (may_be_remote (basetype) || instance != C_C_D)
|
||
#endif
|
||
)
|
||
{
|
||
#ifdef ESKIT
|
||
register int bytecount = 0;
|
||
#else
|
||
register int bytecount = get_arglist_len_in_bytes (parms);
|
||
#endif
|
||
tree fn_as_int;
|
||
|
||
parms = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
|
||
TREE_CHAIN (parms));
|
||
|
||
if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
|
||
fn_as_int = build_unary_op (ADDR_EXPR, function, 0);
|
||
else
|
||
fn_as_int = convert (TREE_TYPE (default_conversion (function)), DECL_VINDEX (function));
|
||
if (all_virtual == 1)
|
||
fn_as_int = convert (integer_type_node, fn_as_int);
|
||
|
||
result = build_opfncall (METHOD_CALL_EXPR, LOOKUP_NORMAL, instance, fn_as_int, parms);
|
||
|
||
if (result == NULL_TREE)
|
||
{
|
||
compiler_error ("could not overload `operator->()(...)'");
|
||
return error_mark_node;
|
||
}
|
||
else if (result == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
#if 0
|
||
/* Do this if we want the result of operator->() to inherit
|
||
the type of the function it is subbing for. */
|
||
TREE_TYPE (result) = value_type;
|
||
#endif
|
||
|
||
#ifdef ESKIT
|
||
{
|
||
int used, size;
|
||
|
||
/* Count the number of bytes of arguements to operator->(),
|
||
not to the method itself. In the tally, don't count bytes
|
||
for pointer to member function or for the bytecount. */
|
||
parms = TREE_OPERAND (result, 1);
|
||
bytecount = get_arglist_len_in_bytes (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (parms))));
|
||
used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_VALUE (parms))));
|
||
#ifdef PUSH_ROUNDING
|
||
size = PUSH_ROUNDING (size);
|
||
#endif
|
||
used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
|
||
/ (PARM_BOUNDARY / BITS_PER_UNIT))
|
||
* (PARM_BOUNDARY / BITS_PER_UNIT));
|
||
bytecount += used;
|
||
TREE_CHAIN (TREE_CHAIN (parms))
|
||
= tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
|
||
TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (parms))));
|
||
}
|
||
#endif
|
||
|
||
return result;
|
||
}
|
||
|
||
if (need_vtbl == needed)
|
||
{
|
||
function = build_vfn_ref (&TREE_VALUE (parms), instance, DECL_VINDEX (function));
|
||
TREE_TYPE (function) = build_pointer_type (fntype);
|
||
}
|
||
#ifdef SOS
|
||
else if (basetype && TYPE_DYNAMIC (basetype))
|
||
{
|
||
function = build_array_ref (dtbl, DECL_DINDEX (function));
|
||
TREE_TYPE (function) = build_pointer_type (fntype);
|
||
}
|
||
#endif
|
||
|
||
if (TREE_INLINE (function) && TREE_CODE (function) == FUNCTION_DECL)
|
||
function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
|
||
else function = default_conversion (function);
|
||
|
||
result =
|
||
build_nt (CALL_EXPR, function, parms, NULL_TREE);
|
||
|
||
TREE_TYPE (result) = value_type;
|
||
TREE_VOLATILE (result) = 1;
|
||
TREE_RAISES (result)
|
||
= TYPE_RAISES_EXCEPTIONS (fntype) || (parms && TREE_RAISES (parms));
|
||
return result;
|
||
}
|
||
|
||
/* Similar to `build_method_call', but for overloaded non-member functions.
|
||
The name of this function comes through NAME. The name depends
|
||
on PARMS.
|
||
|
||
Note that this function must handle simple `C' promotions,
|
||
as well as variable numbers of arguments (...), and
|
||
default arguments to boot.
|
||
|
||
If the overloading is successful, we return a treenode which
|
||
contains the call to the function.
|
||
|
||
If overloading produces candidates which are probabe, but not definite,
|
||
we hold these candidates. If FINAL_CP is non-zero, then we are free
|
||
to assume that final_cp points to enough storage for all candidates that
|
||
this function might generate. The `harshness' array is preallocated for
|
||
the first candidate, but not for subsequent ones.
|
||
|
||
Note that the DECL_RTL of FUNCTION must be made to agree with this
|
||
function's new name. */
|
||
|
||
tree
|
||
build_overload_call (fnname, parms, complain, final_cp)
|
||
tree fnname, parms;
|
||
int complain;
|
||
struct candidate *final_cp;
|
||
{
|
||
/* must check for overloading here */
|
||
tree overload_name, functions, function, parm;
|
||
tree parmtypes = NULL_TREE, last = NULL_TREE;
|
||
register tree outer;
|
||
int length;
|
||
int parmlength = list_length (parms);
|
||
|
||
struct candidate *candidates, *cp;
|
||
int rank_for_overload ();
|
||
|
||
if (final_cp)
|
||
{
|
||
final_cp[0].evil = 0;
|
||
final_cp[0].user = 0;
|
||
final_cp[0].b_or_d = 0;
|
||
final_cp[0].easy = 0;
|
||
final_cp[0].function = 0;
|
||
/* end marker. */
|
||
final_cp[1].evil = 1;
|
||
}
|
||
|
||
for (parm = parms; parm; parm = TREE_CHAIN (parm))
|
||
{
|
||
register tree t = TREE_TYPE (TREE_VALUE (parm));
|
||
|
||
if (t == error_mark_node)
|
||
return error_mark_node;
|
||
if (TREE_CODE (t) == ARRAY_TYPE || TREE_CODE (t) == OFFSET_TYPE)
|
||
{
|
||
/* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
|
||
Also convert OFFSET_TYPE entities to their normal selves.
|
||
This eliminates needless calls to `compute_conversion_costs'. */
|
||
TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
|
||
t = TREE_TYPE (TREE_VALUE (parm));
|
||
}
|
||
last = build_tree_list (NULL_TREE, t);
|
||
parmtypes = chainon (parmtypes, last);
|
||
}
|
||
if (last)
|
||
TREE_CHAIN (last) = void_list_node;
|
||
else
|
||
parmtypes = void_list_node;
|
||
overload_name = build_decl_overload (IDENTIFIER_POINTER (fnname), parmtypes, 0);
|
||
|
||
/* Now check to see whether or not we can win.
|
||
Note that if we are called from `build_method_call',
|
||
then we cannot have a mis-match, because we would have
|
||
already found such a winning case. */
|
||
|
||
if (IDENTIFIER_GLOBAL_VALUE (overload_name))
|
||
if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (overload_name)) != TREE_LIST)
|
||
return build_function_call (DECL_MAIN_VARIANT (IDENTIFIER_GLOBAL_VALUE (overload_name)), parms);
|
||
|
||
functions = IDENTIFIER_GLOBAL_VALUE (fnname);
|
||
|
||
if (functions == NULL_TREE)
|
||
{
|
||
if (complain)
|
||
error ("only member functions apply");
|
||
if (final_cp)
|
||
final_cp->evil = 1;
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_CODE (functions) == FUNCTION_DECL)
|
||
{
|
||
functions = DECL_MAIN_VARIANT (functions);
|
||
if (final_cp)
|
||
{
|
||
/* We are just curious whether this is a viable alternative or not. */
|
||
compute_conversion_costs (functions, parms, final_cp, parmlength);
|
||
return functions;
|
||
}
|
||
else
|
||
return build_function_call (functions, parms);
|
||
}
|
||
|
||
if (TREE_VALUE (functions) == NULL_TREE)
|
||
{
|
||
if (complain)
|
||
error ("function `%s' declared overloaded, but no instances of that function declared",
|
||
IDENTIFIER_POINTER (TREE_PURPOSE (functions)));
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_CODE (TREE_VALUE (functions)) == TREE_LIST)
|
||
{
|
||
register tree outer;
|
||
length = 0;
|
||
|
||
/* The list-of-lists should only occur for class things. */
|
||
assert (functions == IDENTIFIER_CLASS_VALUE (fnname));
|
||
|
||
for (outer = functions; outer; outer = TREE_CHAIN (outer))
|
||
{
|
||
/* member functions. */
|
||
length += list_length (TREE_VALUE (TREE_VALUE (outer)));
|
||
/* friend functions. */
|
||
length += list_length (TREE_TYPE (TREE_VALUE (outer)));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
length = list_length (functions);
|
||
}
|
||
|
||
if (final_cp)
|
||
candidates = final_cp;
|
||
else
|
||
candidates = (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
|
||
|
||
cp = candidates;
|
||
|
||
assert (TREE_CODE (TREE_VALUE (functions)) != TREE_LIST);
|
||
/* OUTER is the list of FUNCTION_DECLS, in a TREE_LIST. */
|
||
|
||
for (outer = functions; outer; outer = TREE_CHAIN (outer))
|
||
{
|
||
function = TREE_VALUE (outer);
|
||
if (TREE_CODE (function) != FUNCTION_DECL)
|
||
{
|
||
if (TREE_CODE (function) == CONST_DECL)
|
||
error_with_decl (function, "enumeral value `%s' conflicts with function of same name");
|
||
else if (TREE_CODE (function) == VAR_DECL)
|
||
if (TREE_STATIC (function))
|
||
error_with_decl (function, "variable `%s' conflicts with function of same name");
|
||
else
|
||
error_with_decl (function, "constant field `%s' conflicts with function of same name");
|
||
else if (TREE_CODE (function) == TYPE_DECL)
|
||
continue;
|
||
else abort ();
|
||
error ("at this point in file");
|
||
continue;
|
||
}
|
||
function = DECL_MAIN_VARIANT (function);
|
||
/* Can't use alloca here, since result might be
|
||
passed to calling function. */
|
||
cp->harshness
|
||
= (unsigned short *)oballoc ((parmlength+1) * sizeof (short));
|
||
compute_conversion_costs (function, parms, cp, parmlength);
|
||
if (cp[0].evil == 0)
|
||
{
|
||
cp[1].evil = 1;
|
||
if (final_cp
|
||
&& cp[0].user == 0 && cp[0].b_or_d == 0
|
||
&& cp[0].easy <= 1)
|
||
{
|
||
final_cp[0].easy = cp[0].easy;
|
||
return function;
|
||
}
|
||
cp++;
|
||
}
|
||
}
|
||
|
||
if (cp - candidates)
|
||
{
|
||
tree rval = error_mark_node;
|
||
|
||
/* Leave marker. */
|
||
cp[0].evil = 1;
|
||
if (cp - candidates > 1)
|
||
{
|
||
struct candidate *best_cp
|
||
= ideal_candidate (NULL_TREE, candidates,
|
||
cp - candidates, parms, parmlength);
|
||
if (best_cp == 0)
|
||
{
|
||
if (complain)
|
||
error ("call of overloaded `%s' is ambiguous", IDENTIFIER_POINTER (fnname));
|
||
return error_mark_node;
|
||
}
|
||
else
|
||
rval = best_cp->function;
|
||
}
|
||
else
|
||
{
|
||
cp -= 1;
|
||
if (cp->evil > 1)
|
||
{
|
||
if (complain)
|
||
error ("type conversion ambiguous");
|
||
}
|
||
else
|
||
rval = cp->function;
|
||
}
|
||
|
||
if (final_cp)
|
||
return rval;
|
||
|
||
return build_function_call (rval, parms);
|
||
}
|
||
else if (complain)
|
||
{
|
||
tree name;
|
||
char *err_name;
|
||
/* Initialize name for error reporting. */
|
||
if (TREE_CODE (functions) == TREE_LIST)
|
||
name = TREE_PURPOSE (functions);
|
||
else
|
||
name = DECL_ORIGINAL_NAME (functions);
|
||
|
||
if (OPERATOR_NAME_P (name))
|
||
{
|
||
char *opname = operator_name_string (name);
|
||
err_name = (char *)alloca (strlen (opname) + 12);
|
||
sprintf (err_name, "operator %s", opname);
|
||
}
|
||
else
|
||
err_name = IDENTIFIER_POINTER (name);
|
||
|
||
report_type_mismatch (cp, parms, "function", err_name);
|
||
}
|
||
return error_mark_node;
|
||
}
|
||
|
||
void
|
||
init_class_processing ()
|
||
{
|
||
current_class_stacksize = 10;
|
||
current_class_base = (tree *)xmalloc(current_class_stacksize * sizeof (tree));
|
||
current_class_stack = current_class_base;
|
||
|
||
current_lang_stacksize = 10;
|
||
current_lang_base = (tree *)xmalloc(current_lang_stacksize * sizeof (tree));
|
||
current_lang_stack = current_lang_base;
|
||
|
||
delta_name = get_identifier (VTABLE_DELTA_NAME);
|
||
pfn_name = get_identifier (VTABLE_PFN_NAME);
|
||
|
||
/* Keep these values lying around. */
|
||
minus_one_node = build_int_2 (-1, 0);
|
||
the_null_vtable_entry = build_vtable_entry (integer_zero_node, integer_zero_node);
|
||
base_layout_decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, error_mark_node);
|
||
TREE_TYPE (base_layout_decl) = make_node (RECORD_TYPE);
|
||
|
||
obstack_init (&class_obstack);
|
||
}
|
||
|
||
/* Set current scope to NAME. CODE tells us if this is a
|
||
STRUCT, UNION, or ENUM environment.
|
||
|
||
NAME may end up being NULL_TREE if this is an anonymous or
|
||
late-bound struct (as in "struct { ... } foo;") */
|
||
|
||
/* Here's a subroutine we need because C lacks lambdas. */
|
||
void
|
||
unuse_fields (type)
|
||
tree type;
|
||
{
|
||
tree fields;
|
||
|
||
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
|
||
{
|
||
if (TREE_CODE (fields) != FIELD_DECL)
|
||
continue;
|
||
|
||
TREE_USED (fields) = 0;
|
||
if (DECL_ANON_UNION_ELEM (fields))
|
||
unuse_fields (TREE_TYPE (fields));
|
||
}
|
||
}
|
||
|
||
/* Set global variables CURRENT_CLASS_NAME and CURRENT_CLASS_TYPE to
|
||
appropriate values, found by looking up the type definition of
|
||
NAME (as a CODE).
|
||
|
||
If MODIFY is 1, we set IDENTIFIER_CLASS_VALUE's of names
|
||
which can be seen locally to the class. They are shadowed by
|
||
any subsequent local declaration (including parameter names).
|
||
|
||
If MODIFY is 2, we set IDENTIFIER_CLASS_VALUE's of names
|
||
which have static meaning (i.e., static members, static
|
||
member functions, enum declarations, etc).
|
||
|
||
So that we may avoid calls to lookup_name, we cache the TYPE_DECL
|
||
in the TREE_TYPE field of the name.
|
||
|
||
For multiple inheritance, we perform a two-pass depth-first search
|
||
of the type lattice. The first pass performs a pre-order search,
|
||
marking types after the type has had its fields installed in
|
||
the appropriate IDENTIFIER_CLASS_VALUE slot. The second pass merely
|
||
unmarks the marked types. If a field or member function name
|
||
appears in an ambiguous way, the IDENTIFIER_CLASS_VALUE of
|
||
that name becomes `error_mark_node'. */
|
||
|
||
void
|
||
pushclass (type, modify)
|
||
tree type;
|
||
int modify;
|
||
{
|
||
push_memoized_context (type, modify);
|
||
|
||
*current_class_stack++ = current_class_name;
|
||
*current_class_stack++ = current_class_type;
|
||
if (current_class_stack >= current_class_base + current_class_stacksize)
|
||
{
|
||
current_class_base =
|
||
(tree *)xrealloc (current_class_base,
|
||
sizeof (tree) * (current_class_stacksize + 10));
|
||
current_class_stack = current_class_base + current_class_stacksize;
|
||
current_class_stacksize += 10;
|
||
}
|
||
|
||
type = TYPE_MAIN_VARIANT (type);
|
||
current_class_name = TYPE_NAME (type);
|
||
if (TREE_CODE (current_class_name) == TYPE_DECL)
|
||
current_class_name = DECL_NAME (current_class_name);
|
||
current_class_type = type;
|
||
|
||
if (type != prev_class_type && prev_class_type != NULL_TREE
|
||
&& current_class_stack == current_class_base + 2)
|
||
{
|
||
popclass (-1);
|
||
prev_class_type = 0;
|
||
}
|
||
|
||
if (modify)
|
||
{
|
||
tree tags;
|
||
|
||
if (type != prev_class_type)
|
||
{
|
||
build_mi_matrix (type);
|
||
push_class_decls (type);
|
||
free_mi_matrix ();
|
||
prev_class_type = type;
|
||
}
|
||
else
|
||
unuse_fields (type);
|
||
|
||
tags = CLASSTYPE_TAGS (type);
|
||
while (tags)
|
||
{
|
||
TREE_NONLOCAL (TREE_VALUE (tags)) = 1;
|
||
pushtag (TREE_PURPOSE (tags), TREE_VALUE (tags));
|
||
if (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (tags)) == NULL_TREE
|
||
&& TREE_CODE (TYPE_NAME (TREE_VALUE (tags))) == TYPE_DECL)
|
||
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (tags))
|
||
= TYPE_NAME (TREE_VALUE (tags));
|
||
tags = TREE_CHAIN (tags);
|
||
}
|
||
}
|
||
else
|
||
pushlevel_class ();
|
||
|
||
if (flag_cadillac)
|
||
cadillac_push_class (type);
|
||
}
|
||
|
||
/* Get out of the current class scope. If we were in a class scope
|
||
previously, that is the one popped to. The flag MODIFY tells
|
||
whether the current scope declarations needs to be modified
|
||
as a result of popping to the new scope. */
|
||
void
|
||
popclass (modify)
|
||
int modify;
|
||
{
|
||
if (flag_cadillac)
|
||
cadillac_pop_class ();
|
||
|
||
if (modify < 0)
|
||
{
|
||
/* Back this old class out completely. */
|
||
tree tags = CLASSTYPE_TAGS (prev_class_type);
|
||
|
||
pop_class_decls (prev_class_type);
|
||
while (tags)
|
||
{
|
||
TREE_NONLOCAL (TREE_VALUE (tags)) = 0;
|
||
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (tags)) = NULL_TREE;
|
||
tags = TREE_CHAIN (tags);
|
||
}
|
||
return;
|
||
}
|
||
if (modify)
|
||
{
|
||
/* Just remove from this class what didn't make
|
||
it into IDENTIFIER_CLASS_VALUE. */
|
||
tree tags = CLASSTYPE_TAGS (current_class_type);
|
||
|
||
while (tags)
|
||
{
|
||
TREE_NONLOCAL (TREE_VALUE (tags)) = 0;
|
||
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (tags)) = NULL_TREE;
|
||
tags = TREE_CHAIN (tags);
|
||
}
|
||
}
|
||
else
|
||
poplevel_class ();
|
||
|
||
current_class_type = *--current_class_stack;
|
||
current_class_name = *--current_class_stack;
|
||
|
||
if (current_class_type)
|
||
{
|
||
if (CLASSTYPE_VTBL_PTR (current_class_type))
|
||
{
|
||
current_vtable_decl = lookup_name (DECL_NAME (CLASSTYPE_VTBL_PTR (current_class_type)));
|
||
if (current_vtable_decl)
|
||
current_vtable_decl = build_indirect_ref (current_vtable_decl, 0);
|
||
}
|
||
current_class_decl = lookup_name (get_identifier (THIS_NAME));
|
||
if (current_class_decl)
|
||
{
|
||
if (TREE_CODE (TREE_TYPE (current_class_decl)) == POINTER_TYPE)
|
||
{
|
||
/* Can't call build_indirect_ref here, because it has special
|
||
logic to return C_C_D given this argument. */
|
||
C_C_D = build1 (INDIRECT_REF, current_class_type, current_class_decl);
|
||
TREE_READONLY (C_C_D) = TREE_READONLY (TREE_TYPE (TREE_TYPE (current_class_decl)));
|
||
TREE_VOLATILE (C_C_D) = TREE_VOLATILE (TREE_TYPE (TREE_TYPE (current_class_decl)));
|
||
}
|
||
else
|
||
C_C_D = current_class_decl;
|
||
}
|
||
else C_C_D = NULL_TREE;
|
||
}
|
||
else
|
||
{
|
||
current_class_decl = NULL_TREE;
|
||
current_vtable_decl = NULL_TREE;
|
||
C_C_D = NULL_TREE;
|
||
}
|
||
|
||
pop_memoized_context (modify);
|
||
}
|
||
|
||
/* Set global variables CURRENT_LANG_NAME to appropriate value
|
||
so that behavior of name-mangline machinery is correct. */
|
||
|
||
void
|
||
push_lang_context (name)
|
||
tree name;
|
||
{
|
||
*current_lang_stack++ = current_lang_name;
|
||
if (current_lang_stack >= current_lang_base + current_lang_stacksize)
|
||
{
|
||
current_lang_base =
|
||
(tree *)xrealloc (current_lang_base,
|
||
sizeof (tree) * (current_lang_stacksize + 10));
|
||
current_lang_stack = current_lang_base + current_lang_stacksize;
|
||
current_lang_stacksize += 10;
|
||
}
|
||
|
||
if (name == lang_name_cplusplus)
|
||
{
|
||
strict_prototype = strict_prototypes_lang_cplusplus;
|
||
current_lang_name = name;
|
||
}
|
||
else if (name == lang_name_c)
|
||
{
|
||
strict_prototype = strict_prototypes_lang_c;
|
||
current_lang_name = name;
|
||
}
|
||
else
|
||
error ("language string `\"%s\"' not recognized", IDENTIFIER_POINTER (name));
|
||
|
||
if (flag_cadillac)
|
||
cadillac_push_lang (name);
|
||
}
|
||
|
||
/* Get out of the current language scope. */
|
||
void
|
||
pop_lang_context ()
|
||
{
|
||
if (flag_cadillac)
|
||
cadillac_pop_lang ();
|
||
|
||
current_lang_name = *--current_lang_stack;
|
||
if (current_lang_name == lang_name_cplusplus)
|
||
strict_prototype = strict_prototypes_lang_cplusplus;
|
||
else if (current_lang_name == lang_name_c)
|
||
strict_prototype = strict_prototypes_lang_c;
|
||
}
|
||
|
||
int
|
||
root_lang_context_p ()
|
||
{
|
||
return current_lang_stack == current_lang_base;
|
||
}
|
||
|
||
/* Type instantiation routines. */
|
||
|
||
/* This function will instantiate the type of the expression given
|
||
in RHS to match the type of LHSTYPE. If LHSTYPE is NULL_TREE,
|
||
or other errors exist, the TREE_TYPE of RHS will be ERROR_MARK_NODE.
|
||
|
||
This function is used in build_modify_expr, actualparameterlist,
|
||
build_c_cast, and compute_conversion_costs. */
|
||
tree
|
||
instantiate_type (lhstype, rhs, complain)
|
||
tree lhstype, rhs;
|
||
int complain;
|
||
{
|
||
if (TREE_CODE (rhs) == OP_IDENTIFIER)
|
||
return build_instantiated_decl (lhstype, rhs);
|
||
|
||
if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
|
||
{
|
||
if (complain)
|
||
error ("not enough type information");
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_TYPE (rhs) != NULL_TREE && ! (type_unknown_p (rhs)))
|
||
return rhs;
|
||
|
||
/* This should really only be used when attempting to distinguish
|
||
what sort of a pointer to function we have. For now, any
|
||
arithmethic operation which is not supported on pointers
|
||
is rejected as an error. */
|
||
|
||
switch (TREE_CODE (rhs))
|
||
{
|
||
case TYPE_EXPR:
|
||
case CONVERT_EXPR:
|
||
case SAVE_EXPR:
|
||
case CONSTRUCTOR:
|
||
case BUFFER_REF:
|
||
assert (0);
|
||
return error_mark_node;
|
||
|
||
case INDIRECT_REF:
|
||
case ARRAY_REF:
|
||
TREE_TYPE (rhs) = lhstype;
|
||
lhstype = build_pointer_type (lhstype);
|
||
TREE_OPERAND (rhs, 0)
|
||
= instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
|
||
if (TREE_OPERAND (rhs, 0) == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
return rhs;
|
||
|
||
case NOP_EXPR:
|
||
rhs = copy_node (TREE_OPERAND (rhs, 0));
|
||
TREE_TYPE (rhs) = unknown_type_node;
|
||
return instantiate_type (lhstype, rhs, complain);
|
||
|
||
case COMPONENT_REF:
|
||
{
|
||
tree field = TREE_OPERAND (rhs, 1);
|
||
if (TREE_CODE (field) == TREE_LIST)
|
||
{
|
||
tree function = instantiate_type (lhstype, field, complain);
|
||
if (function == error_mark_node)
|
||
return error_mark_node;
|
||
assert (TREE_CODE (function) == FUNCTION_DECL);
|
||
if (DECL_VIRTUAL_P (function))
|
||
{
|
||
tree base = TREE_OPERAND (rhs, 0);
|
||
tree base_ptr = build_unary_op (ADDR_EXPR, base, 0);
|
||
if (base_ptr == error_mark_node)
|
||
return error_mark_node;
|
||
base_ptr = convert_pointer_to (DECL_VCONTEXT (function), base_ptr);
|
||
if (base_ptr == error_mark_node)
|
||
return error_mark_node;
|
||
return build_vfn_ref (&base_ptr, base, DECL_VINDEX (function));
|
||
}
|
||
return function;
|
||
}
|
||
|
||
assert (TREE_CODE (field) == FIELD_DECL);
|
||
assert (!(TREE_CODE (TREE_TYPE (field)) == FUNCTION_TYPE
|
||
|| TREE_CODE (TREE_TYPE (field)) == METHOD_TYPE));
|
||
|
||
TREE_TYPE (rhs) = lhstype;
|
||
/* First look for an exact match */
|
||
|
||
while (field && TREE_TYPE (field) != lhstype)
|
||
field = TREE_CHAIN (field);
|
||
if (field)
|
||
{
|
||
TREE_OPERAND (rhs, 1) = field;
|
||
return rhs;
|
||
}
|
||
|
||
/* No exact match found, look for a compatible function. */
|
||
field = TREE_OPERAND (rhs, 1);
|
||
while (field && ! comptypes (lhstype, TREE_TYPE (field), 0))
|
||
field = TREE_CHAIN (field);
|
||
if (field)
|
||
{
|
||
TREE_OPERAND (rhs, 1) = field;
|
||
field = TREE_CHAIN (field);
|
||
while (field && ! comptypes (lhstype, TREE_TYPE (field), 0))
|
||
field = TREE_CHAIN (field);
|
||
if (field)
|
||
{
|
||
if (complain)
|
||
error ("ambiguous overload for COMPONENT_REF requested");
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (complain)
|
||
error ("no appropriate overload exists for COMPONENT_REF");
|
||
return error_mark_node;
|
||
}
|
||
return rhs;
|
||
}
|
||
|
||
case TREE_LIST:
|
||
{
|
||
tree elem, baselink, name;
|
||
int globals = overloaded_globals_p (rhs);
|
||
|
||
/* If there's only one function we know about, return that. */
|
||
if (globals > 0 && TREE_CHAIN (rhs) == NULL_TREE)
|
||
return TREE_VALUE (rhs);
|
||
|
||
/* First look for an exact match. Search either overloaded
|
||
functions or member functions. May have to undo what
|
||
`default_conversion' or `datatype' might do to lhstype. */
|
||
|
||
if (TREE_CODE (lhstype) == POINTER_TYPE)
|
||
if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE
|
||
|| TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
|
||
lhstype = TREE_TYPE (lhstype);
|
||
else
|
||
{
|
||
if (complain)
|
||
error ("invalid type combination for overload");
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_CODE (lhstype) != FUNCTION_TYPE && globals > 0)
|
||
{
|
||
if (complain)
|
||
error ("cannot resolve overloaded function `%s' based on non-function type",
|
||
IDENTIFIER_POINTER (TREE_PURPOSE (rhs)));
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (globals > 0)
|
||
{
|
||
assert (TREE_CODE (TREE_VALUE (rhs)) == FUNCTION_DECL);
|
||
elem = rhs;
|
||
while (elem)
|
||
if (TREE_TYPE (TREE_VALUE (elem)) != lhstype)
|
||
elem = TREE_CHAIN (elem);
|
||
else
|
||
return TREE_VALUE (elem);
|
||
/* No exact match found, look for a compatible function. */
|
||
elem = rhs;
|
||
while (elem && ! comp_target_types (lhstype, TREE_TYPE (TREE_VALUE (elem)), 1))
|
||
elem = TREE_CHAIN (elem);
|
||
if (elem)
|
||
{
|
||
tree save_elem = TREE_VALUE (elem);
|
||
elem = TREE_CHAIN (elem);
|
||
while (elem && ! comp_target_types (lhstype, TREE_TYPE (TREE_VALUE (elem)), 0))
|
||
elem = TREE_CHAIN (elem);
|
||
if (elem)
|
||
{
|
||
if (complain)
|
||
error ("ambiguous overload for overloaded function requested");
|
||
return error_mark_node;
|
||
}
|
||
return save_elem;
|
||
}
|
||
if (complain)
|
||
{
|
||
if (TREE_CHAIN (rhs))
|
||
error ("no appropriate overload for overloaded function `%s' exists",
|
||
IDENTIFIER_POINTER (TREE_PURPOSE (rhs)));
|
||
else
|
||
error ("function `%s' has inappropriate type signature",
|
||
IDENTIFIER_POINTER (TREE_PURPOSE (rhs)));
|
||
}
|
||
return error_mark_node;
|
||
}
|
||
|
||
if (TREE_NONLOCAL (rhs))
|
||
{
|
||
/* Got to get it as a baselink. */
|
||
rhs = lookup_fnfields (CLASSTYPE_AS_LIST (current_class_type),
|
||
TREE_PURPOSE (rhs), 0);
|
||
}
|
||
else
|
||
{
|
||
assert (TREE_CHAIN (rhs) == NULL_TREE);
|
||
if (TREE_CODE (TREE_VALUE (rhs)) == TREE_LIST)
|
||
rhs = TREE_VALUE (rhs);
|
||
assert (TREE_CODE (TREE_VALUE (rhs)) == FUNCTION_DECL);
|
||
}
|
||
|
||
for (baselink = rhs; baselink;
|
||
baselink = next_baselink (baselink))
|
||
{
|
||
elem = TREE_VALUE (baselink);
|
||
while (elem)
|
||
if (TREE_TYPE (elem) != lhstype)
|
||
elem = TREE_CHAIN (elem);
|
||
else
|
||
return elem;
|
||
}
|
||
|
||
/* No exact match found, look for a compatible method. */
|
||
for (baselink = rhs; baselink;
|
||
baselink = next_baselink (baselink))
|
||
{
|
||
elem = TREE_VALUE (baselink);
|
||
while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 1))
|
||
elem = TREE_CHAIN (elem);
|
||
if (elem)
|
||
{
|
||
tree save_elem = elem;
|
||
elem = TREE_CHAIN (elem);
|
||
while (elem && ! comp_target_types (lhstype, TREE_TYPE (elem), 0))
|
||
elem = TREE_CHAIN (elem);
|
||
if (elem)
|
||
{
|
||
if (complain)
|
||
error ("ambiguous overload for overloaded method requested");
|
||
return error_mark_node;
|
||
}
|
||
return save_elem;
|
||
}
|
||
name = DECL_ORIGINAL_NAME (TREE_VALUE (rhs));
|
||
if (TREE_CODE (lhstype) == FUNCTION_TYPE && globals < 0)
|
||
{
|
||
/* Try to instantiate from non-member functions. */
|
||
rhs = IDENTIFIER_GLOBAL_VALUE (name);
|
||
if (rhs && TREE_CODE (rhs) == TREE_LIST)
|
||
{
|
||
/* This code seems to be missing a `return'. */
|
||
abort ();
|
||
instantiate_type (lhstype, rhs, complain);
|
||
}
|
||
}
|
||
|
||
if (complain)
|
||
error ("no static member functions named `%s'",
|
||
IDENTIFIER_POINTER (name));
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
|
||
case CALL_EXPR:
|
||
/* This is too hard for now. */
|
||
assert (0);
|
||
return error_mark_node;
|
||
|
||
case PLUS_EXPR:
|
||
case MINUS_EXPR:
|
||
case COMPOUND_EXPR:
|
||
TREE_OPERAND (rhs, 0) = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
|
||
if (TREE_OPERAND (rhs, 0) == error_mark_node)
|
||
return error_mark_node;
|
||
TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
|
||
if (TREE_OPERAND (rhs, 1) == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
TREE_TYPE (rhs) = lhstype;
|
||
return rhs;
|
||
|
||
case MULT_EXPR:
|
||
case TRUNC_DIV_EXPR:
|
||
case FLOOR_DIV_EXPR:
|
||
case CEIL_DIV_EXPR:
|
||
case ROUND_DIV_EXPR:
|
||
case RDIV_EXPR:
|
||
case TRUNC_MOD_EXPR:
|
||
case FLOOR_MOD_EXPR:
|
||
case CEIL_MOD_EXPR:
|
||
case ROUND_MOD_EXPR:
|
||
case FIX_ROUND_EXPR:
|
||
case FIX_FLOOR_EXPR:
|
||
case FIX_CEIL_EXPR:
|
||
case FIX_TRUNC_EXPR:
|
||
case FLOAT_EXPR:
|
||
case NEGATE_EXPR:
|
||
case ABS_EXPR:
|
||
case MAX_EXPR:
|
||
case MIN_EXPR:
|
||
case FFS_EXPR:
|
||
|
||
case BIT_AND_EXPR:
|
||
case BIT_IOR_EXPR:
|
||
case BIT_XOR_EXPR:
|
||
case LSHIFT_EXPR:
|
||
case RSHIFT_EXPR:
|
||
case LROTATE_EXPR:
|
||
case RROTATE_EXPR:
|
||
|
||
case PREINCREMENT_EXPR:
|
||
case PREDECREMENT_EXPR:
|
||
case POSTINCREMENT_EXPR:
|
||
case POSTDECREMENT_EXPR:
|
||
if (complain)
|
||
error ("illegal operation on uninstantiated type");
|
||
return error_mark_node;
|
||
|
||
case TRUTH_AND_EXPR:
|
||
case TRUTH_OR_EXPR:
|
||
case LT_EXPR:
|
||
case LE_EXPR:
|
||
case GT_EXPR:
|
||
case GE_EXPR:
|
||
case EQ_EXPR:
|
||
case NE_EXPR:
|
||
case TRUTH_ANDIF_EXPR:
|
||
case TRUTH_ORIF_EXPR:
|
||
case TRUTH_NOT_EXPR:
|
||
if (complain)
|
||
error ("not enough type information");
|
||
return error_mark_node;
|
||
|
||
case COND_EXPR:
|
||
if (type_unknown_p (TREE_OPERAND (rhs, 0)))
|
||
{
|
||
if (complain)
|
||
error ("not enough type information");
|
||
return error_mark_node;
|
||
}
|
||
TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
|
||
if (TREE_OPERAND (rhs, 1) == error_mark_node)
|
||
return error_mark_node;
|
||
TREE_OPERAND (rhs, 2) = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), complain);
|
||
if (TREE_OPERAND (rhs, 2) == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
TREE_TYPE (rhs) = lhstype;
|
||
return rhs;
|
||
|
||
case MODIFY_EXPR:
|
||
TREE_OPERAND (rhs, 1) = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain);
|
||
if (TREE_OPERAND (rhs, 1) == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
TREE_TYPE (rhs) = lhstype;
|
||
return rhs;
|
||
|
||
case ADDR_EXPR:
|
||
if (TREE_CODE (lhstype) != POINTER_TYPE)
|
||
{
|
||
if (complain)
|
||
error ("type for resolving address of overloaded function must be pointer type");
|
||
return error_mark_node;
|
||
}
|
||
TREE_TYPE (rhs) = lhstype;
|
||
lhstype = TREE_TYPE (lhstype);
|
||
TREE_OPERAND (rhs, 0) = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
|
||
if (TREE_OPERAND (rhs, 0) == error_mark_node)
|
||
return error_mark_node;
|
||
|
||
mark_addressable (TREE_OPERAND (rhs, 0));
|
||
return rhs;
|
||
|
||
case ENTRY_VALUE_EXPR:
|
||
assert (0);
|
||
return error_mark_node;
|
||
|
||
case ERROR_MARK:
|
||
return error_mark_node;
|
||
|
||
default:
|
||
assert (0);
|
||
return error_mark_node;
|
||
}
|
||
}
|
||
|
||
/* This routine is called when we finally know the type of expression
|
||
we are looking for. If the operator encoded by EXP can take an
|
||
argument of type TYPE, return the FUNCTION_DECL for that operator. */
|
||
tree
|
||
build_instantiated_decl (type, exp)
|
||
tree type, exp;
|
||
{
|
||
tree parmtypes, decl, name;
|
||
|
||
assert (TREE_CODE (exp) == OP_IDENTIFIER);
|
||
type = datatype (type);
|
||
if (TREE_CODE (type) != POINTER_TYPE
|
||
|| (TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE
|
||
&& TREE_CODE (TREE_TYPE (type)) != METHOD_TYPE))
|
||
{
|
||
error ("invalid type used to resolve overloaded function");
|
||
return error_mark_node;
|
||
}
|
||
|
||
|
||
/* Now we know the type of this function, so overload it. */
|
||
parmtypes = TYPE_ARG_TYPES (TREE_TYPE (type));
|
||
name = build_operator_fnname (&exp, parmtypes, 0);
|
||
if (name)
|
||
{
|
||
name = build_decl_overload (IDENTIFIER_POINTER (name), parmtypes, 1);
|
||
decl = lookup_name (name);
|
||
if (decl)
|
||
return decl;
|
||
error ("no suitable declaration of `operator %s' for overloading",
|
||
operator_name_string (name));
|
||
return error_mark_node;
|
||
}
|
||
return error_mark_node;
|
||
}
|
||
|
||
/* Return the name of the virtual function table (as an IDENTIFIER_NODE)
|
||
for the given TYPE. */
|
||
static tree
|
||
get_vtable_name (type)
|
||
tree type;
|
||
{
|
||
char *buf = (char *)alloca (sizeof (VTABLE_NAME_FORMAT)
|
||
+ TYPE_NAME_LENGTH (type) + 2);
|
||
sprintf (buf, VTABLE_NAME_FORMAT, TYPE_NAME_STRING (type));
|
||
return get_identifier (buf);
|
||
}
|
||
|
||
/* Return the name of the virtual function pointer field
|
||
(as an IDENTIFIER_NODE) for the given TYPE. Note that
|
||
this may have to look back through base types to find the
|
||
ultimate field name. (For single inheritance, these could
|
||
all be the same name. Who knows for multiple inheritance). */
|
||
static tree
|
||
get_vfield_name (type)
|
||
tree type;
|
||
{
|
||
char *buf;
|
||
|
||
while (CLASSTYPE_N_BASECLASSES (type)
|
||
&& TYPE_VIRTUAL_P (CLASSTYPE_BASECLASS (type, 1))
|
||
&& ! CLASSTYPE_VIA_VIRTUAL (type, 1))
|
||
type = CLASSTYPE_BASECLASS (type, 1);
|
||
|
||
buf = (char *)alloca (sizeof (VFIELD_NAME_FORMAT)
|
||
+ TYPE_NAME_LENGTH (type) + 2);
|
||
sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
|
||
return get_identifier (buf);
|
||
}
|
||
|
||
void
|
||
print_class_statistics ()
|
||
{
|
||
#ifdef GATHER_STATISTICS
|
||
fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
|
||
fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
|
||
fprintf (stderr, "build_method_call = %d (inner = %d)\n",
|
||
n_build_method_call, n_inner_fields_searched);
|
||
if (n_vtables)
|
||
{
|
||
fprintf (stderr, "vtables = %d; vtable searches = %d\n",
|
||
n_vtables, n_vtable_searches);
|
||
fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
|
||
n_vtable_entries, n_vtable_elems);
|
||
}
|
||
#endif
|
||
}
|