#include "config.h"
#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#include "rtl.h"
#include "output.h"
#include "toplev.h"
#include "splay-tree.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))
extern void set_class_shadows PROTO ((tree));
int current_class_depth;
typedef struct class_stack_node {
tree name;
tree type;
tree access;
splay_tree names_used;
}* class_stack_node_t;
static int current_class_stack_size;
static class_stack_node_t current_class_stack;
tree current_class_ptr, current_class_ref;
tree current_class_name;
tree current_class_type;
tree current_access_specifier;
tree previous_class_type;
tree previous_class_values;
static struct obstack class_cache_obstack;
char *class_cache_firstobj;
struct base_info;
static tree get_vfield_name PROTO((tree));
static void finish_struct_anon PROTO((tree));
static tree build_vbase_pointer PROTO((tree, tree));
static tree build_vtable_entry PROTO((tree, tree));
static tree get_vtable_name PROTO((tree));
static tree get_derived_offset PROTO((tree, tree));
static tree get_basefndecls PROTO((tree, tree));
static void set_rtti_entry PROTO((tree, tree, tree));
static tree build_vtable PROTO((tree, tree));
static void prepare_fresh_vtable PROTO((tree, tree));
static void fixup_vtable_deltas1 PROTO((tree, tree));
static void fixup_vtable_deltas PROTO((tree, int, tree));
static void finish_vtbls PROTO((tree, int, tree));
static void modify_vtable_entry PROTO((tree, tree, tree));
static tree get_vtable_entry_n PROTO((tree, unsigned HOST_WIDE_INT));
static void add_virtual_function PROTO((tree *, tree *, int *, tree, tree));
static tree delete_duplicate_fields_1 PROTO((tree, tree));
static void delete_duplicate_fields PROTO((tree));
static void finish_struct_bits PROTO((tree, int));
static int alter_access PROTO((tree, tree, tree, tree));
static void handle_using_decl PROTO((tree, tree, tree, tree));
static int overrides PROTO((tree, tree));
static int strictly_overrides PROTO((tree, tree));
static void merge_overrides PROTO((tree, tree, int, tree));
static void override_one_vtable PROTO((tree, tree, tree));
static void mark_overriders PROTO((tree, tree));
static void check_for_override PROTO((tree, tree));
static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
static tree get_class_offset PROTO((tree, tree, tree, tree));
static void modify_one_vtable PROTO((tree, tree, tree, tree));
static void modify_all_vtables PROTO((tree, tree, tree));
static void modify_all_direct_vtables PROTO((tree, int, tree, tree,
tree));
static void modify_all_indirect_vtables PROTO((tree, int, int, tree,
tree, tree));
static int finish_base_struct PROTO((tree, struct base_info *));
static void finish_struct_methods PROTO((tree));
static void maybe_warn_about_overly_private_class PROTO ((tree));
static tree make_method_vec PROTO((int));
static void free_method_vec PROTO((tree));
static tree add_implicitly_declared_members PROTO((tree, int, int, int));
static tree fixed_type_or_null PROTO((tree, int *));
static tree resolve_address_of_overloaded_function PROTO((tree, tree, int,
int, tree));
static void build_vtable_entry_ref PROTO((tree, tree, tree));
tree *current_lang_base, *current_lang_stack;
int current_lang_stacksize;
tree lang_name_c, lang_name_cplusplus, lang_name_java;
#ifdef OBJCPLUS
tree lang_name_objc;
#endif
tree current_lang_name;
static tree base_layout_decl;
tree access_default_node;
tree access_public_node;
tree access_protected_node;
tree access_private_node;
tree access_default_virtual_node;
tree access_public_virtual_node;
tree access_protected_virtual_node;
tree access_private_virtual_node;
#ifdef GATHER_STATISTICS
int n_vtables = 0;
int n_vtable_entries = 0;
int n_vtable_searches = 0;
int n_vtable_elems = 0;
int n_convert_harshness = 0;
int n_compute_conversion_costs = 0;
int n_build_method_call = 0;
int n_inner_fields_searched = 0;
#endif
static tree
build_vbase_pointer (exp, type)
tree exp, type;
{
char *name;
FORMAT_VBASE_NAME (name, type);
return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
}
#if 0
static int
complete_type_p (expr)
tree expr;
{
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
while (1)
{
switch (TREE_CODE (expr))
{
case SAVE_EXPR:
case INDIRECT_REF:
case ADDR_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
expr = TREE_OPERAND (expr, 0);
continue;
case CALL_EXPR:
if (! TREE_HAS_CONSTRUCTOR (expr))
break;
case VAR_DECL:
case FIELD_DECL:
if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (expr)))
&& TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
return 1;
case TARGET_EXPR:
case PARM_DECL:
if (IS_AGGR_TYPE (TREE_TYPE (expr))
&& TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
return 1;
case PLUS_EXPR:
default:
break;
}
break;
}
return 0;
}
#endif
tree
build_vbase_path (code, type, expr, path, nonnull)
enum tree_code code;
tree type, expr, path;
int nonnull;
{
register int changed = 0;
tree last = NULL_TREE, last_virtual = NULL_TREE;
int fixed_type_p;
tree null_expr = 0, nonnull_expr;
tree basetype;
tree offset = integer_zero_node;
if (path == NULL_TREE || BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
return build1 (NOP_EXPR, type, expr);
if (flag_this_is_variable > 0)
nonnull = 0;
fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
nonnull_expr = expr;
if (BINFO_INHERITANCE_CHAIN (path))
path = reverse_path (path);
basetype = BINFO_TYPE (path);
while (path)
{
if (TREE_VIA_VIRTUAL (path))
{
last_virtual = BINFO_TYPE (path);
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
if (changed)
{
tree ind;
if (last)
{
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
}
ind = build_indirect_ref (nonnull_expr, NULL_PTR);
nonnull_expr = build_vbase_pointer (ind, last_virtual);
if (nonnull == 0
&& TREE_CODE (type) == POINTER_TYPE
&& null_expr == NULL_TREE)
{
null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
expr = build (COND_EXPR, build_pointer_type (last_virtual),
build (EQ_EXPR, boolean_type_node, expr,
integer_zero_node),
null_expr, nonnull_expr);
}
}
if (nonnull_expr == error_mark_node)
return error_mark_node;
}
else
{
cp_error ("cannot cast up from virtual baseclass `%T'",
last_virtual);
return error_mark_node;
}
}
last = path;
path = BINFO_INHERITANCE_CHAIN (path);
}
if (null_expr)
{
TREE_OPERAND (expr, 2) = nonnull_expr;
TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1))
= TREE_TYPE (nonnull_expr);
}
else
expr = nonnull_expr;
if (changed)
{
tree intype = TREE_TYPE (TREE_TYPE (expr));
if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last))
{
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (intype), 0);
offset = BINFO_OFFSET (binfo);
}
}
else
{
if (last_virtual)
{
offset = BINFO_OFFSET (binfo_member (last_virtual,
CLASSTYPE_VBASECLASSES (basetype)));
offset = size_binop (PLUS_EXPR, offset, BINFO_OFFSET (last));
}
else
offset = (last != NULL_TREE) ? BINFO_OFFSET (last) : NULL_TREE;
}
if (offset != NULL_TREE && TREE_INT_CST_LOW (offset))
{
offset = cp_convert (type, offset);
#if 0
expr = build1 (NOP_EXPR, type, expr);
#endif
if (nonnull == 0)
{
if (null_expr)
TREE_TYPE (null_expr) = type;
else
null_expr = build1 (NOP_EXPR, type, integer_zero_node);
if (TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
return build (COND_EXPR, type,
build (EQ_EXPR, boolean_type_node, expr, integer_zero_node),
null_expr,
build (code, type, expr, offset));
}
else return build (code, type, expr, offset);
}
if (null_expr)
{
TREE_TYPE (expr) = type;
return expr;
}
else
return build1 (NOP_EXPR, type, expr);
}
static tree
build_vtable_entry (delta, pfn)
tree delta, pfn;
{
if (flag_vtable_thunks)
{
HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta);
if (idelta && ! DECL_ABSTRACT_VIRTUAL_P (TREE_OPERAND (pfn, 0)))
{
pfn = build1 (ADDR_EXPR, vtable_entry_type,
make_thunk (pfn, idelta));
TREE_READONLY (pfn) = 1;
TREE_CONSTANT (pfn) = 1;
}
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return pfn;
}
else
{
extern int flag_huge_objects;
tree elems = expr_tree_cons (NULL_TREE, delta,
expr_tree_cons (NULL_TREE, integer_zero_node,
build_expr_list (NULL_TREE, pfn)));
tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
if (! int_fits_type_p (delta, delta_type_node))
{
if (flag_huge_objects)
sorry ("object size exceeds built-in limit for virtual function table implementation");
else
sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
}
TREE_CONSTANT (entry) = 1;
TREE_STATIC (entry) = 1;
TREE_READONLY (entry) = 1;
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
}
static void
build_vtable_entry_ref (basetype, vtbl, idx)
tree basetype, vtbl, idx;
{
static char asm_stmt[] = ".vtable_entry %c0, %c1";
tree s, i, i2;
s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0);
s = build_tree_list (build_string (1, "s"), s);
i = build_array_ref (vtbl, idx);
if (!flag_vtable_thunks)
i = build_component_ref (i, pfn_identifier, vtable_entry_type, 0);
i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0));
i2 = build_array_ref (vtbl, build_int_2(0,0));
i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0));
i = build_binary_op (MINUS_EXPR, i, i2);
i = build_tree_list (build_string (1, "i"), i);
expand_asm_operands (build_string (sizeof(asm_stmt)-1, asm_stmt),
NULL_TREE, chainon (s, i), NULL_TREE, 1, NULL, 0);
}
tree
build_vfn_ref_using_vtable (basetype, vtbl, idx)
tree basetype;
tree vtbl;
tree idx;
{
tree aref;
assemble_external (vtbl);
if (flag_vtable_gc)
build_vtable_entry_ref (basetype, vtbl, idx);
aref = build_array_ref (vtbl, idx);
return aref;
}
tree
build_vtbl_ref (instance, idx)
tree instance, idx;
{
tree vtbl;
tree basetype = TREE_TYPE (instance);
if (TREE_CODE (basetype) == REFERENCE_TYPE)
basetype = TREE_TYPE (basetype);
if (instance == current_class_ref)
vtbl = build_vfield_ref (instance, basetype);
else
{
if (optimize)
{
tree ref = NULL_TREE;
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) == NON_LVALUE_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 (TREE_TYPE (instance))
&& (TREE_CODE (instance) == RESULT_DECL
|| TREE_CODE (instance) == PARM_DECL
|| TREE_CODE (instance) == VAR_DECL))
vtbl = TYPE_BINFO_VTABLE (basetype);
else
vtbl = build_vfield_ref (instance, basetype);
}
return build_vfn_ref_using_vtable (basetype, vtbl, idx);
}
tree
build_vfn_ref (ptr_to_instptr, instance, idx)
tree *ptr_to_instptr, instance;
tree idx;
{
tree aref = build_vtbl_ref (instance, idx);
if (flag_vtable_thunks)
return aref;
if (ptr_to_instptr)
{
if (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,
cp_convert (ptrdiff_type_node,
build_component_ref (aref, delta_identifier, NULL_TREE, 0)));
}
return build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
}
static tree
get_vtable_name (type)
tree type;
{
tree type_id = build_typename_overload (type);
char *buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT)
+ IDENTIFIER_LENGTH (type_id) + 2);
const char *ptr = IDENTIFIER_POINTER (type_id);
int i;
for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
#if 0
while (ptr[i] >= '0' && ptr[i] <= '9')
i += 1;
#endif
sprintf (buf, VTABLE_NAME_FORMAT, ptr+i);
return get_identifier (buf);
}
tree
get_vfield_offset (binfo)
tree binfo;
{
tree tmp
= size_binop (FLOOR_DIV_EXPR,
DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
size_int (BITS_PER_UNIT));
tmp = convert (sizetype, tmp);
return size_binop (PLUS_EXPR, tmp, BINFO_OFFSET (binfo));
}
static tree
get_derived_offset (binfo, type)
tree binfo, type;
{
tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
tree offset2;
int i;
while (BINFO_BASETYPES (binfo)
&& (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
{
tree binfos = BINFO_BASETYPES (binfo);
if (BINFO_TYPE (binfo) == type)
break;
binfo = TREE_VEC_ELT (binfos, i);
}
offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
return size_binop (MINUS_EXPR, offset1, offset2);
}
static void
set_rtti_entry (virtuals, offset, type)
tree virtuals, offset, type;
{
tree vfn;
if (CLASSTYPE_COM_INTERFACE (type))
return;
if (flag_rtti)
vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn (type));
else
vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, size_zero_node);
TREE_CONSTANT (vfn) = 1;
if (! flag_vtable_thunks)
TREE_VALUE (virtuals) = build_vtable_entry (offset, vfn);
else
{
tree voff = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
TREE_CONSTANT (voff) = 1;
TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, voff);
TREE_VALUE (TREE_CHAIN (virtuals))
= build_vtable_entry (integer_zero_node, vfn);
}
}
static tree
build_vtable (binfo, type)
tree binfo, type;
{
tree name = get_vtable_name (type);
tree virtuals, decl;
if (binfo)
{
tree offset;
virtuals = copy_list (BINFO_VIRTUALS (binfo));
decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo)));
offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE);
offset = ssize_binop (MINUS_EXPR, integer_zero_node, offset);
set_rtti_entry (virtuals, offset, type);
}
else
{
virtuals = NULL_TREE;
decl = build_lang_decl (VAR_DECL, name, void_type_node);
}
#ifdef GATHER_STATISTICS
n_vtables += 1;
n_vtable_elems += list_length (virtuals);
#endif
import_export_vtable (decl, type, 0);
decl = pushdecl_top_level (decl);
SET_IDENTIFIER_GLOBAL_VALUE (name, decl);
TYPE_BINFO_VTABLE (type) = decl;
TYPE_BINFO_VIRTUALS (type) = virtuals;
DECL_ARTIFICIAL (decl) = 1;
TREE_STATIC (decl) = 1;
#ifndef WRITABLE_VTABLES
TREE_READONLY (decl) = 1;
#endif
DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (decl));
DECL_VIRTUAL_P (decl) = 1;
DECL_CONTEXT (decl) = type;
binfo = TYPE_BINFO (type);
SET_BINFO_NEW_VTABLE_MARKED (binfo);
#ifdef NEXT_SEMANTICS
CLASSTYPE_VTABLE_DECL (type) = decl;
#endif
return decl;
}
extern tree signed_size_zero_node;
static void
prepare_fresh_vtable (binfo, for_type)
tree binfo, for_type;
{
tree basetype;
tree orig_decl = BINFO_VTABLE (binfo);
tree name;
tree new_decl;
tree offset;
tree path = binfo;
char *buf, *buf2;
char joiner = '_';
int i;
#ifdef JOINER
joiner = JOINER;
#endif
basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo));
buf2 = TYPE_ASSEMBLER_NAME_STRING (basetype);
i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1;
while (1)
{
char *buf1 = (char *) alloca (TYPE_ASSEMBLER_NAME_LENGTH (for_type)
+ 1 + i);
char *new_buf2;
sprintf (buf1, "%s%c%s", TYPE_ASSEMBLER_NAME_STRING (for_type), joiner,
buf2);
buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT) + strlen (buf1) + 1);
sprintf (buf, VTABLE_NAME_FORMAT, buf1);
name = get_identifier (buf);
if (! IDENTIFIER_GLOBAL_VALUE (name))
break;
path = BINFO_INHERITANCE_CHAIN (path);
my_friendly_assert (path != NULL_TREE, 368);
basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (path));
if (for_type == basetype)
{
int j = 2;
i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i + 1 + 3;
buf1 = (char *) alloca (i);
do {
sprintf (buf1, "%s%c%s%c%d",
TYPE_ASSEMBLER_NAME_STRING (basetype), joiner,
buf2, joiner, j);
buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT)
+ strlen (buf1) + 1);
sprintf (buf, VTABLE_NAME_FORMAT, buf1);
name = get_identifier (buf);
} while (++j <= 999 && IDENTIFIER_GLOBAL_VALUE (name));
my_friendly_assert (j <= 999, 369);
break;
}
i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i;
new_buf2 = (char *) alloca (i);
sprintf (new_buf2, "%s%c%s",
TYPE_ASSEMBLER_NAME_STRING (basetype), joiner, buf2);
buf2 = new_buf2;
}
new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
DECL_CONTEXT (new_decl) = for_type;
DECL_ARTIFICIAL (new_decl) = 1;
TREE_STATIC (new_decl) = 1;
BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
DECL_VIRTUAL_P (new_decl) = 1;
#ifndef WRITABLE_VTABLES
TREE_READONLY (new_decl) = 1;
#endif
DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);
BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
if (TREE_VIA_VIRTUAL (binfo))
{
tree binfo1 = binfo_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (for_type));
if (binfo1 != binfo)
warning ("internal inconsistency: binfo offset error for rtti");
offset = BINFO_OFFSET (binfo1);
}
else
offset = BINFO_OFFSET (binfo);
set_rtti_entry (BINFO_VIRTUALS (binfo),
ssize_binop (MINUS_EXPR, integer_zero_node, offset),
for_type);
#ifdef GATHER_STATISTICS
n_vtables += 1;
n_vtable_elems += list_length (BINFO_VIRTUALS (binfo));
#endif
import_export_vtable (new_decl, for_type, 0);
if (TREE_VIA_VIRTUAL (binfo))
my_friendly_assert (binfo == binfo_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (current_class_type)),
170);
SET_BINFO_NEW_VTABLE_MARKED (binfo);
}
#if 0
static tree
get_vtable_entry (virtuals, base_fndecl)
tree virtuals, base_fndecl;
{
unsigned HOST_WIDE_INT n = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
? (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl))
& (((unsigned HOST_WIDE_INT)1<<(BITS_PER_WORD-1))-1))
: TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)));
#ifdef GATHER_STATISTICS
n_vtable_searches += n;
#endif
while (n > 0 && virtuals)
{
--n;
virtuals = TREE_CHAIN (virtuals);
}
return virtuals;
}
#endif
static void
modify_vtable_entry (old_entry_in_list, new_entry, fndecl)
tree old_entry_in_list, new_entry, fndecl;
{
tree base_fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list)), 0);
#ifdef NOTQUITE
cp_warning ("replaced %D with %D", DECL_ASSEMBLER_NAME (base_fndecl),
DECL_ASSEMBLER_NAME (fndecl));
#endif
TREE_VALUE (old_entry_in_list) = new_entry;
if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
{
DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl);
DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl);
}
}
static tree
get_vtable_entry_n (virtuals, n)
tree virtuals;
unsigned HOST_WIDE_INT n;
{
while (n > 0)
{
--n;
virtuals = TREE_CHAIN (virtuals);
}
return virtuals;
}
static void
add_virtual_function (pv, phv, has_virtual, fndecl, t)
tree *pv, *phv;
int *has_virtual;
tree fndecl;
tree t;
{
tree pending_virtuals = *pv;
tree pending_hard_virtuals = *phv;
tree vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
TREE_CONSTANT (vfn) = 1;
#ifndef DUMB_USER
if (current_class_type == 0)
cp_warning ("internal problem, current_class_type is zero when adding `%D', please report",
fndecl);
if (current_class_type && t != current_class_type)
cp_warning ("internal problem, current_class_type differs when adding `%D', please report",
fndecl);
#endif
if (DECL_VINDEX (fndecl) == error_mark_node)
{
tree entry;
CLASSTYPE_RTTI (t) = t;
if (*has_virtual == 0 && ! CLASSTYPE_COM_INTERFACE (t))
{
if (flag_vtable_thunks)
*has_virtual = 2;
else
*has_virtual = 1;
}
{
static tree index_table[256];
tree idx;
int i = (*has_virtual)++;
if (i >= 256 || index_table[i] == 0)
{
idx = build_int_2 (i, 0);
if (i < 256)
index_table[i] = idx;
}
else
idx = index_table[i];
DECL_VINDEX (fndecl) = idx;
DECL_CONTEXT (fndecl) = t;
}
entry = build_vtable_entry (integer_zero_node, vfn);
pending_virtuals = tree_cons (DECL_VINDEX (fndecl), entry, pending_virtuals);
}
else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
{
pending_hard_virtuals = temp_tree_cons (fndecl, vfn, pending_hard_virtuals);
}
*pv = pending_virtuals;
*phv = pending_hard_virtuals;
}
struct obstack class_obstack;
extern struct obstack *current_obstack;
static tree free_method_vecs;
static tree
make_method_vec (n)
int n;
{
tree new_vec;
tree* t;
for (t = &free_method_vecs; *t; t = &(TREE_CHAIN (*t)))
if (TREE_VEC_LENGTH (*t) == n)
{
new_vec = *t;
*t = TREE_CHAIN (new_vec);
TREE_CHAIN (new_vec) = NULL_TREE;
bzero ((PTR) &TREE_VEC_ELT (new_vec, 0), n * sizeof (tree));
return new_vec;
}
new_vec = make_tree_vec (n);
return new_vec;
}
static void
free_method_vec (vec)
tree vec;
{
TREE_CHAIN (vec) = free_method_vecs;
free_method_vecs = vec;
}
void
add_method (type, fields, method)
tree type, *fields, method;
{
push_obstacks_nochange ();
end_temporary_allocation ();
DECL_CONTEXT (method) = type;
DECL_CLASS_CONTEXT (method) = type;
if (fields && *fields)
*fields = build_overload (method, *fields);
else
{
int len;
int slot;
tree method_vec;
if (!CLASSTYPE_METHOD_VEC (type))
CLASSTYPE_METHOD_VEC (type) = make_method_vec (8);
method_vec = CLASSTYPE_METHOD_VEC (type);
len = TREE_VEC_LENGTH (method_vec);
if (DECL_NAME (method) == constructor_name (type))
slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
else
{
for (slot = 2; slot < len; ++slot)
if (!TREE_VEC_ELT (method_vec, slot)
|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec,
slot)))
== DECL_NAME (method)))
break;
if (slot == len)
{
tree new_vec = make_method_vec (2 * len);
bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
(PTR) &TREE_VEC_ELT (new_vec, 0),
len * sizeof (tree));
free_method_vec (method_vec);
len = 2 * len;
method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
}
if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
{
for (slot = 2; slot < len; ++slot)
{
tree fn = TREE_VEC_ELT (method_vec, slot);
if (!fn)
break;
if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
break;
}
if (!TREE_VEC_ELT (method_vec, slot))
;
else
{
bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
(PTR) &TREE_VEC_ELT (method_vec, slot + 1),
(len - slot - 1) * sizeof (tree));
TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
}
}
}
if (template_class_depth (type))
;
else
{
tree fns;
for (fns = TREE_VEC_ELT (method_vec, slot);
fns;
fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
if (TREE_CODE (method) != TEMPLATE_DECL)
{
if (DECL_STATIC_FUNCTION_P (fn)
!= DECL_STATIC_FUNCTION_P (method))
{
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
else
parms2 = TREE_CHAIN (parms2);
if (compparms (parms1, parms2))
cp_error ("`%#D' and `%#D' cannot be overloaded",
fn, method);
}
if (DECL_ASSEMBLER_NAME (fn)
!= DECL_ASSEMBLER_NAME (method))
continue;
}
else if (!decls_match (fn, method))
continue;
cp_error_at ("`%D' has already been declared in `%T'",
method, type);
return;
}
}
TREE_VEC_ELT (method_vec, slot)
= build_overload (method, TREE_VEC_ELT (method_vec, slot));
if (!DECL_CONSTRUCTOR_P (method)
&& !DECL_DESTRUCTOR_P (method))
push_class_level_binding (DECL_NAME (method),
TREE_VEC_ELT (method_vec, slot));
}
pop_obstacks ();
}
static tree
delete_duplicate_fields_1 (field, fields)
tree field, fields;
{
tree x;
tree prev = 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, 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, 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)
cp_error_at ("duplicate enum value `%D'", x);
else if (TREE_CODE (field) == CONST_DECL
|| TREE_CODE (x) == CONST_DECL)
cp_error_at ("duplicate field `%D' (as enum and non-enum)",
x);
else if (DECL_DECLARES_TYPE_P (field)
&& DECL_DECLARES_TYPE_P (x))
{
if (same_type_p (TREE_TYPE (field), TREE_TYPE (x)))
continue;
cp_error_at ("duplicate nested type `%D'", x);
}
else if (DECL_DECLARES_TYPE_P (field)
|| DECL_DECLARES_TYPE_P (x))
{
if ((TREE_CODE (field) == TYPE_DECL
&& DECL_ARTIFICIAL (field))
|| (TREE_CODE (x) == TYPE_DECL
&& DECL_ARTIFICIAL (x)))
continue;
cp_error_at ("duplicate field `%D' (as type and non-type)",
x);
}
else
cp_error_at ("duplicate member `%D'", x);
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, TREE_CHAIN (x));
}
static int
alter_access (t, binfo, fdecl, access)
tree t;
tree binfo;
tree fdecl;
tree access;
{
tree elem = purpose_member (t, DECL_ACCESS (fdecl));
if (elem)
{
if (TREE_VALUE (elem) != access)
{
if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
cp_error_at ("conflicting access specifications for method `%D', ignored", TREE_TYPE (fdecl));
else
error ("conflicting access specifications for field `%s', ignored",
IDENTIFIER_POINTER (DECL_NAME (fdecl)));
}
else
{
;
}
}
else
{
enforce_access (binfo, fdecl);
DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
return 1;
}
return 0;
}
static void
handle_using_decl (using_decl, t, method_vec, fields)
tree using_decl;
tree t;
tree method_vec;
tree fields;
{
tree ctype = DECL_INITIAL (using_decl);
tree name = DECL_NAME (using_decl);
tree access
= TREE_PRIVATE (using_decl) ? access_private_node
: TREE_PROTECTED (using_decl) ? access_protected_node
: access_public_node;
tree fdecl, binfo;
tree flist = NULL_TREE;
tree tmp;
int i;
int n_methods;
binfo = binfo_or_else (ctype, t);
if (! binfo)
return;
if (name == constructor_name (ctype)
|| name == constructor_name_full (ctype))
{
cp_error_at ("using-declaration for constructor", using_decl);
return;
}
fdecl = lookup_member (binfo, name, 0, 0);
if (!fdecl)
{
cp_error_at ("no members matching `%D' in `%#T'", using_decl, ctype);
return;
}
if (TREE_CODE (fdecl) == TREE_LIST)
fdecl = TREE_VALUE (fdecl);
if (TREE_CODE (fdecl) == OVERLOAD)
{
flist = fdecl;
fdecl = OVL_FUNCTION (flist);
}
name = DECL_NAME (fdecl);
n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
for (i = 2; i < n_methods && TREE_VEC_ELT (method_vec, i); i++)
if (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i)))
== name)
{
cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
cp_error_at (" because of local method `%#D' with same name",
OVL_CURRENT (TREE_VEC_ELT (method_vec, i)));
return;
}
if (! DECL_LANG_SPECIFIC (fdecl))
return;
for (tmp = fields; tmp; tmp = TREE_CHAIN (tmp))
if (DECL_NAME (tmp) == name)
{
cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
cp_error_at (" because of local field `%#D' with same name", tmp);
return;
}
if (flist)
{
while (flist)
{
if (alter_access (t, binfo, OVL_FUNCTION (flist),
access) == 0)
return;
flist = OVL_CHAIN (flist);
}
}
else
alter_access (t, binfo, fdecl, access);
}
struct base_info
{
int has_virtual;
int max_has_virtual;
tree vfield;
tree vfields;
tree rtti;
char cant_have_default_ctor;
char cant_have_const_ctor;
char no_const_asn_ref;
};
static int
finish_base_struct (t, b)
tree t;
struct base_info *b;
{
tree binfos = TYPE_BINFO_BASETYPES (t);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
int first_vfn_base_index = -1;
bzero ((char *) b, sizeof (struct base_info));
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
if (warn_ecpp && ! TYPE_VIRTUAL_P (basetype)
&& TYPE_HAS_DESTRUCTOR (basetype))
cp_warning ("base class `%#T' has a non-virtual destructor", basetype);
if (TYPE_SIZE (basetype) == 0)
{
int j;
if (i == n_baseclasses-1)
TREE_VEC_ELT (binfos, i) = NULL_TREE;
TREE_VEC_LENGTH (binfos) -= 1;
n_baseclasses -= 1;
for (j = i; j+1 < n_baseclasses; j++)
TREE_VEC_ELT (binfos, j) = TREE_VEC_ELT (binfos, j+1);
}
if (! TYPE_HAS_CONST_INIT_REF (basetype))
b->cant_have_const_ctor = 1;
if (TYPE_HAS_CONSTRUCTOR (basetype)
&& ! TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype))
{
b->cant_have_default_ctor = 1;
if (! TYPE_HAS_CONSTRUCTOR (t))
{
cp_pedwarn ("base `%T' with only non-default constructor",
basetype);
cp_pedwarn ("in class without a constructor");
}
}
if (TYPE_HAS_ASSIGN_REF (basetype)
&& !TYPE_HAS_CONST_ASSIGN_REF (basetype))
b->no_const_asn_ref = 1;
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (basetype);
TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
TYPE_OVERLOADS_CALL_EXPR (t) |= TYPE_OVERLOADS_CALL_EXPR (basetype);
TYPE_OVERLOADS_ARRAY_REF (t) |= TYPE_OVERLOADS_ARRAY_REF (basetype);
TYPE_OVERLOADS_ARROW (t) |= TYPE_OVERLOADS_ARROW (basetype);
if (CLASSTYPE_COM_INTERFACE (basetype))
{
CLASSTYPE_COM_INTERFACE (t) = 1;
if (i > 0)
cp_error
("COM interface type `%T' must be the leftmost base class",
basetype);
}
else if (CLASSTYPE_COM_INTERFACE (t))
{
cp_error ("COM interface type `%T' with non-COM base class `%T'",
t, basetype);
CLASSTYPE_COM_INTERFACE (t) = 0;
}
if (TYPE_VIRTUAL_P (basetype))
{
if (b->rtti == NULL_TREE)
b->rtti = CLASSTYPE_RTTI (basetype);
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
if (first_vfn_base_index < 0)
{
tree vfields;
first_vfn_base_index = i;
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
b->has_virtual = CLASSTYPE_VSIZE (basetype);
b->vfield = CLASSTYPE_VFIELD (basetype);
b->vfields = copy_list (CLASSTYPE_VFIELDS (basetype));
vfields = b->vfields;
while (vfields)
{
if (VF_BINFO_VALUE (vfields) == NULL_TREE
|| ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields)))
{
tree value = VF_BASETYPE_VALUE (vfields);
if (DECL_NAME (CLASSTYPE_VFIELD (value))
== DECL_NAME (CLASSTYPE_VFIELD (basetype)))
VF_NORMAL_VALUE (b->vfields) = basetype;
else
VF_NORMAL_VALUE (b->vfields) = VF_NORMAL_VALUE (vfields);
}
vfields = TREE_CHAIN (vfields);
}
CLASSTYPE_VFIELD (t) = b->vfield;
}
else
{
tree vfields = CLASSTYPE_VFIELDS (basetype);
while (vfields)
{
if (VF_BINFO_VALUE (vfields) == NULL_TREE
|| ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields)))
{
tree value = VF_BASETYPE_VALUE (vfields);
b->vfields = tree_cons (base_binfo, value, b->vfields);
if (DECL_NAME (CLASSTYPE_VFIELD (value))
== DECL_NAME (CLASSTYPE_VFIELD (basetype)))
VF_NORMAL_VALUE (b->vfields) = basetype;
else
VF_NORMAL_VALUE (b->vfields) = VF_NORMAL_VALUE (vfields);
}
vfields = TREE_CHAIN (vfields);
}
if (b->has_virtual == 0)
{
first_vfn_base_index = i;
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
b->has_virtual = CLASSTYPE_VSIZE (basetype);
b->vfield = CLASSTYPE_VFIELD (basetype);
CLASSTYPE_VFIELD (t) = b->vfield;
vfields = b->vfields;
while (vfields)
{
if (DECL_NAME (CLASSTYPE_VFIELD (t))
== DECL_NAME (CLASSTYPE_VFIELD (basetype)))
{
VF_NORMAL_VALUE (vfields) = t;
break;
}
vfields = TREE_CHAIN (vfields);
}
}
}
}
}
{
tree vfields;
for (vfields = b->vfields; vfields; vfields = TREE_CHAIN (vfields))
{
if (CLASSTYPE_VSIZE (VF_BASETYPE_VALUE (vfields)) > b->max_has_virtual)
b->max_has_virtual = CLASSTYPE_VSIZE (VF_BASETYPE_VALUE (vfields));
if (VF_DERIVED_VALUE (vfields)
&& CLASSTYPE_VSIZE (VF_DERIVED_VALUE (vfields)) > b->max_has_virtual)
b->max_has_virtual = CLASSTYPE_VSIZE (VF_DERIVED_VALUE (vfields));
}
}
if (b->vfield == 0)
return -1;
b->rtti = CLASSTYPE_RTTI (BINFO_TYPE (TREE_VEC_ELT (binfos, first_vfn_base_index)));
return first_vfn_base_index;
}
static void
finish_struct_bits (t, max_has_virtual)
tree t;
int max_has_virtual;
{
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
tree variants = TYPE_NEXT_VARIANT (t);
while (variants)
{
TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t);
TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t);
TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
TYPE_NEEDS_DESTRUCTOR (variants) = TYPE_NEEDS_DESTRUCTOR (t);
TYPE_USES_COMPLEX_INHERITANCE (variants) = TYPE_USES_COMPLEX_INHERITANCE (t);
TYPE_VIRTUAL_P (variants) = TYPE_VIRTUAL_P (t);
TYPE_USES_VIRTUAL_BASECLASSES (variants) = TYPE_USES_VIRTUAL_BASECLASSES (t);
TYPE_MIN_VALUE (variants) = TYPE_MIN_VALUE (t);
TYPE_MAX_VALUE (variants) = TYPE_MAX_VALUE (t);
TYPE_FIELDS (variants) = TYPE_FIELDS (t);
TYPE_SIZE (variants) = TYPE_SIZE (t);
TYPE_SIZE_UNIT (variants) = TYPE_SIZE_UNIT (t);
variants = TYPE_NEXT_VARIANT (variants);
}
if (n_baseclasses && max_has_virtual)
{
CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
}
if (n_baseclasses)
{
tree binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (binfo);
tree basetype;
for (i = n_baseclasses-1; i >= 0; i--)
{
basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
TYPE_HAS_CONVERSION (t) |= TYPE_HAS_CONVERSION (basetype);
}
}
if (! TYPE_HAS_TRIVIAL_INIT_REF (t)
|| (TYPE_MODE (t) == BLKmode && ! aggregate_value_p (t)
&& CLASSTYPE_NON_AGGREGATE (t)))
{
tree variants;
DECL_MODE (TYPE_MAIN_DECL (t)) = BLKmode;
for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
{
TYPE_MODE (variants) = BLKmode;
TREE_ADDRESSABLE (variants) = 1;
}
}
}
static void
maybe_warn_about_overly_private_class (t)
tree t;
{
int has_member_fn = 0;
int has_nonprivate_method = 0;
tree fn;
if (!warn_ctor_dtor_privacy
|| (CLASSTYPE_FRIEND_CLASSES (t)
|| DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))
|| CLASSTYPE_TEMPLATE_INSTANTIATION (t))
return;
for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
if (!DECL_ARTIFICIAL (fn))
{
if (!TREE_PRIVATE (fn))
{
if (DECL_STATIC_FUNCTION_P (fn))
return;
has_nonprivate_method = 1;
break;
}
else if (!DECL_CONSTRUCTOR_P (fn) && !DECL_DESTRUCTOR_P (fn))
has_member_fn = 1;
}
if (!has_nonprivate_method && has_member_fn)
{
int i;
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); i++)
if (TREE_VIA_PUBLIC (TREE_VEC_ELT (binfos, i))
|| TREE_VIA_PROTECTED (TREE_VEC_ELT (binfos, i)))
{
has_nonprivate_method = 1;
break;
}
if (!has_nonprivate_method)
{
cp_warning ("all member functions in class `%T' are private", t);
return;
}
}
if (TYPE_HAS_DESTRUCTOR (t))
{
tree dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 1);
if (TREE_PRIVATE (dtor))
{
cp_warning ("`%#T' only defines a private destructor and has no friends",
t);
return;
}
}
if (TYPE_HAS_CONSTRUCTOR (t))
{
int nonprivate_ctor = 0;
if (!TYPE_HAS_INIT_REF (t))
nonprivate_ctor = 1;
else
for (fn = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 0);
fn;
fn = OVL_NEXT (fn))
{
tree ctor = OVL_CURRENT (fn);
if (! TREE_PRIVATE (ctor))
{
nonprivate_ctor = 1;
break;
}
}
if (nonprivate_ctor == 0)
{
cp_warning ("`%#T' only defines private constructors and has no friends",
t);
return;
}
}
}
static void
finish_struct_methods (t)
tree t;
{
tree fn_fields;
tree method_vec = CLASSTYPE_METHOD_VEC (t);
tree ctor_name = constructor_name (t);
for (fn_fields = TYPE_METHODS (t); fn_fields;
fn_fields = TREE_CHAIN (fn_fields))
{
tree fn_name = DECL_NAME (fn_fields);
DECL_IN_AGGR_P (fn_fields) = 0;
if (fn_name == ctor_name)
{
tree parmtypes = FUNCTION_ARG_CHAIN (fn_fields);
tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
if (TREE_CODE (parmtype) == REFERENCE_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == t)
{
if (TREE_CHAIN (parmtypes) == NULL_TREE
|| TREE_CHAIN (parmtypes) == void_list_node
|| TREE_PURPOSE (TREE_CHAIN (parmtypes)))
{
if (TREE_PROTECTED (fn_fields))
TYPE_HAS_NONPUBLIC_CTOR (t) = 1;
else if (TREE_PRIVATE (fn_fields))
TYPE_HAS_NONPUBLIC_CTOR (t) = 2;
}
}
}
else if (fn_name == ansi_opname[(int) MODIFY_EXPR])
{
tree parmtype = TREE_VALUE (FUNCTION_ARG_CHAIN (fn_fields));
if (copy_assignment_arg_p (parmtype, DECL_VIRTUAL_P (fn_fields)))
{
if (TREE_PROTECTED (fn_fields))
TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 1;
else if (TREE_PRIVATE (fn_fields))
TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 2;
}
}
}
if (TYPE_HAS_DESTRUCTOR (t) && !TREE_VEC_ELT (method_vec, 1))
TYPE_HAS_DESTRUCTOR (t) = 0;
maybe_warn_about_overly_private_class (t);
}
void
duplicate_tag_error (t)
tree t;
{
cp_error ("redefinition of `%#T'", t);
cp_error_at ("previous definition here", t);
if (CLASSTYPE_METHOD_VEC (t))
{
tree method_vec = CLASSTYPE_METHOD_VEC (t);
int i, len = TREE_VEC_LENGTH (method_vec);
for (i = 0; i < len; i++)
{
tree unchain = TREE_VEC_ELT (method_vec, i);
while (unchain != NULL_TREE)
{
TREE_CHAIN (OVL_CURRENT (unchain)) = NULL_TREE;
unchain = OVL_NEXT (unchain);
}
}
}
if (TYPE_LANG_SPECIFIC (t))
{
tree binfo = TYPE_BINFO (t);
int interface_only = CLASSTYPE_INTERFACE_ONLY (t);
int interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (t);
bzero ((char *) TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
BINFO_BASETYPES(binfo) = NULL_TREE;
TYPE_BINFO (t) = binfo;
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
TYPE_REDEFINED (t) = 1;
}
TYPE_SIZE (t) = NULL_TREE;
TYPE_MODE (t) = VOIDmode;
TYPE_FIELDS (t) = NULL_TREE;
TYPE_METHODS (t) = NULL_TREE;
TYPE_VFIELD (t) = NULL_TREE;
TYPE_CONTEXT (t) = NULL_TREE;
}
static void
finish_vtbls (binfo, do_self, t)
tree binfo;
int do_self;
tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
if (BINFO_NEW_VTABLE_MARKED (binfo))
{
tree decl, context;
decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0;
if (DECL_INITIAL (decl) != BINFO_VIRTUALS (binfo))
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE,
BINFO_VIRTUALS (binfo));
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
DECL_CONTEXT (decl) = context;
#ifdef NEXT_SEMANTICS
if (context == t)
CLASSTYPE_VTABLE_DECL (t) = decl;
#endif
}
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
}
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (t));
}
finish_vtbls (base_binfo, is_not_base_vtable, t);
}
}
static int
overrides (fndecl, base_fndecl)
tree fndecl, base_fndecl;
{
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
&& DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 1;
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
|| DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 0;
if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
{
tree types, base_types;
#if 0
retypes = TREE_TYPE (TREE_TYPE (fndecl));
base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
#endif
types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
== TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
&& compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
return 1;
}
return 0;
}
static tree
get_class_offset_1 (parent, binfo, context, t, fndecl)
tree parent, binfo, context, t, fndecl;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree rval = NULL_TREE;
if (binfo == parent)
return error_mark_node;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree nrval;
if (TREE_VIA_VIRTUAL (base_binfo))
base_binfo = binfo_member (BINFO_TYPE (base_binfo),
CLASSTYPE_VBASECLASSES (t));
nrval = get_class_offset_1 (parent, base_binfo, context, t, fndecl);
if (nrval && (nrval != error_mark_node || rval==0))
{
if (rval && rval != error_mark_node
&& ! tree_int_cst_equal (nrval, rval))
{
error ("every virtual function must have a unique final overrider");
cp_error (" found two (or more) `%T' class subobjects in `%T'", context, t);
cp_error (" with virtual `%D' from virtual base class", fndecl);
return rval;
}
rval = nrval;
}
if (rval && BINFO_TYPE (binfo) == context)
{
my_friendly_assert (rval == error_mark_node
|| tree_int_cst_equal (rval, BINFO_OFFSET (binfo)), 999);
rval = BINFO_OFFSET (binfo);
}
}
return rval;
}
static tree
get_class_offset (context, t, binfo, fndecl)
tree context, t, binfo, fndecl;
{
tree first_binfo = binfo;
tree offset;
int i;
if (context == t)
return integer_zero_node;
if (BINFO_TYPE (binfo) == context)
return BINFO_OFFSET (binfo);
while (BINFO_BASETYPES (binfo)
&& (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
{
tree binfos = BINFO_BASETYPES (binfo);
binfo = TREE_VEC_ELT (binfos, i);
if (BINFO_TYPE (binfo) == context)
return BINFO_OFFSET (binfo);
}
offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
my_friendly_abort (999);
return offset;
}
unsigned HOST_WIDE_INT
skip_rtti_stuff (virtuals, t)
tree *virtuals, t;
{
int n;
if (CLASSTYPE_COM_INTERFACE (t))
return 0;
n = 0;
if (*virtuals)
{
++n;
*virtuals = TREE_CHAIN (*virtuals);
}
if (flag_vtable_thunks && *virtuals)
{
++n;
*virtuals = TREE_CHAIN (*virtuals);
}
return n;
}
static void
modify_one_vtable (binfo, t, fndecl, pfn)
tree binfo, t, fndecl, pfn;
{
tree virtuals = BINFO_VIRTUALS (binfo);
unsigned HOST_WIDE_INT n;
if (flag_rtti)
{
if (binfo == TYPE_BINFO (t))
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
build_vtable (TYPE_BINFO (DECL_CONTEXT (CLASSTYPE_VFIELD (t))), t);
}
else
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
prepare_fresh_vtable (binfo, t);
}
}
if (fndecl == NULL_TREE)
return;
n = skip_rtti_stuff (&virtuals, t);
while (virtuals)
{
tree current_fndecl = TREE_VALUE (virtuals);
current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
current_fndecl = TREE_OPERAND (current_fndecl, 0);
if (current_fndecl && overrides (fndecl, current_fndecl))
{
tree base_offset, offset;
tree context = DECL_CLASS_CONTEXT (fndecl);
tree vfield = CLASSTYPE_VFIELD (t);
tree this_offset;
offset = get_class_offset (context, t, binfo, fndecl);
base_offset = size_binop (PLUS_EXPR,
get_derived_offset (binfo, DECL_CONTEXT (current_fndecl)),
BINFO_OFFSET (binfo));
this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
if (binfo == TYPE_BINFO (t))
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
}
else
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
prepare_fresh_vtable (binfo, t);
}
#ifdef NOTQUITE
cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo)));
#endif
modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
build_vtable_entry (this_offset, pfn),
fndecl);
}
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
static void
modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
tree binfo;
int do_self;
tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
modify_one_vtable (binfo, t, fndecl, pfn);
}
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
modify_all_direct_vtables (base_binfo, is_not_base_vtable, t, fndecl, pfn);
}
}
static void
fixup_vtable_deltas1 (binfo, t)
tree binfo, t;
{
tree virtuals = BINFO_VIRTUALS (binfo);
unsigned HOST_WIDE_INT n;
n = skip_rtti_stuff (&virtuals, t);
while (virtuals)
{
tree fndecl = TREE_VALUE (virtuals);
tree pfn = FNADDR_FROM_VTABLE_ENTRY (fndecl);
tree delta = DELTA_FROM_VTABLE_ENTRY (fndecl);
fndecl = TREE_OPERAND (pfn, 0);
if (fndecl)
{
tree base_offset, offset;
tree context = DECL_CLASS_CONTEXT (fndecl);
tree vfield = CLASSTYPE_VFIELD (t);
tree this_offset;
offset = get_class_offset (context, t, binfo, fndecl);
base_offset = size_binop (PLUS_EXPR,
get_derived_offset (binfo,
DECL_CONTEXT (fndecl)),
BINFO_OFFSET (binfo));
this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
if (! tree_int_cst_equal (this_offset, delta))
{
if (binfo == TYPE_BINFO (t))
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
}
else
{
if (! BINFO_NEW_VTABLE_MARKED (binfo))
prepare_fresh_vtable (binfo, t);
}
modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
build_vtable_entry (this_offset, pfn),
fndecl);
}
}
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
static void
fixup_vtable_deltas (binfo, init_self, t)
tree binfo;
int init_self;
tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
}
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
fixup_vtable_deltas1 (binfo, t);
}
}
static void
modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
tree binfo;
int do_self, via_virtual;
tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
if (do_self && via_virtual && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
modify_one_vtable (binfo, t, fndecl, pfn);
}
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
via_virtual = 1;
base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (t));
}
modify_all_indirect_vtables (base_binfo, is_not_base_vtable, via_virtual, t, fndecl, pfn);
}
}
static void
modify_all_vtables (t, fndecl, vfn)
tree t, fndecl, vfn;
{
modify_all_direct_vtables (TYPE_BINFO (t), 1, t, fndecl, vfn);
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
modify_all_indirect_vtables (TYPE_BINFO (t), 1, 0, t, fndecl, vfn);
}
static int
strictly_overrides (fndecl1, fndecl2)
tree fndecl1, fndecl2;
{
int distance = get_base_distance (DECL_CLASS_CONTEXT (fndecl2),
DECL_CLASS_CONTEXT (fndecl1),
0, (tree *)0);
if (distance == -2 || distance > 0)
return 1;
return 0;
}
static void
override_one_vtable (binfo, old, t)
tree binfo, old, t;
{
tree virtuals = BINFO_VIRTUALS (binfo);
tree old_virtuals = BINFO_VIRTUALS (old);
enum { REUSE_NEW, REUSE_OLD, UNDECIDED, NEITHER } choose = UNDECIDED;
if (BINFO_NEW_VTABLE_MARKED (binfo))
choose = NEITHER;
skip_rtti_stuff (&virtuals, t);
skip_rtti_stuff (&old_virtuals, t);
while (virtuals)
{
tree fndecl = TREE_VALUE (virtuals);
tree old_fndecl = TREE_VALUE (old_virtuals);
fndecl = FNADDR_FROM_VTABLE_ENTRY (fndecl);
old_fndecl = FNADDR_FROM_VTABLE_ENTRY (old_fndecl);
fndecl = TREE_OPERAND (fndecl, 0);
old_fndecl = TREE_OPERAND (old_fndecl, 0);
if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
{
}
else if (strictly_overrides (fndecl, old_fndecl))
{
if (choose == UNDECIDED)
choose = REUSE_NEW;
else if (choose == REUSE_OLD)
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
prepare_fresh_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
}
}
else if (strictly_overrides (old_fndecl, fndecl))
{
if (choose == UNDECIDED)
choose = REUSE_OLD;
else if (choose == REUSE_NEW)
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
prepare_fresh_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
}
else if (choose == NEITHER)
{
TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
}
}
else
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
prepare_fresh_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
{
tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
tree vfn;
fndecl = copy_node (fndecl);
copy_lang_decl (fndecl);
DECL_NEEDS_FINAL_OVERRIDER_P (fndecl) = 1;
if (! CLASSTYPE_ABSTRACT_VIRTUALS (t))
CLASSTYPE_ABSTRACT_VIRTUALS (t) = error_mark_node;
vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
TREE_CONSTANT (vfn) = 1;
TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn);
}
}
virtuals = TREE_CHAIN (virtuals);
old_virtuals = TREE_CHAIN (old_virtuals);
}
if (choose == REUSE_OLD)
{
BINFO_VTABLE (binfo) = BINFO_VTABLE (old);
BINFO_VIRTUALS (binfo) = BINFO_VIRTUALS (old);
}
}
static void
merge_overrides (binfo, old, do_self, t)
tree binfo, old;
int do_self;
tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
tree old_binfos = BINFO_BASETYPES (old);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
override_one_vtable (binfo, old, t);
}
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
merge_overrides (base_binfo, old_base_binfo, is_not_base_vtable, t);
}
}
static tree
get_basefndecls (fndecl, t)
tree fndecl, t;
{
tree methods = TYPE_METHODS (t);
tree base_fndecls = NULL_TREE;
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
while (methods)
{
if (TREE_CODE (methods) == FUNCTION_DECL
&& DECL_VINDEX (methods) != NULL_TREE
&& DECL_NAME (fndecl) == DECL_NAME (methods))
base_fndecls = temp_tree_cons (fndecl, methods, base_fndecls);
methods = TREE_CHAIN (methods);
}
if (base_fndecls)
return base_fndecls;
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
base_fndecls = chainon (get_basefndecls (fndecl, basetype),
base_fndecls);
}
return base_fndecls;
}
static void
mark_overriders (fndecl, base_fndecls)
tree fndecl, base_fndecls;
{
for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
{
if (overrides (fndecl, TREE_VALUE (base_fndecls)))
TREE_PURPOSE (base_fndecls) = fndecl;
}
}
static void
check_for_override (decl, ctype)
tree decl, ctype;
{
tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
int virtualp = DECL_VIRTUAL_P (decl);
int found_overriden_fn = 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo)))
{
tree tmp = get_matching_virtual
(base_binfo, decl,
DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
if (tmp && !found_overriden_fn)
{
DECL_VIRTUAL_P (decl) = 1;
if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
{
cp_error_at ("method `%D' may not be declared static",
decl);
cp_error_at ("(since `%D' declared virtual in base class.)",
tmp);
break;
}
virtualp = 1;
DECL_VINDEX (decl)
= tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
found_overriden_fn = 1;
}
}
}
if (virtualp)
{
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
}
}
void
warn_hidden (t)
tree t;
{
tree method_vec = CLASSTYPE_METHOD_VEC (t);
int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
int i;
for (i = 2; i < n_methods && TREE_VEC_ELT (method_vec, i); ++i)
{
tree fns = TREE_VEC_ELT (method_vec, i);
tree fndecl;
tree base_fndecls = NULL_TREE;
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (; fns; fns = OVL_NEXT (fns))
{
fndecl = OVL_CURRENT (fns);
if (DECL_VINDEX (fndecl))
break;
}
if (fns == NULL_TREE)
continue;
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
base_fndecls = chainon (get_basefndecls (fndecl, basetype),
base_fndecls);
}
fns = OVL_NEXT (fns);
if (base_fndecls)
for (; fns; fns = OVL_NEXT (fns))
{
fndecl = OVL_CURRENT (fns);
if (DECL_VINDEX (fndecl))
mark_overriders (fndecl, base_fndecls);
}
for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
{
if (! overrides (TREE_PURPOSE (base_fndecls),
TREE_VALUE (base_fndecls)))
{
cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
cp_warning_at (" by `%D'", TREE_PURPOSE (base_fndecls));
}
}
}
}
static void
finish_struct_anon (t)
tree t;
{
tree field;
for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
{
if (TREE_STATIC (field))
continue;
if (TREE_CODE (field) != FIELD_DECL)
continue;
if (DECL_NAME (field) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
tree* uelt = &TYPE_FIELDS (TREE_TYPE (field));
for (; *uelt; uelt = &TREE_CHAIN (*uelt))
{
if (DECL_ARTIFICIAL (*uelt))
continue;
if (DECL_NAME (*uelt) == constructor_name (t))
cp_pedwarn_at ("ANSI C++ forbids member `%D' with same name as enclosing class",
*uelt);
if (TREE_CODE (*uelt) != FIELD_DECL)
{
cp_pedwarn_at ("`%#D' invalid; an anonymous union can only have non-static data members",
*uelt);
continue;
}
if (TREE_PRIVATE (*uelt))
cp_pedwarn_at ("private member `%#D' in anonymous union",
*uelt);
else if (TREE_PROTECTED (*uelt))
cp_pedwarn_at ("protected member `%#D' in anonymous union",
*uelt);
TREE_PRIVATE (*uelt) = TREE_PRIVATE (field);
TREE_PROTECTED (*uelt) = TREE_PROTECTED (field);
}
}
}
}
extern int interface_only, interface_unknown;
static tree
add_implicitly_declared_members (t, cant_have_default_ctor,
cant_have_const_cctor,
cant_have_assignment)
tree t;
int cant_have_default_ctor;
int cant_have_const_cctor;
int cant_have_assignment;
{
tree default_fn;
tree implicit_fns = NULL_TREE;
tree name = TYPE_IDENTIFIER (t);
tree virtual_dtor = NULL_TREE;
tree *f;
if (TYPE_NEEDS_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t)
&& !IS_SIGNATURE (t))
{
default_fn = cons_up_default_function (t, name, 0);
check_for_override (default_fn, t);
if (default_fn == void_type_node)
TYPE_NEEDS_DESTRUCTOR (t) = 0;
else
{
TREE_CHAIN (default_fn) = implicit_fns;
implicit_fns = default_fn;
if (DECL_VINDEX (default_fn))
virtual_dtor = default_fn;
}
}
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor
#ifdef OBJCPLUS
&& !is_class_name (name)
#endif
&& ! IS_SIGNATURE (t))
{
default_fn = cons_up_default_function (t, name, 2);
TREE_CHAIN (default_fn) = implicit_fns;
implicit_fns = default_fn;
}
if (! TYPE_HAS_INIT_REF (t)
#ifdef OBJCPLUS
&& ! is_class_name (name)
#endif
&& ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t))
{
default_fn = cons_up_default_function (t, name,
3 + cant_have_const_cctor);
TREE_CHAIN (default_fn) = implicit_fns;
implicit_fns = default_fn;
}
if (! TYPE_HAS_ASSIGN_REF (t) && ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t))
{
default_fn = cons_up_default_function (t, name,
5 + cant_have_assignment);
TREE_CHAIN (default_fn) = implicit_fns;
implicit_fns = default_fn;
}
for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
add_method (t, 0, *f);
*f = TYPE_METHODS (t);
TYPE_METHODS (t) = implicit_fns;
return virtual_dtor;
}
void
finish_struct_1 (t, warn_anon)
tree t;
int warn_anon;
{
int old;
enum tree_code code = TREE_CODE (t);
tree fields = TYPE_FIELDS (t);
tree x, last_x, method_vec;
int has_virtual;
int max_has_virtual;
tree pending_virtuals = NULL_TREE;
tree pending_hard_virtuals = NULL_TREE;
tree abstract_virtuals = NULL_TREE;
tree vfield;
tree vfields;
tree virtual_dtor;
int cant_have_default_ctor;
int cant_have_const_ctor;
int no_const_asn_ref;
int has_mutable = 0;
int first_vfn_base_index;
int n_baseclasses;
int any_default_members = 0;
int const_sans_init = 0;
int ref_sans_init = 0;
tree access_decls = NULL_TREE;
int aggregate = 1;
int empty = 1;
int has_pointers = 0;
tree inline_friends;
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
pedwarn ("anonymous class type not used to declare any objects");
if (TYPE_SIZE (t))
{
if (IS_AGGR_TYPE (t))
cp_error ("redefinition of `%#T'", t);
else
my_friendly_abort (172);
popclass ();
return;
}
GNU_xref_decl (current_function_decl, t);
TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0;
#if 0
if (! IS_SIGNATURE (t))
{
my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
my_friendly_assert (CLASSTYPE_INTERFACE_KNOWN (t) == ! interface_unknown, 999);
}
#endif
old = suspend_momentary ();
if (TYPE_BINFO_BASETYPES (t))
n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t));
else
n_baseclasses = 0;
if (n_baseclasses > 0)
{
struct base_info base_info;
first_vfn_base_index = finish_base_struct (t, &base_info);
CLASSTYPE_VFIELD_PARENT (t) = first_vfn_base_index;
has_virtual = base_info.has_virtual;
max_has_virtual = base_info.max_has_virtual;
vfield = base_info.vfield;
vfields = base_info.vfields;
CLASSTYPE_RTTI (t) = base_info.rtti;
cant_have_default_ctor = base_info.cant_have_default_ctor;
cant_have_const_ctor = base_info.cant_have_const_ctor;
no_const_asn_ref = base_info.no_const_asn_ref;
aggregate = 0;
}
else
{
first_vfn_base_index = -1;
has_virtual = 0;
max_has_virtual = has_virtual;
vfield = NULL_TREE;
vfields = NULL_TREE;
CLASSTYPE_RTTI (t) = NULL_TREE;
cant_have_default_ctor = 0;
cant_have_const_ctor = 0;
no_const_asn_ref = 0;
}
#if 0
if (write_virtuals == 3 && CLASSTYPE_INTERFACE_KNOWN (t)
&& ! IS_SIGNATURE (t))
{
my_friendly_assert (CLASSTYPE_INTERFACE_ONLY (t) == interface_only, 999);
my_friendly_assert (CLASSTYPE_VTABLE_NEEDS_WRITING (t) == ! interface_only, 999);
}
#endif
CLASSTYPE_VFIELDS (t) = vfields;
CLASSTYPE_VFIELD (t) = vfield;
for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
{
GNU_xref_member (current_class_name, x);
if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))
continue;
DECL_SAVED_INSNS (x) = NULL_RTX;
DECL_FIELD_SIZE (x) = 0;
check_for_override (x, t);
if (DECL_ABSTRACT_VIRTUAL_P (x) && ! DECL_VINDEX (x))
cp_error_at ("initializer specified for non-virtual method `%D'", x);
if (DECL_VINDEX (x))
{
add_virtual_function (&pending_virtuals, &pending_hard_virtuals,
&has_virtual, x, t);
if (DECL_ABSTRACT_VIRTUAL_P (x))
abstract_virtuals = tree_cons (NULL_TREE, x, abstract_virtuals);
#if 0
else
TREE_USED (x) = 1;
#endif
}
}
if (n_baseclasses)
fields = chainon (build_vbase_pointer_fields (t), fields);
last_x = NULL_TREE;
for (x = fields; x; x = TREE_CHAIN (x))
{
GNU_xref_member (current_class_name, x);
if (TREE_CODE (x) == FIELD_DECL)
{
DECL_PACKED (x) |= TYPE_PACKED (t);
if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
;
else
empty = 0;
}
if (TREE_CODE (x) == USING_DECL)
{
if (last_x)
TREE_CHAIN (last_x) = TREE_CHAIN (x);
else
fields = TREE_CHAIN (x);
access_decls = scratch_tree_cons (NULL_TREE, x, access_decls);
continue;
}
last_x = x;
if (TREE_CODE (x) == TYPE_DECL
|| TREE_CODE (x) == TEMPLATE_DECL)
continue;
DECL_FIELD_CONTEXT (x) = t;
if (current_function_decl && TREE_STATIC (x))
cp_error_at ("field `%D' in local class cannot be static", x);
if (TREE_CODE (TREE_TYPE (x)) == FUNCTION_TYPE)
{
cp_error_at ("field `%D' invalidly declared function type",
x);
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
}
else if (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE)
{
cp_error_at ("field `%D' invalidly declared method type", x);
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
}
else if (TREE_CODE (TREE_TYPE (x)) == OFFSET_TYPE)
{
cp_error_at ("field `%D' invalidly declared offset type", x);
TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
}
#if 0
if (DECL_NAME (x) == constructor_name (t))
cant_have_default_ctor = 1;
#endif
if (TREE_TYPE (x) == error_mark_node)
continue;
DECL_SAVED_INSNS (x) = NULL_RTX;
DECL_FIELD_SIZE (x) = 0;
DECL_NONLOCAL (x) = 1;
if (TREE_CODE (x) == CONST_DECL)
continue;
if (TREE_CODE (x) == VAR_DECL)
{
if (TREE_CODE (t) == UNION_TYPE)
cp_error_at ("field `%D' declared static in union", x);
continue;
}
if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
aggregate = 0;
if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE)
{
if (DECL_INITIAL (x) == NULL_TREE)
ref_sans_init = 1;
cant_have_default_ctor = 1;
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
{
if (DECL_NAME (x))
cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
else
cp_warning_at ("non-static reference in class without a constructor", x);
}
}
if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE)
has_pointers = 1;
if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (TREE_TYPE (x)))
has_mutable = 1;
if (CP_TYPE_CONST_P (TREE_TYPE (x)))
{
C_TYPE_FIELDS_READONLY (t) = 1;
if (DECL_INITIAL (x) == NULL_TREE)
const_sans_init = 1;
cant_have_default_ctor = 1;
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && !IS_SIGNATURE (t)
&& extra_warnings)
{
if (DECL_NAME (x))
cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
else
cp_warning_at ("non-static const member in class without a constructor", x);
}
}
else
{
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;
}
}
if (DECL_C_BIT_FIELD (x))
{
if (DECL_INITIAL (x)
&& ! INTEGRAL_TYPE_P (TREE_TYPE (x)))
{
cp_error_at ("bit-field `%#D' with non-integral type", x);
DECL_INITIAL (x) = NULL;
}
if (DECL_INITIAL (x))
{
tree w = DECL_INITIAL (x);
register int width = 0;
STRIP_NOPS (w);
if (TREE_CODE (w) == CONST_DECL)
w = DECL_INITIAL (w);
else if (TREE_READONLY_DECL_P (w))
w = decl_constant_value (w);
if (TREE_CODE (w) != INTEGER_CST)
{
cp_error_at ("bit-field `%D' width not an integer constant",
x);
DECL_INITIAL (x) = NULL_TREE;
}
else if (width = TREE_INT_CST_LOW (w),
width < 0)
{
DECL_INITIAL (x) = NULL;
cp_error_at ("negative width in bit-field `%D'", x);
}
else if (width == 0 && DECL_NAME (x) != 0)
{
DECL_INITIAL (x) = NULL;
cp_error_at ("zero width for bit-field `%D'", x);
}
else if (width
> TYPE_PRECISION (long_long_unsigned_type_node))
{
DECL_INITIAL (x) = NULL;
sorry ("bit-fields larger than %d bits",
TYPE_PRECISION (long_long_unsigned_type_node));
cp_error_at (" in declaration of `%D'", x);
}
else if (width > TYPE_PRECISION (TREE_TYPE (x))
&& TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE)
{
cp_warning_at ("width of `%D' exceeds its type", x);
}
else if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
&& ((min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
TREE_UNSIGNED (TREE_TYPE (x))) > width)
|| (min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
TREE_UNSIGNED (TREE_TYPE (x))) > width)))
{
cp_warning_at ("`%D' is too small to hold all values of `%#T'",
x, TREE_TYPE (x));
}
if (DECL_INITIAL (x))
{
DECL_INITIAL (x) = NULL_TREE;
DECL_FIELD_SIZE (x) = width;
DECL_BIT_FIELD (x) = 1;
if (width == 0)
{
#ifdef EMPTY_FIELD_BOUNDARY
DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
EMPTY_FIELD_BOUNDARY);
#endif
#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS)
DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
TYPE_ALIGN (TREE_TYPE (x)));
#endif
}
}
}
else
DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
}
else
{
tree type = TREE_TYPE (x);
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x)
&& ! TYPE_PTRMEMFUNC_P (type))
{
if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
abstract_virtuals_error (x, type);
if (IS_SIGNATURE (type))
signature_error (x, type);
if (code == UNION_TYPE)
{
const char *fie = NULL;
if (TYPE_NEEDS_CONSTRUCTING (type))
fie = "constructor";
else if (TYPE_NEEDS_DESTRUCTOR (type))
fie = "destructor";
else if (TYPE_HAS_COMPLEX_ASSIGN_REF (type))
fie = "copy assignment operator";
if (fie)
cp_error_at ("member `%#D' with %s not allowed in union", x,
fie);
}
else
{
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (type);
TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
}
if (!TYPE_HAS_CONST_INIT_REF (type))
cant_have_const_ctor = 1;
if (!TYPE_HAS_CONST_ASSIGN_REF (type))
no_const_asn_ref = 1;
if (TYPE_HAS_CONSTRUCTOR (type)
&& ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
{
cant_have_default_ctor = 1;
#if 0
if (! TYPE_HAS_CONSTRUCTOR (t))
{
if (DECL_NAME (x))
cp_pedwarn_at ("member `%#D' with only non-default constructor", x);
else
cp_pedwarn_at ("member with only non-default constructor", x);
cp_pedwarn_at ("in class without a constructor",
x);
}
#endif
}
}
if (DECL_INITIAL (x) != NULL_TREE)
{
if (code == UNION_TYPE && any_default_members != 0)
cp_error_at ("multiple fields in union `%T' initialized");
any_default_members = 1;
}
}
}
CLASSTYPE_READONLY_FIELDS_NEED_INIT (t) = const_sans_init;
CLASSTYPE_REF_FIELDS_NEED_INIT (t) = ref_sans_init;
CLASSTYPE_ABSTRACT_VIRTUALS (t) = abstract_virtuals;
CLASSTYPE_HAS_MUTABLE (t) = has_mutable;
if (has_pointers && warn_ecpp && TYPE_HAS_CONSTRUCTOR (t)
&& ! (TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
{
cp_warning ("`%#T' has pointer data members", t);
if (! TYPE_HAS_INIT_REF (t))
{
cp_warning (" but does not override `%T(const %T&)'", t, t);
if (! TYPE_HAS_ASSIGN_REF (t))
cp_warning (" or `operator=(const %T&)'", t);
}
else if (! TYPE_HAS_ASSIGN_REF (t))
cp_warning (" but does not override `operator=(const %T&)'", t);
}
TYPE_HAS_COMPLEX_INIT_REF (t)
|= (TYPE_HAS_INIT_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
|| has_virtual || any_default_members);
TYPE_NEEDS_CONSTRUCTING (t)
|= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
|| has_virtual || any_default_members);
if (! IS_SIGNATURE (t))
CLASSTYPE_NON_AGGREGATE (t)
= ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
#if 0
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor
#ifdef OBJCPLUS
&& !is_class_name (name)
#endif
&& ! IS_SIGNATURE (t))
{
tree default_fn = cons_up_default_function (t, name, 2);
TREE_CHAIN (default_fn) = fn_fields;
fn_fields = default_fn;
}
if (! TYPE_HAS_INIT_REF (t)
#ifdef OBJCPLUS
&& ! is_class_name (name)
#endif
&& ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t))
{
tree default_fn = cons_up_default_function (t, name,
3 + cant_have_const_ctor);
TREE_CHAIN (default_fn) = fn_fields;
fn_fields = default_fn;
}
#endif
TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
virtual_dtor
= add_implicitly_declared_members (t, cant_have_default_ctor,
cant_have_const_ctor,
no_const_asn_ref);
if (virtual_dtor)
add_virtual_function (&pending_virtuals, &pending_hard_virtuals,
&has_virtual, virtual_dtor, t);
if (TYPE_METHODS (t))
{
finish_struct_methods (t);
method_vec = CLASSTYPE_METHOD_VEC (t);
}
else
{
method_vec = 0;
TYPE_HAS_CONSTRUCTOR (t) = 0;
TYPE_HAS_DESTRUCTOR (t) = 0;
}
for (access_decls = nreverse (access_decls); access_decls;
access_decls = TREE_CHAIN (access_decls))
handle_using_decl (TREE_VALUE (access_decls), t, method_vec, fields);
if (vfield == NULL_TREE && has_virtual)
{
vfield = build_lang_field_decl (FIELD_DECL, get_vfield_name (t),
vtbl_ptr_type_node);
DECL_ASSEMBLER_NAME (vfield) = get_identifier (VFIELD_BASE);
CLASSTYPE_VFIELD (t) = vfield;
DECL_VIRTUAL_P (vfield) = 1;
DECL_ARTIFICIAL (vfield) = 1;
DECL_FIELD_CONTEXT (vfield) = t;
DECL_CLASS_CONTEXT (vfield) = t;
DECL_FCONTEXT (vfield) = t;
DECL_SAVED_INSNS (vfield) = NULL_RTX;
DECL_FIELD_SIZE (vfield) = 0;
DECL_ALIGN (vfield) = TYPE_ALIGN (ptr_type_node);
#if 0
TREE_CHAIN (vfield) = fields;
fields = vfield;
#else
if (last_x)
{
my_friendly_assert (TREE_CHAIN (last_x) == NULL_TREE, 175);
TREE_CHAIN (last_x) = vfield;
last_x = vfield;
}
else
fields = vfield;
#endif
empty = 0;
vfields = chainon (vfields, build_tree_list (NULL_TREE, t));
}
delete_duplicate_fields (fields);
TYPE_FIELDS (t) = fields;
if (n_baseclasses)
{
last_x = build_base_fields (t);
for (x = last_x; empty && x; x = TREE_CHAIN (x))
if (DECL_SIZE (x) != integer_zero_node)
empty = 0;
}
inline_friends = CLASSTYPE_INLINE_FRIENDS (t);
CLASSTYPE_INLINE_FRIENDS (t) = NULL_TREE;
if (empty)
{
tree decl = build_lang_field_decl
(FIELD_DECL, NULL_TREE, char_type_node);
TREE_CHAIN (decl) = fields;
TYPE_FIELDS (t) = decl;
TYPE_NONCOPIED_PARTS (t)
= tree_cons (NULL_TREE, decl, TYPE_NONCOPIED_PARTS (t));
TREE_STATIC (TYPE_NONCOPIED_PARTS (t)) = 1;
}
if (n_baseclasses)
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
layout_type (t);
if (empty && flag_new_abi)
CLASSTYPE_SIZE (t) = integer_zero_node;
else if (flag_new_abi && TYPE_HAS_COMPLEX_INIT_REF (t)
&& TYPE_HAS_COMPLEX_ASSIGN_REF (t))
CLASSTYPE_SIZE (t) = TYPE_BINFO_SIZE (t);
else
CLASSTYPE_SIZE (t) = TYPE_SIZE (t);
CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
finish_struct_anon (t);
layout_decl (TYPE_MAIN_DECL (t), 0);
pending_hard_virtuals = nreverse (pending_hard_virtuals);
if (n_baseclasses)
max_has_virtual = layout_basetypes (t, max_has_virtual);
if (empty)
TYPE_FIELDS (t) = fields;
my_friendly_assert (TYPE_FIELDS (t) == fields, 981117);
while (fields && DECL_C_BIT_FIELD (fields)
&& DECL_INITIAL (fields))
fields = TREE_CHAIN (fields);
for (x = fields; x;)
{
if (TREE_CHAIN (x) && DECL_C_BIT_FIELD (TREE_CHAIN (x))
&& DECL_INITIAL (TREE_CHAIN (x)))
TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
else
x = TREE_CHAIN (x);
}
TYPE_FIELDS (t) = fields;
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
{
tree vbases;
vbases = CLASSTYPE_VBASECLASSES (t);
{
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
tree vbases;
vbases = CLASSTYPE_VBASECLASSES (basetype);
while (vbases)
{
merge_overrides (binfo_member (BINFO_TYPE (vbases),
CLASSTYPE_VBASECLASSES (t)),
vbases, 1, t);
vbases = TREE_CHAIN (vbases);
}
}
}
}
if (vfield != NULL_TREE
&& DECL_FIELD_CONTEXT (vfield) != t)
{
tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
tree offset = BINFO_OFFSET (binfo);
vfield = copy_node (vfield);
copy_lang_decl (vfield);
if (! integer_zerop (offset))
offset = size_binop (MULT_EXPR, offset, size_int (BITS_PER_UNIT));
DECL_FIELD_CONTEXT (vfield) = t;
DECL_CLASS_CONTEXT (vfield) = t;
DECL_FIELD_BITPOS (vfield)
= size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (vfield));
CLASSTYPE_VFIELD (t) = vfield;
}
#ifdef NOTQUITE
cp_warning ("Doing hard virtuals for %T...", t);
#endif
if (has_virtual > max_has_virtual)
max_has_virtual = has_virtual;
if (max_has_virtual > 0)
TYPE_VIRTUAL_P (t) = 1;
if (flag_rtti && TYPE_VIRTUAL_P (t) && !pending_hard_virtuals)
modify_all_vtables (t, NULL_TREE, NULL_TREE);
while (pending_hard_virtuals)
{
modify_all_vtables (t,
TREE_PURPOSE (pending_hard_virtuals),
TREE_VALUE (pending_hard_virtuals));
pending_hard_virtuals = TREE_CHAIN (pending_hard_virtuals);
}
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
{
tree vbases;
vbases = CLASSTYPE_VBASECLASSES (t);
while (vbases)
{
fixup_vtable_deltas (vbases, 1, t);
vbases = TREE_CHAIN (vbases);
}
}
if (pending_virtuals)
{
pending_virtuals = nreverse (pending_virtuals);
if (first_vfn_base_index < 0)
{
if (! CLASSTYPE_COM_INTERFACE (t))
{
if (flag_vtable_thunks)
pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
set_rtti_entry (pending_virtuals,
convert (ssizetype, integer_zero_node), t);
}
build_vtable (NULL_TREE, t);
}
else
{
if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))
build_vtable (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index), t);
}
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
else if (first_vfn_base_index >= 0)
{
tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index);
if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
if (max_has_virtual || first_vfn_base_index >= 0)
{
CLASSTYPE_VSIZE (t) = has_virtual;
if (first_vfn_base_index >= 0)
{
if (pending_virtuals)
TYPE_BINFO_VIRTUALS (t) = chainon (TYPE_BINFO_VIRTUALS (t),
pending_virtuals);
}
else if (has_virtual)
{
TYPE_BINFO_VIRTUALS (t) = pending_virtuals;
DECL_VIRTUAL_P (TYPE_BINFO_VTABLE (t)) = 1;
}
}
if (has_virtual)
{
tree itype = build_index_type (size_int (has_virtual));
tree atype = build_cplus_array_type (vtable_entry_type, itype);
layout_type (atype);
CLASSTYPE_VFIELD (t) = vfield;
if (TREE_TYPE (TYPE_BINFO_VTABLE (t)) != atype)
{
TREE_TYPE (TYPE_BINFO_VTABLE (t)) = atype;
DECL_SIZE (TYPE_BINFO_VTABLE (t)) = 0;
layout_decl (TYPE_BINFO_VTABLE (t), 0);
DECL_ALIGN (TYPE_BINFO_VTABLE (t))
= MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (TYPE_BINFO_VTABLE (t)));
}
}
else if (first_vfn_base_index >= 0)
CLASSTYPE_VFIELD (t) = vfield;
CLASSTYPE_VFIELDS (t) = vfields;
finish_struct_bits (t, max_has_virtual);
for (x = fields; x; x = TREE_CHAIN (x))
{
if (TREE_CODE (x) == VAR_DECL && TREE_STATIC (x)
&& TREE_TYPE (x) == t)
{
DECL_MODE (x) = TYPE_MODE (t);
make_decl_rtl (x, NULL, 0);
}
}
if (TYPE_HAS_CONSTRUCTOR (t))
{
tree vfields = CLASSTYPE_VFIELDS (t);
while (vfields)
{
if (VF_DERIVED_VALUE (vfields))
TREE_ADDRESSABLE (vfields) = 1;
vfields = TREE_CHAIN (vfields);
}
}
do_inline_function_hair (t, inline_friends);
if (CLASSTYPE_VSIZE (t) != 0)
{
#if 0
if (DECL_FIELD_CONTEXT (vfield) != t)
{
tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
tree offset = BINFO_OFFSET (binfo);
vfield = copy_node (vfield);
copy_lang_decl (vfield);
if (! integer_zerop (offset))
offset = size_binop (MULT_EXPR, offset, size_int (BITS_PER_UNIT));
DECL_FIELD_CONTEXT (vfield) = t;
DECL_CLASS_CONTEXT (vfield) = t;
DECL_FIELD_BITPOS (vfield)
= size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (vfield));
CLASSTYPE_VFIELD (t) = vfield;
}
#endif
TYPE_NONCOPIED_PARTS (t)
= tree_cons (default_conversion (TYPE_BINFO_VTABLE (t)),
vfield, TYPE_NONCOPIED_PARTS (t));
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
&& DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
cp_warning ("`%#T' has virtual functions but non-virtual destructor",
t);
}
finish_vtbls (TYPE_BINFO (t), 1, t);
hack_incomplete_structures (t);
#if 0
if (TYPE_NAME (t) && TYPE_IDENTIFIER (t))
undo_template_name_overload (TYPE_IDENTIFIER (t), 1);
#endif
resume_momentary (old);
if (warn_overloaded_virtual)
warn_hidden (t);
#if 0
if (write_symbols != DWARF_DEBUG)
{
if (DECL_CLASS_SCOPE_P (TYPE_MAIN_DECL (t)))
DECL_IGNORED_P (TYPE_MAIN_DECL (t)) = TREE_ASM_WRITTEN (TYPE_MAIN_DECL (t));
}
#endif
if (write_symbols != DWARF_DEBUG && write_symbols != DWARF2_DEBUG)
{
if (CLASSTYPE_METHOD_VEC (t))
{
if (CLASSTYPE_INTERFACE_ONLY (t))
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
#if 0
else if (CLASSTYPE_INTERFACE_UNKNOWN (t))
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
#endif
}
else if (CLASSTYPE_INTERFACE_ONLY (t))
TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
}
rest_of_type_compilation (t, toplevel_bindings_p ());
return;
}
void
unreverse_member_declarations (t)
tree t;
{
tree next;
tree prev;
tree x;
TYPE_METHODS (t) = nreverse (TYPE_METHODS (t));
CLASSTYPE_TAGS (t) = nreverse (CLASSTYPE_TAGS (t));
prev = NULL_TREE;
for (x = TYPE_FIELDS (t);
x && TREE_CODE (x) != TYPE_DECL;
x = next)
{
next = TREE_CHAIN (x);
TREE_CHAIN (x) = prev;
prev = x;
}
if (prev)
{
TREE_CHAIN (TYPE_FIELDS (t)) = x;
if (prev)
TYPE_FIELDS (t) = prev;
}
}
tree
finish_struct (t, attributes, warn_anon)
tree t, attributes;
int warn_anon;
{
tree name = TYPE_NAME (t);
if (TREE_CODE (name) == TYPE_DECL)
{
extern int lineno;
DECL_SOURCE_FILE (name) = input_filename;
if (DECL_SOURCE_LINE (name))
DECL_SOURCE_LINE (name) = lineno;
name = DECL_NAME (name);
}
if (IS_SIGNATURE (t))
append_signature_fields (t);
unreverse_member_declarations (t);
cplus_decl_attributes (t, attributes, NULL_TREE);
if (processing_template_decl)
{
tree d = getdecls ();
for (; d; d = TREE_CHAIN (d))
{
if ((TREE_CODE (d) == TYPE_DECL
&& (TREE_TYPE (d) == t
|| TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TYPE_PARM
|| TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TEMPLATE_PARM))
|| TREE_CODE (d) == CONST_DECL)
break;
else if (IDENTIFIER_TEMPLATE (DECL_NAME (d)))
continue;
DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t))
= tree_cons (NULL_TREE, d,
DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t)));
}
finish_struct_methods (t);
TYPE_SIZE (t) = integer_zero_node;
}
else
finish_struct_1 (t, warn_anon);
TYPE_BEING_DEFINED (t) = 0;
if (current_class_type)
popclass ();
else
error ("trying to finish struct, but kicked out due to previous parse errors.");
return t;
}
static tree
fixed_type_or_null (instance, nonnull)
tree instance;
int *nonnull;
{
switch (TREE_CODE (instance))
{
case INDIRECT_REF:
if (TREE_TYPE (instance)
== TREE_TYPE (TREE_TYPE (TREE_OPERAND (instance, 0))))
instance = TREE_OPERAND (instance, 0);
case CALL_EXPR:
if (TREE_HAS_CONSTRUCTOR (instance))
{
if (nonnull)
*nonnull = 1;
return TREE_TYPE (instance);
}
return NULL_TREE;
case SAVE_EXPR:
if (TREE_HAS_CONSTRUCTOR (instance))
{
if (nonnull)
*nonnull = 1;
return TREE_TYPE (instance);
}
return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull);
case RTL_EXPR:
return NULL_TREE;
case PLUS_EXPR:
case MINUS_EXPR:
if (TREE_CODE (TREE_OPERAND (instance, 1)) == INTEGER_CST)
fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull);
if (TREE_CODE (TREE_OPERAND (instance, 0)) == ADDR_EXPR)
return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull);
return NULL_TREE;
case NOP_EXPR:
case CONVERT_EXPR:
return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull);
case ADDR_EXPR:
if (nonnull)
*nonnull = 1;
return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull);
case COMPONENT_REF:
return fixed_type_or_null (TREE_OPERAND (instance, 1), nonnull);
case VAR_DECL:
case FIELD_DECL:
if (TREE_CODE (TREE_TYPE (instance)) == ARRAY_TYPE
&& IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (instance))))
{
if (nonnull)
*nonnull = 1;
return TREE_TYPE (TREE_TYPE (instance));
}
case TARGET_EXPR:
case PARM_DECL:
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
{
if (nonnull)
*nonnull = 1;
return TREE_TYPE (instance);
}
else if (nonnull)
{
if (instance == current_class_ptr
&& flag_this_is_variable <= 0)
{
if (flag_this_is_variable == 0)
*nonnull = 1;
if (flag_this_is_variable < 0)
return TREE_TYPE (TREE_TYPE (instance));
}
else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
*nonnull = 1;
}
return NULL_TREE;
default:
return NULL_TREE;
}
}
int
resolves_to_fixed_type_p (instance, nonnull)
tree instance;
int *nonnull;
{
tree t = TREE_TYPE (instance);
tree fixed = fixed_type_or_null (instance, nonnull);
if (fixed == NULL_TREE)
return 0;
if (POINTER_TYPE_P (t))
t = TREE_TYPE (t);
return same_type_p (TYPE_MAIN_VARIANT (t), TYPE_MAIN_VARIANT (fixed));
}
void
init_class_processing ()
{
current_class_depth = 0;
current_class_stack_size = 10;
current_class_stack
= (class_stack_node_t) xmalloc (current_class_stack_size
* sizeof (struct class_stack_node));
current_lang_stacksize = 10;
current_lang_base = (tree *)xmalloc(current_lang_stacksize * sizeof (tree));
current_lang_stack = current_lang_base;
access_default_node = build_int_2 (0, 0);
access_public_node = build_int_2 (1, 0);
access_protected_node = build_int_2 (2, 0);
access_private_node = build_int_2 (3, 0);
access_default_virtual_node = build_int_2 (4, 0);
access_public_virtual_node = build_int_2 (5, 0);
access_protected_virtual_node = build_int_2 (6, 0);
access_private_virtual_node = build_int_2 (7, 0);
base_layout_decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, error_mark_node);
TREE_TYPE (base_layout_decl) = make_node (RECORD_TYPE);
gcc_obstack_init (&class_obstack);
}
void
pushclass (type, modify)
tree type;
int modify;
{
type = TYPE_MAIN_VARIANT (type);
if (current_class_depth + 1 >= current_class_stack_size)
{
current_class_stack_size *= 2;
current_class_stack
= (class_stack_node_t) xrealloc (current_class_stack,
current_class_stack_size
* sizeof (struct class_stack_node));
}
current_class_stack[current_class_depth].name = current_class_name;
current_class_stack[current_class_depth].type = current_class_type;
current_class_stack[current_class_depth].access = current_access_specifier;
current_class_stack[current_class_depth].names_used = 0;
current_class_depth++;
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;
current_access_specifier = (CLASSTYPE_DECLARED_CLASS (type)
? access_private_node
: access_public_node);
if (previous_class_type != NULL_TREE
&& (type != previous_class_type
|| TYPE_SIZE (previous_class_type) == NULL_TREE)
&& current_class_depth == 1)
{
invalidate_class_lookup_cache ();
if (class_cache_firstobj)
obstack_free (&class_cache_obstack, class_cache_firstobj);
class_cache_firstobj
= (char*) obstack_finish (&class_cache_obstack);
}
if (modify && current_class_depth > 1)
clear_identifier_class_values ();
pushlevel_class ();
#if 0
if (CLASSTYPE_TEMPLATE_INFO (type))
overload_template_name (type);
#endif
if (modify)
{
if (type != previous_class_type || current_class_depth > 1)
push_class_decls (type);
else
{
tree item;
set_class_shadows (previous_class_values);
for (item = previous_class_values; item; item = TREE_CHAIN (item))
{
tree id = TREE_PURPOSE (item);
tree decl = TREE_TYPE (item);
push_class_binding (id, decl);
if (TREE_CODE (decl) == TYPE_DECL)
set_identifier_type_value (id, TREE_TYPE (decl));
}
unuse_fields (type);
}
storetags (CLASSTYPE_TAGS (type));
}
}
void
invalidate_class_lookup_cache ()
{
tree t;
for (t = previous_class_values; t; t = TREE_CHAIN (t))
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
previous_class_type = NULL_TREE;
}
void
popclass ()
{
poplevel (1, 0, 0);
pop_class_decls ();
current_class_depth--;
current_class_name = current_class_stack[current_class_depth].name;
current_class_type = current_class_stack[current_class_depth].type;
current_access_specifier = current_class_stack[current_class_depth].access;
if (current_class_stack[current_class_depth].names_used)
splay_tree_delete (current_class_stack[current_class_depth].names_used);
}
int
currently_open_class (t)
tree t;
{
int i;
if (t == current_class_type)
return 1;
for (i = 0; i < current_class_depth; ++i)
if (current_class_stack [i].type == t)
return 1;
return 0;
}
void
push_nested_class (type, modify)
tree type;
int modify;
{
tree context;
if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type)
|| TREE_CODE (type) == NAMESPACE_DECL
|| TREE_CODE (type) == TEMPLATE_TYPE_PARM
|| TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
return;
context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
if (context && CLASS_TYPE_P (context))
push_nested_class (context, 2);
pushclass (type, modify);
}
void
pop_nested_class ()
{
tree context = DECL_CONTEXT (TYPE_MAIN_DECL (current_class_type));
popclass ();
if (context && CLASS_TYPE_P (context))
pop_nested_class ();
}
void
push_lang_context (name)
tree name;
{
#ifdef OBJCPLUS
if(IDENTIFIER_POINTER (name) == IDENTIFIER_POINTER (lang_name_objc))
name = lang_name_objc;
if(IDENTIFIER_POINTER (name) == IDENTIFIER_POINTER (lang_name_c))
name = lang_name_c;
#endif
*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_java)
{
strict_prototype = strict_prototypes_lang_cplusplus;
current_lang_name = name;
DECL_IGNORED_P (java_byte_type_node) = 0;
DECL_IGNORED_P (java_short_type_node) = 0;
DECL_IGNORED_P (java_int_type_node) = 0;
DECL_IGNORED_P (java_long_type_node) = 0;
DECL_IGNORED_P (java_float_type_node) = 0;
DECL_IGNORED_P (java_double_type_node) = 0;
DECL_IGNORED_P (java_char_type_node) = 0;
DECL_IGNORED_P (java_boolean_type_node) = 0;
}
else if (name == lang_name_c)
{
strict_prototype = strict_prototypes_lang_c;
current_lang_name = name;
}
#ifdef OBJCPLUS
else if (name == lang_name_objc)
{
strict_prototype = strict_prototypes_lang_c;
current_lang_name = name;
}
#endif
else
error ("language string `\"%s\"' not recognized", IDENTIFIER_POINTER (name));
}
void
pop_lang_context ()
{
current_lang_name = *--current_lang_stack;
if (current_lang_name == lang_name_cplusplus
|| current_lang_name == lang_name_java)
strict_prototype = strict_prototypes_lang_cplusplus;
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;
#ifdef OBJCPLUS
else if (current_lang_name == lang_name_objc)
strict_prototype = strict_prototypes_lang_c;
#endif
}
static tree
resolve_address_of_overloaded_function (target_type,
overload,
complain,
template_only,
explicit_targs)
tree target_type;
tree overload;
int complain;
int template_only;
tree explicit_targs;
{
int is_ptrmem = 0;
int is_reference = 0;
tree matches = NULL_TREE;
tree fn;
my_friendly_assert (!(TREE_CODE (target_type) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (target_type))
== METHOD_TYPE)), 0);
if (TYPE_PTRFN_P (target_type))
;
else if (TYPE_PTRMEMFUNC_P (target_type))
is_ptrmem = 1;
else if (TREE_CODE (target_type) == FUNCTION_TYPE)
{
target_type = build_reference_type (target_type);
is_reference = 1;
}
else
{
if (complain)
cp_error("cannot resolve overloaded function `%D' based on conversion to type `%T'",
DECL_NAME (OVL_FUNCTION (overload)), target_type);
return error_mark_node;
}
if (!template_only)
{
tree fns;
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
tree fntype;
if (TREE_CODE (fn) == TEMPLATE_DECL)
continue;
if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
!= is_ptrmem)
continue;
fntype = TREE_TYPE (fn);
if (is_ptrmem)
fntype = build_ptrmemfunc_type (build_pointer_type (fntype));
else if (!is_reference)
fntype = build_pointer_type (fntype);
if (can_convert_arg (target_type, fntype, fn))
matches = scratch_tree_cons (fn, NULL_TREE, matches);
}
}
if (!matches)
{
tree target_fn_type;
tree target_arg_types;
tree fns;
if (is_ptrmem)
target_fn_type
= TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (target_type));
else
target_fn_type = TREE_TYPE (target_type);
target_arg_types = TYPE_ARG_TYPES (target_fn_type);
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
tree instantiation;
tree instantiation_type;
tree targs;
if (TREE_CODE (fn) != TEMPLATE_DECL)
continue;
if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
!= is_ptrmem)
continue;
targs = make_scratch_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs,
target_arg_types, NULL_TREE,
DEDUCE_EXACT) != 0)
continue;
instantiation = instantiate_template (fn, targs);
if (instantiation == error_mark_node)
continue;
instantiation_type = TREE_TYPE (instantiation);
if (is_ptrmem)
instantiation_type =
build_ptrmemfunc_type (build_pointer_type (instantiation_type));
else if (!is_reference)
instantiation_type = build_pointer_type (instantiation_type);
if (can_convert_arg (target_type, instantiation_type, instantiation))
matches = scratch_tree_cons (instantiation, fn, matches);
}
if (matches)
{
tree match = most_specialized_instantiation (matches,
explicit_targs);
if (match != error_mark_node)
matches = scratch_tree_cons (match, NULL_TREE, NULL_TREE);
}
}
if (matches == NULL_TREE)
{
if (complain)
{
cp_error ("no matches converting function `%D' to type `%#T'",
DECL_NAME (OVL_FUNCTION (overload)),
target_type);
for (; overload; overload = OVL_NEXT (overload))
matches = scratch_tree_cons (NULL_TREE, OVL_CURRENT (overload),
matches);
print_candidates (matches);
}
return error_mark_node;
}
else if (TREE_CHAIN (matches))
{
if (complain)
{
tree match;
cp_error ("converting overloaded function `%D' to type `%#T' is ambiguous",
DECL_NAME (OVL_FUNCTION (overload)),
target_type);
for (match = matches; match; match = TREE_CHAIN (match))
TREE_VALUE (match) = TREE_PURPOSE (match);
print_candidates (matches);
}
return error_mark_node;
}
fn = TREE_PURPOSE (matches);
mark_used (fn);
if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
return build_unary_op (ADDR_EXPR, fn, 0);
else
{
mark_addressable (fn);
return fn;
}
}
tree
instantiate_type (lhstype, rhs, flags)
tree lhstype, rhs;
int flags;
{
int complain = (flags & 1);
int strict = (flags & 2) ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
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)))
{
if (comptypes (lhstype, TREE_TYPE (rhs), strict))
return rhs;
if (complain)
cp_error ("argument of type `%T' does not match `%T'",
TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
if (TREE_CODE (rhs) != OVERLOAD)
rhs = copy_node (rhs);
switch (TREE_CODE (rhs))
{
case TYPE_EXPR:
case CONVERT_EXPR:
case SAVE_EXPR:
case CONSTRUCTOR:
case BUFFER_REF:
my_friendly_abort (177);
return error_mark_node;
case INDIRECT_REF:
case ARRAY_REF:
{
tree new_rhs;
new_rhs = instantiate_type (build_pointer_type (lhstype),
TREE_OPERAND (rhs, 0), flags);
if (new_rhs == error_mark_node)
return error_mark_node;
TREE_TYPE (rhs) = lhstype;
TREE_OPERAND (rhs, 0) = new_rhs;
return rhs;
}
case NOP_EXPR:
rhs = copy_node (TREE_OPERAND (rhs, 0));
TREE_TYPE (rhs) = unknown_type_node;
return instantiate_type (lhstype, rhs, flags);
case COMPONENT_REF:
{
tree field = TREE_OPERAND (rhs, 1);
tree r;
r = instantiate_type (lhstype, field, flags);
if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype))
{
if (complain)
{
tree t = TYPE_PTRMEMFUNC_OBJECT_TYPE (lhstype);
if (TREE_CODE (field) == OVERLOAD)
field = OVL_FUNCTION (field);
if (TREE_CODE (field) == FUNCTION_DECL)
{
cp_pedwarn ("object-dependent reference `%E' can only be used in a call",
DECL_NAME (field));
cp_pedwarn (" to form a pointer to member function, say `&%T::%E'",
t, DECL_NAME (field));
}
else
cp_pedwarn ("object-dependent reference can only be used in a call");
}
return r;
}
return r;
}
case OFFSET_REF:
rhs = TREE_OPERAND (rhs, 1);
if (BASELINK_P (rhs))
return instantiate_type (lhstype, TREE_VALUE (rhs), flags);
my_friendly_assert (TREE_CODE (rhs) == TEMPLATE_ID_EXPR, 0);
case TEMPLATE_ID_EXPR:
return
resolve_address_of_overloaded_function (lhstype,
TREE_OPERAND (rhs, 0),
complain,
1,
TREE_OPERAND (rhs, 1));
case OVERLOAD:
return
resolve_address_of_overloaded_function (lhstype,
rhs,
complain,
0,
NULL_TREE);
case TREE_LIST:
my_friendly_assert (BASELINK_P (rhs), 990412);
return instantiate_type (lhstype, TREE_VALUE (rhs), flags);
case CALL_EXPR:
my_friendly_abort (183);
return error_mark_node;
case PLUS_EXPR:
case MINUS_EXPR:
case COMPOUND_EXPR:
TREE_OPERAND (rhs, 0)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
if (TREE_OPERAND (rhs, 0) == error_mark_node)
return error_mark_node;
TREE_OPERAND (rhs, 1)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
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 ("invalid operation on uninstantiated type");
return error_mark_node;
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_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), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
TREE_OPERAND (rhs, 2)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
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), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
TREE_TYPE (rhs) = lhstype;
return rhs;
case ADDR_EXPR:
return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
return error_mark_node;
case ERROR_MARK:
return error_mark_node;
default:
my_friendly_abort (185);
return error_mark_node;
}
}
static tree
get_vfield_name (type)
tree type;
{
tree binfo = TYPE_BINFO (type);
char *buf;
while (BINFO_BASETYPES (binfo)
&& TYPE_VIRTUAL_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
&& ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
binfo = BINFO_BASETYPE (binfo, 0);
type = BINFO_TYPE (binfo);
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
}
void
push_cache_obstack ()
{
static int cache_obstack_initialized;
if (!cache_obstack_initialized)
{
gcc_obstack_init (&class_cache_obstack);
class_cache_firstobj
= (char*) obstack_finish (&class_cache_obstack);
cache_obstack_initialized = 1;
}
push_obstacks_nochange ();
current_obstack = &class_cache_obstack;
}
void
build_self_reference ()
{
tree name = constructor_name (current_class_type);
tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
tree saved_cas;
DECL_NONLOCAL (value) = 1;
DECL_CONTEXT (value) = current_class_type;
DECL_CLASS_CONTEXT (value) = current_class_type;
DECL_ARTIFICIAL (value) = 1;
saved_cas = current_access_specifier;
current_access_specifier = access_public_node;
finish_member_declaration (value);
current_access_specifier = saved_cas;
}
int
is_empty_class (type)
tree type;
{
tree t;
if (type == error_mark_node)
return 0;
if (! IS_AGGR_TYPE (type))
return 0;
if (flag_new_abi)
return CLASSTYPE_SIZE (type) == integer_zero_node;
if (TYPE_BINFO_BASETYPES (type))
return 0;
t = TYPE_FIELDS (type);
while (t && TREE_CODE (t) != FIELD_DECL)
t = TREE_CHAIN (t);
return (t == NULL_TREE);
}
tree
get_enclosing_class (type)
tree type;
{
tree node = type;
while (node && TREE_CODE (node) != NAMESPACE_DECL)
{
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
case 'd':
node = DECL_CONTEXT (node);
break;
case 't':
if (node != type)
return node;
node = TYPE_CONTEXT (node);
break;
default:
my_friendly_abort (0);
}
}
return NULL_TREE;
}
int
is_base_of_enclosing_class (base, type)
tree base, type;
{
while (type)
{
if (get_binfo (base, type, 0))
return 1;
type = get_enclosing_class (type);
}
return 0;
}
void
maybe_note_name_used_in_class (name, decl)
tree name;
tree decl;
{
splay_tree names_used;
if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type))
return;
if (IDENTIFIER_CLASS_VALUE (name))
return;
if (!current_class_stack[current_class_depth - 1].names_used)
current_class_stack[current_class_depth - 1].names_used
= splay_tree_new (splay_tree_compare_pointers, 0, 0);
names_used = current_class_stack[current_class_depth - 1].names_used;
splay_tree_insert (names_used,
(splay_tree_key) name,
(splay_tree_value) decl);
}
void
note_name_declared_in_class (name, decl)
tree name;
tree decl;
{
splay_tree names_used;
splay_tree_node n;
names_used
= current_class_stack[current_class_depth - 1].names_used;
if (!names_used)
return;
n = splay_tree_lookup (names_used, (splay_tree_key) name);
if (n)
{
cp_error ("declaration of `%#D'", decl);
cp_error_at ("changes meaning of `%s' from `%+#D'",
IDENTIFIER_POINTER (DECL_NAME (decl)),
(tree) n->value);
}
}