diff options
Diffstat (limited to 'gcc/cp/class.c')
-rwxr-xr-x | gcc/cp/class.c | 5669 |
1 files changed, 5669 insertions, 0 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c new file mode 100755 index 0000000..a219b7d --- /dev/null +++ b/gcc/cp/class.c @@ -0,0 +1,5669 @@ +/* Functions related to building classes and their related objects. + Copyright (C) 1987, 92-97, 1998, 1999 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@cygnus.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* High-level class interface. */ + +#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 "obstack.h" +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +extern struct obstack permanent_obstack; + +/* This is how we tell when two virtual member functions are really the + same. */ +#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL)) + +extern void set_class_shadows PROTO ((tree)); + +/* The number of nested classes being processed. If we are not in the + scope of any class, this is zero. */ + +int current_class_depth; + +/* In order to deal with nested classes, we keep a stack of classes. + The topmost entry is the innermost class, and is the entry at index + CURRENT_CLASS_DEPTH */ + +typedef struct class_stack_node { + /* The name of the class. */ + tree name; + + /* The _TYPE node for the class. */ + tree type; + + /* The access specifier pending for new declarations in the scope of + this class. */ + tree access; +}* class_stack_node_t; + +/* The stack itself. This is an dynamically resized array. The + number of elements allocated is CURRENT_CLASS_STACK_SIZE. */ +static int current_class_stack_size; +static class_stack_node_t current_class_stack; + +/* When we're processing a member function, current_class_ptr is the + PARM_DECL for the `this' pointer. The current_class_ref is an + expression for `*this'. */ +tree current_class_ptr, current_class_ref; + +/* The following two can be derived from the previous one */ +tree current_class_name; /* IDENTIFIER_NODE: name of current class */ +tree current_class_type; /* _TYPE: the type of the current class */ +tree current_access_specifier; +tree previous_class_type; /* _TYPE: the previous type that was a class */ +tree previous_class_values; /* TREE_LIST: copy of the class_shadowed list + when leaving an outermost class scope. */ + +/* The obstack on which the cached class declarations are kept. */ +static struct obstack class_cache_obstack; +/* The first object allocated on that obstack. We can use + obstack_free with tis value to free the entire obstack. */ +static 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 maybe_fixup_vptrs PROTO((tree, 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 void build_class_init_list PROTO((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 void check_member_decl_is_same_in_complete_scope PROTO((tree, 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)); + +/* Way of stacking language names. */ +tree *current_lang_base, *current_lang_stack; +int current_lang_stacksize; + +/* Names of languages we recognize. */ +tree lang_name_c, lang_name_cplusplus, lang_name_java; +tree current_lang_name; + +/* When layout out an aggregate type, the size of the + basetypes (virtual and non-virtual) is passed to layout_record + via this node. */ +static tree base_layout_decl; + +/* Constants used for access control. */ +tree access_default_node; /* 0 */ +tree access_public_node; /* 1 */ +tree access_protected_node; /* 2 */ +tree access_private_node; /* 3 */ +tree access_default_virtual_node; /* 4 */ +tree access_public_virtual_node; /* 5 */ +tree access_protected_virtual_node; /* 6 */ +tree access_private_virtual_node; /* 7 */ + +/* Variables shared between class.c and call.c. */ + +#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 + +/* Virtual baseclass things. */ + +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 +/* Is the type of the EXPR, the complete type of the object? + If we are going to be wrong, we must be conservative, and return 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; + /* fall through... */ + 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; + /* fall through... */ + case TARGET_EXPR: + case PARM_DECL: + if (IS_AGGR_TYPE (TREE_TYPE (expr)) + && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type) + return 1; + /* fall through... */ + case PLUS_EXPR: + default: + break; + } + break; + } + return 0; +} +#endif + +/* Build multi-level access to EXPR using hierarchy path PATH. + CODE is PLUS_EXPR if we are going with the grain, + and MINUS_EXPR if we are not (in which case, we cannot traverse + virtual baseclass links). + + TYPE is the type we want this path to have on exit. + + NONNULL is non-zero if we know (for any reason) that EXPR is + not, in fact, zero. */ + +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 (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE) + return build1 (NOP_EXPR, type, expr); + + /* If -fthis-is-variable, we might have set nonnull incorrectly. We + don't care enough to get this right, so just clear it. */ + if (flag_this_is_variable > 0) + nonnull = 0; + + /* We could do better if we had additional logic to convert back to the + unconverted type (the static type of the complete object), and then + convert back to the type we want. Until that is done, we only optimize + if the complete type is the same type as expr has. */ + 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; + + /* We already check for ambiguous things in the caller, just + find a path. */ + 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); + } + } + /* else we'll figure out the offset below. */ + + /* Happens in the case of parse errors. */ + 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); + } + /* LAST is now the last basetype assoc on the path. */ + + /* A pointer to a virtual base member of a non-null object + is non-null. Therefore, we only need to test for zeroness once. + Make EXPR the canonical expression to deal with here. */ + 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 we go through any virtual base pointers, make sure that + casts to BASETYPE from the last virtual base class use + the right value for BASETYPE. */ + if (changed) + { + tree intype = TREE_TYPE (TREE_TYPE (expr)); + if (TYPE_MAIN_VARIANT (intype) != 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 = BINFO_OFFSET (last); + } + + if (TREE_INT_CST_LOW (offset)) + { + /* Bash types to make the backend happy. */ + offset = cp_convert (type, offset); +#if 0 + /* This shouldn't be necessary. (mrs) */ + expr = build1 (NOP_EXPR, type, expr); +#endif + + /* If expr might be 0, we need to preserve that zeroness. */ + 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); + } + + /* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may + be used multiple times in initialization of multiple inheritance. */ + if (null_expr) + { + TREE_TYPE (expr) = type; + return expr; + } + else + return build1 (NOP_EXPR, type, expr); +} + +/* Virtual function things. */ + +/* Build an entry in the virtual function table. + DELTA is the offset for the `this' pointer. + PFN is an ADDR_EXPR containing a pointer to the virtual function. + Note that the index (DELTA2) in the virtual function table + is always 0. */ + +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); + + /* DELTA used to be constructed by `size_int' and/or size_binop, + which caused overflow problems when it was negative. That should + be fixed now. */ + + 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; + } +} + +/* We want to give the assembler the vtable identifier as well as + the offset to the function pointer. So we generate + + __asm__ __volatile__ (".vtable_entry %c0, %c1" + : : "s"(&class_vtable), + "i"((long)&vtbl[idx].pfn - (long)&vtbl[0])); */ + +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, 0); + 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); +} + +/* Given an object INSTANCE, return an expression which yields the + virtual function vtable element corresponding to INDEX. There are + many special cases for INSTANCE which we take care of here, mainly + to avoid creating extra tree nodes when we don't have to. */ + +tree +build_vtbl_ref (instance, idx) + tree instance, idx; +{ + tree vtbl, aref; + 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) + { + /* Try to figure out what a reference refers to, and + access its virtual function table directly. */ + 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); + } + + assemble_external (vtbl); + + if (flag_vtable_gc) + build_vtable_entry_ref (basetype, vtbl, idx); + + aref = build_array_ref (vtbl, idx); + + return aref; +} + +/* Given an object INSTANCE, return an expression which yields the + virtual function corresponding to INDEX. There are many special + cases for INSTANCE which we take care of here, mainly to avoid + creating extra tree nodes when we don't have to. */ + +tree +build_vfn_ref (ptr_to_instptr, instance, idx) + tree *ptr_to_instptr, instance; + tree idx; +{ + tree aref = build_vtbl_ref (instance, idx); + + /* When using thunks, there is no extra delta, and we get the pfn + directly. */ + if (flag_vtable_thunks) + return aref; + + if (ptr_to_instptr) + { + /* Save the intermediate result in a SAVE_EXPR so we don't have to + compute each component of the virtual function pointer twice. */ + 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); +} + +/* Return the name of the virtual function table (as an IDENTIFIER_NODE) + for the given TYPE. */ + +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); + char *ptr = IDENTIFIER_POINTER (type_id); + int i; + for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ; +#if 0 + /* We don't take off the numbers; prepare_fresh_vtable uses the + DECL_ASSEMBLER_NAME for the type, which includes the number + in `3foo'. If we were to pull them off here, we'd end up with + something like `_vt.foo.3bar', instead of a uniform definition. */ + while (ptr[i] >= '0' && ptr[i] <= '9') + i += 1; +#endif + sprintf (buf, VTABLE_NAME_FORMAT, ptr+i); + return get_identifier (buf); +} + +/* Return the offset to the main vtable for a given base BINFO. */ + +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)); +} + +/* Get the offset to the start of the original binfo that we derived + this binfo from. If we find TYPE first, return the offset only + that far. The shortened search is useful because the this pointer + on method calling is expected to point to a DECL_CONTEXT (fndecl) + object, and not a baseclass of it. */ + +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); +} + +/* Update the rtti info for this class. */ + +static void +set_rtti_entry (virtuals, offset, type) + tree virtuals, offset, type; +{ + tree vfn; + + 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); + + /* The second slot is for the tdesc pointer when thunks are used. */ + TREE_VALUE (TREE_CHAIN (virtuals)) + = build_vtable_entry (integer_zero_node, vfn); + } +} + +/* Build a virtual function for type TYPE. + If BINFO is non-NULL, build the vtable starting with the initial + approximation that it is the same as the one which is the head of + the association list. */ + +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_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo))); + + /* Now do rtti stuff. */ + 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_decl (VAR_DECL, name, void_type_node); + } + +#ifdef GATHER_STATISTICS + n_vtables += 1; + n_vtable_elems += list_length (virtuals); +#endif + + /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ + import_export_vtable (decl, type, 0); + + decl = pushdecl_top_level (decl); + SET_IDENTIFIER_GLOBAL_VALUE (name, decl); + /* Initialize the association list for this type, based + on our first approximation. */ + TYPE_BINFO_VTABLE (type) = decl; + TYPE_BINFO_VIRTUALS (type) = virtuals; + + DECL_ARTIFICIAL (decl) = 1; + TREE_STATIC (decl) = 1; +#ifndef WRITABLE_VTABLES + /* Make them READONLY by default. (mrs) */ + TREE_READONLY (decl) = 1; +#endif + /* At one time the vtable info was grabbed 2 words at a time. This + fails on sparc unless you have 8-byte alignment. (tiemann) */ + 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); + return decl; +} + +extern tree signed_size_zero_node; + +/* Give TYPE a new virtual function table which is initialized + with a skeleton-copy of its original initialization. The only + entry that changes is the `delta' entry, so we can really + share a lot of structure. + + FOR_TYPE is the derived type which caused this table to + be needed. + + BINFO is the type association which provided TYPE for FOR_TYPE. + + The order in which vtables are built (by calling this function) for + an object must remain the same, otherwise a binary incompatibility + can result. */ + +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; + + /* We know that the vtable that we are going to create doesn't exist + yet in the global namespace, and when we finish, it will be + pushed into the global namespace. In complex MI hierarchies, we + have to loop while the name we are thinking of adding is globally + defined, adding more name components to the vtable name as we + loop, until the name is unique. This is because in complex MI + cases, we might have the same base more than once. This means + that the order in which this function is called for vtables must + remain the same, otherwise binary compatibility can be + compromised. */ + + 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 this name doesn't clash, then we can use it, otherwise + we add more to the name until it is unique. */ + + if (! IDENTIFIER_GLOBAL_VALUE (name)) + break; + + /* Set values for next loop through, if the name isn't unique. */ + + path = BINFO_INHERITANCE_CHAIN (path); + + /* We better not run out of stuff to make it unique. */ + my_friendly_assert (path != NULL_TREE, 368); + + basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (path)); + + if (for_type == basetype) + { + /* If we run out of basetypes in the path, we have already + found created a vtable with that name before, we now + resort to tacking on _%d to distinguish them. */ + 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); + + /* If this name doesn't clash, then we can use it, + otherwise we add something different to the name until + it is unique. */ + } while (++j <= 999 && IDENTIFIER_GLOBAL_VALUE (name)); + + /* Hey, they really like MI don't they? Increase the 3 + above to 6, and the 999 to 999999. :-) */ + 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_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); + /* Remember which class this vtable is really for. */ + 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 + /* Make them READONLY by default. (mrs) */ + TREE_READONLY (new_decl) = 1; +#endif + DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl); + + /* Make fresh virtual list, so we can smash it later. */ + BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo)); + + if (TREE_VIA_VIRTUAL (binfo)) + { + tree binfo1 = binfo_member (BINFO_TYPE (binfo), + CLASSTYPE_VBASECLASSES (for_type)); + + /* XXX - This should never happen, if it does, the caller should + ensure that the binfo is from for_type's binfos, not from any + base type's. We can remove all this code after a while. */ + 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 + + /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ + 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 +/* Access the virtual function table entry that logically + contains BASE_FNDECL. VIRTUALS is the virtual function table's + initializer. We can run off the end, when dealing with virtual + destructors in MI situations, return NULL_TREE in that case. */ + +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 + +/* Put new entry ENTRY into virtual function table initializer + VIRTUALS. + + Also update DECL_VINDEX (FNDECL). */ + +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; + + /* Now assign virtual dispatch information, if unset. */ + /* We can dispatch this, through any overridden base function. */ + if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST) + { + DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl); + DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl); + } +} + +/* Access the virtual function table entry N. VIRTUALS is the virtual + function table's initializer. */ + +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; +} + +/* Add a virtual function to all the appropriate vtables for the class + T. DECL_VINDEX(X) should be error_mark_node, if we want to + allocate a new slot in our table. If it is error_mark_node, we + know that no other function from another vtable is overridden by X. + HAS_VIRTUAL keeps track of how many virtuals there are in our main + vtable for the type, and we build upon the PENDING_VIRTUALS list + and return it. */ + +static void +add_virtual_function (pv, phv, has_virtual, fndecl, t) + tree *pv, *phv; + int *has_virtual; + tree fndecl; + tree t; /* Structure type. */ +{ + tree pending_virtuals = *pv; + tree pending_hard_virtuals = *phv; + + /* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely + convert to void *. Make such a conversion here. */ + 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 the virtual function is a redefinition of a prior one, + figure out in which base class the new definition goes, + and if necessary, make a fresh virtual function table + to hold that entry. */ + if (DECL_VINDEX (fndecl) == error_mark_node) + { + tree entry; + + /* We remember that this was the base sub-object for rtti. */ + CLASSTYPE_RTTI (t) = t; + + /* If we are using thunks, use two slots at the front, one + for the offset pointer, one for the tdesc pointer. */ + if (*has_virtual == 0 && flag_vtable_thunks) + { + *has_virtual = 1; + } + + /* Build a new INT_CST for this DECL_VINDEX. */ + { + static tree index_table[256]; + tree idx; + /* We skip a slot for the offset/tdesc entry. */ + 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]; + + /* Now assign virtual dispatch information. */ + 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); + } + /* Might already be INTEGER_CST if declared twice in class. We will + give error later or we've already given it. */ + else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST) + { + /* Need an entry in some other virtual function table. + Deal with this after we have laid out our virtual base classes. */ + pending_hard_virtuals = temp_tree_cons (fndecl, vfn, pending_hard_virtuals); + } + *pv = pending_virtuals; + *phv = pending_hard_virtuals; +} + +/* Obstack on which to build the vector of class methods. */ +struct obstack class_obstack; +extern struct obstack *current_obstack; + +/* These are method vectors that were too small for the number of + methods in some class, and so were abandoned. */ +static tree free_method_vecs; + +/* Returns a method vector with enough room for N methods. N should + be a power of two. */ + +static tree +make_method_vec (n) + int n; +{ + tree new_vec; + tree* t; + + for (t = &free_method_vecs; *t; t = &(TREE_CHAIN (*t))) + /* Note that we don't use >= n here because we don't want to + allocate a very large vector where it isn't needed. */ + 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; +} + +/* Free the method vector VEC. */ + +static void +free_method_vec (vec) + tree vec; +{ + TREE_CHAIN (vec) = free_method_vecs; + free_method_vecs = vec; +} + +/* Add method METHOD to class TYPE. + + If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of + the class type where the method should be added. */ + +void +add_method (type, fields, method) + tree type, *fields, method; +{ + push_obstacks (&permanent_obstack, &permanent_obstack); + + /* Setting the DECL_CONTEXT and DECL_CLASS_CONTEXT here is probably + redundant. */ + DECL_CONTEXT (method) = type; + DECL_CLASS_CONTEXT (method) = type; + + if (fields && *fields) + *fields = build_overload (method, *fields); + else + { + int len; + tree method_vec; + + if (!CLASSTYPE_METHOD_VEC (type)) + /* Make a new method vector. We start with 8 entries. We must + allocate at least two (for constructors and destructors), and + we're going to end up with an assignment operator at some + point as well. + + We could use a TREE_LIST for now, and convert it to a + TREE_VEC in finish_struct, but we would probably waste more + memory making the links in the list than we would by + over-allocating the size of the vector here. Furthermore, + we would complicate all the code that expects this to be a + vector. We keep a free list of vectors that we outgrew so + that we don't really waste any memory. */ + 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)) + { + /* A new constructor or destructor. Constructors go in + slot 0; destructors go in slot 1. */ + int slot + = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0; + + TREE_VEC_ELT (method_vec, slot) + = build_overload (method, TREE_VEC_ELT (method_vec, slot)); + } + else + { + int i; + + /* See if we already have an entry with this name. */ + for (i = 2; i < len; ++i) + if (!TREE_VEC_ELT (method_vec, i) + || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i))) + == DECL_NAME (method))) + break; + + if (i == len) + { + /* We need a bigger method vector. */ + 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; + } + else if (template_class_depth (type)) + /* TYPE is a template class. Don't issue any errors now; + wait until instantiation time to complain. */ + ; + else + { + tree fns; + + /* Check to see if we've already got this method. */ + for (fns = TREE_VEC_ELT (method_vec, i); + fns; + fns = OVL_NEXT (fns)) + { + tree fn = OVL_CURRENT (fns); + + if (TREE_CODE (fn) != TREE_CODE (method)) + continue; + + if (TREE_CODE (method) != TEMPLATE_DECL) + { + /* [over.load] Member function declarations with the + same name and the same parameter types cannot be + overloaded if any of them is a static member + function declaration. */ + 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); + } + + /* Since this is an ordinary function in a + non-template class, it's mangled name can be + used as a unique identifier. This technique + is only an optimization; we would get the + same results if we just used decls_match + here. */ + if (DECL_ASSEMBLER_NAME (fn) + != DECL_ASSEMBLER_NAME (method)) + continue; + } + else if (!decls_match (fn, method)) + continue; + + /* There has already been a declaration of this + method or member template. */ + cp_error_at ("`%D' has already been declared in `%T'", + method, type); + + /* We don't call duplicate_decls here to merege the + declarations because that will confuse things if + the methods have inline definitions In + particular, we will crash while processing the + definitions. */ + return; + } + } + + if (TREE_VEC_ELT (method_vec, i)) + /* We found a match. */; + else if (DECL_CONV_FN_P (method)) + { + /* Type conversion operators have to come before + ordinary methods; add_conversions depends on this to + speed up looking for conversion operators. So, if + necessary, we slide some of the vector elements up. + In theory, this makes this algorithm O(N^2) but we + don't expect many conversion operators. */ + for (i = 2; i < len; ++i) + { + tree fn = TREE_VEC_ELT (method_vec, i); + + if (!fn) + /* There are no more entries in the vector, so we + can insert the new conversion operator here. */ + break; + + if (! DECL_CONV_FN_P (OVL_CURRENT (fn))) + /* We can insert the new function right at the Ith + position. */ + break; + } + + if (!TREE_VEC_ELT (method_vec, i)) + /* There is nothing in the Ith slot, so we can avoid + moving anything. */ + ; + else + { + /* We know the last slot in the vector is empty + because we know that at this point there's room for + a new function. */ + bcopy ((PTR) &TREE_VEC_ELT (method_vec, i), + (PTR) &TREE_VEC_ELT (method_vec, i + 1), + (len - i - 1) * sizeof (tree)); + TREE_VEC_ELT (method_vec, i) = NULL_TREE; + } + } + + /* Actually insert the new method. */ + TREE_VEC_ELT (method_vec, i) + = build_overload (method, TREE_VEC_ELT (method_vec, i)); + } + + if (TYPE_BINFO_BASETYPES (type) && CLASSTYPE_BASELINK_VEC (type)) + { + /* ??? May be better to know whether these can be extended? */ + tree baselink_vec = CLASSTYPE_BASELINK_VEC (type); + + TREE_VEC_LENGTH (baselink_vec) += 1; + CLASSTYPE_BASELINK_VEC (type) = copy_node (baselink_vec); + TREE_VEC_LENGTH (baselink_vec) -= 1; + + TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), len) = 0; + } + } + pop_obstacks (); +} + +/* Subroutines of finish_struct. */ + +/* Look through the list of fields for this struct, deleting + duplicates as we go. This must be recursive to handle + anonymous unions. + + FIELD is the field which may not appear anywhere in FIELDS. + FIELD_PTR, if non-null, is the starting point at which + chained deletions may take place. + The value returned is the first acceptable entry found + in FIELDS. + + Note that anonymous fields which are not of UNION_TYPE are + not duplicates, they are just anonymous fields. This happens + when we have unnamed bitfields, for example. */ + +static tree +delete_duplicate_fields_1 (field, 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)) + { + /* Hide tag decls. */ + 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)); +} + +/* Change the access of FDECL to ACCESS in T. The access to FDECL is + along the path given by BINFO. Return 1 if change was legit, + otherwise return 0. */ + +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 + { + /* They're changing the access to the same thing they changed + it to before. That's OK. */ + ; + } + } + else + { + enforce_access (binfo, fdecl); + + DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl)); + return 1; + } + return 0; +} + +/* Process the USING_DECL, which is a member of T. The METHOD_VEC, if + non-NULL, is the methods of T. The FIELDS are the fields of T. */ + +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; + } + + /* Functions are represented as TREE_LIST, with the purpose + being the type and the value the functions. Other members + come as themselves. */ + if (TREE_CODE (fdecl) == TREE_LIST) + /* Ignore base type this came from. */ + fdecl = TREE_VALUE (fdecl); + + if (TREE_CODE (fdecl) == OVERLOAD) + { + /* We later iterate over all functions. */ + 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)) + /* We don't currently handle DECL_ACCESS for TYPE_DECLs; just return. */ + 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; + } + + /* Make type T see field decl FDECL with access ACCESS.*/ + 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); +} + +/* If FOR_TYPE needs to reinitialize virtual function table pointers + for TYPE's sub-objects, add such reinitializations to BASE_INIT_LIST. + Returns BASE_INIT_LIST appropriately modified. */ + +static tree +maybe_fixup_vptrs (for_type, binfo, base_init_list) + tree for_type, binfo, base_init_list; +{ + /* Now reinitialize any slots that don't fall under our virtual + function table pointer. */ + tree vfields = CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)); + while (vfields) + { + tree basetype = VF_NORMAL_VALUE (vfields) + ? TYPE_MAIN_VARIANT (VF_NORMAL_VALUE (vfields)) + : VF_BASETYPE_VALUE (vfields); + + tree base_binfo = get_binfo (basetype, for_type, 0); + /* Punt until this is implemented. */ + if (1 /* BINFO_MODIFIED (base_binfo) */) + { + tree base_offset = get_vfield_offset (base_binfo); + if (! tree_int_cst_equal (base_offset, get_vfield_offset (TYPE_BINFO (for_type))) + && ! tree_int_cst_equal (base_offset, get_vfield_offset (binfo))) + base_init_list = tree_cons (error_mark_node, base_binfo, + base_init_list); + } + vfields = TREE_CHAIN (vfields); + } + return base_init_list; +} + +/* If TYPE does not have a constructor, then the compiler must + manually deal with all of the initialization this type requires. + + If a base initializer exists only to fill in the virtual function + table pointer, then we mark that fact with the TREE_VIRTUAL bit. + This way, we avoid multiple initializations of the same field by + each virtual function table up the class hierarchy. + + Virtual base class pointers are not initialized here. They are + initialized only at the "top level" of object creation. If we + initialized them here, we would have to skip a lot of work. */ + +static void +build_class_init_list (type) + tree type; +{ + tree base_init_list = NULL_TREE; + tree member_init_list = NULL_TREE; + + /* Since we build member_init_list and base_init_list using + tree_cons, backwards fields the all through work. */ + tree x; + tree binfos = BINFO_BASETYPES (TYPE_BINFO (type)); + int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; + + for (x = TYPE_FIELDS (type); x; x = TREE_CHAIN (x)) + { + if (TREE_CODE (x) != FIELD_DECL) + continue; + + if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (x)) + || DECL_INITIAL (x) != NULL_TREE) + member_init_list = tree_cons (x, type, member_init_list); + } + member_init_list = nreverse (member_init_list); + + /* We will end up doing this last. Need special marker + to avoid infinite regress. */ + if (TYPE_VIRTUAL_P (type)) + { + base_init_list = build_tree_list (error_mark_node, TYPE_BINFO (type)); + if (CLASSTYPE_NEEDS_VIRTUAL_REINIT (type) == 0) + TREE_VALUE (base_init_list) = NULL_TREE; + TREE_ADDRESSABLE (base_init_list) = 1; + } + + /* Each base class which needs to have initialization + of some kind gets to make such requests known here. */ + for (i = n_baseclasses-1; i >= 0; i--) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + tree blist; + + /* Don't initialize virtual baseclasses this way. */ + if (TREE_VIA_VIRTUAL (base_binfo)) + continue; + + if (TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (base_binfo))) + { + /* ...and the last shall come first... */ + base_init_list = maybe_fixup_vptrs (type, base_binfo, base_init_list); + base_init_list = tree_cons (NULL_TREE, base_binfo, base_init_list); + continue; + } + + if ((blist = CLASSTYPE_BASE_INIT_LIST (BINFO_TYPE (base_binfo))) == NULL_TREE) + /* Nothing to initialize. */ + continue; + + /* ...ditto... */ + base_init_list = maybe_fixup_vptrs (type, base_binfo, base_init_list); + + /* This is normally true for single inheritance. + The win is we can shrink the chain of initializations + to be done by only converting to the actual type + we are interested in. */ + if (TREE_VALUE (blist) + && TREE_CODE (TREE_VALUE (blist)) == TREE_VEC + && tree_int_cst_equal (BINFO_OFFSET (base_binfo), + BINFO_OFFSET (TREE_VALUE (blist)))) + { + if (base_init_list) + { + /* Does it do more than just fill in a + virtual function table pointer? */ + if (! TREE_ADDRESSABLE (blist)) + base_init_list = build_tree_list (blist, base_init_list); + /* Can we get by just with the virtual function table + pointer that it fills in? */ + else if (TREE_ADDRESSABLE (base_init_list) + && TREE_VALUE (base_init_list) == 0) + base_init_list = blist; + /* Maybe, but it is not obvious as the previous case. */ + else if (! CLASSTYPE_NEEDS_VIRTUAL_REINIT (type)) + { + tree last = tree_last (base_init_list); + while (TREE_VALUE (last) + && TREE_CODE (TREE_VALUE (last)) == TREE_LIST) + last = tree_last (TREE_VALUE (last)); + if (TREE_VALUE (last) == 0) + base_init_list = build_tree_list (blist, base_init_list); + } + } + else + base_init_list = blist; + } + else + { + /* The function expand_aggr_init knows how to do the + initialization of `basetype' without getting + an explicit `blist'. */ + if (base_init_list) + base_init_list = tree_cons (NULL_TREE, base_binfo, base_init_list); + else + base_init_list = CLASSTYPE_BINFO_AS_LIST (BINFO_TYPE (base_binfo)); + } + } + + if (base_init_list) + { + if (member_init_list) + CLASSTYPE_BASE_INIT_LIST (type) = + build_tree_list (base_init_list, member_init_list); + else + CLASSTYPE_BASE_INIT_LIST (type) = base_init_list; + } + else if (member_init_list) + CLASSTYPE_BASE_INIT_LIST (type) = member_init_list; +} + +struct base_info +{ + int has_virtual; + int max_has_virtual; + int n_ancestors; + tree vfield; + tree vfields; + tree rtti; + char cant_have_default_ctor; + char cant_have_const_ctor; + char no_const_asn_ref; +}; + +/* Record information about type T derived from its base classes. + Store most of that information in T itself, and place the + remaining information in the struct BASE_INFO. + + Propagate basetype offsets throughout the lattice. Note that the + lattice topped by T is really a pair: it's a DAG that gives the + structure of the derivation hierarchy, and it's a list of the + virtual baseclasses that appear anywhere in the DAG. When a vbase + type appears in the DAG, it's offset is 0, and it's children start + their offsets from that point. When a vbase type appears in the list, + its offset is the offset it has in the hierarchy, and its children's + offsets include that offset in theirs. + + Returns the index of the first base class to have virtual functions, + or -1 if no such base class. */ + +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); + + /* Effective C++ rule 14. We only need to check TYPE_VIRTUAL_P + here because the case of virtual functions but non-virtual + dtor is handled in finish_struct_1. */ + if (warn_ecpp && ! TYPE_VIRTUAL_P (basetype) + && TYPE_HAS_DESTRUCTOR (basetype)) + cp_warning ("base class `%#T' has a non-virtual destructor", basetype); + + /* If the type of basetype is incomplete, then + we already complained about that fact + (and we should have fixed it up as well). */ + if (TYPE_SIZE (basetype) == 0) + { + int j; + /* The base type is of incomplete type. It is + probably best to pretend that it does not + exist. */ + if (i == n_baseclasses-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; + + b->n_ancestors += CLASSTYPE_N_SUPERCLASSES (basetype); + 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 (! TREE_VIA_VIRTUAL (base_binfo)) + CLASSTYPE_N_SUPERCLASSES (t) += 1; + + if (TYPE_VIRTUAL_P (basetype)) + { + /* Ensure that this is set from at least a virtual base + class. */ + if (b->rtti == NULL_TREE) + b->rtti = CLASSTYPE_RTTI (basetype); + + /* Don't borrow virtuals from virtual baseclasses. */ + if (TREE_VIA_VIRTUAL (base_binfo)) + continue; + + if (first_vfn_base_index < 0) + { + tree vfields; + first_vfn_base_index = i; + + /* Update these two, now that we know what vtable we are + going to extend. This is so that we can add virtual + functions, and override them properly. */ + 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 + { + /* Only add unique vfields, and flatten them out as we go. */ + 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; + + /* Update these two, now that we know what vtable we are + going to extend. This is so that we can add virtual + functions, and override them properly. */ + 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; + /* When we install the first one, set the VF_NORMAL_VALUE + to be the current class, as this it is the most derived + class. Hopefully, this is not set to something else + later. (mrs) */ + vfields = b->vfields; + while (vfields) + { + if (DECL_NAME (CLASSTYPE_VFIELD (t)) + == DECL_NAME (CLASSTYPE_VFIELD (basetype))) + { + VF_NORMAL_VALUE (vfields) = t; + /* There should only be one of them! And it should + always be found, if we get into here. (mrs) */ + break; + } + vfields = TREE_CHAIN (vfields); + } + } + } + } + } + + { + tree vfields; + /* Find the base class with the largest number of virtual functions. */ + 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) + /* If all virtual functions come only from virtual baseclasses. */ + return -1; + + /* Update the rtti base if we have a non-virtual base class version + of it. */ + b->rtti = CLASSTYPE_RTTI (BINFO_TYPE (TREE_VEC_ELT (binfos, first_vfn_base_index))); + + return first_vfn_base_index; +} + +/* Set memoizing fields and bits of T (and its variants) for later use. + MAX_HAS_VIRTUAL is the largest size of any T's virtual function tables. */ + +static void +finish_struct_bits (t, max_has_virtual) + tree t; + int max_has_virtual; +{ + int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t); + + /* Fix up variants (if any). */ + tree variants = TYPE_NEXT_VARIANT (t); + while (variants) + { + /* These fields are in the _TYPE part of the node, not in + the TYPE_LANG_SPECIFIC component, so they are not shared. */ + 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); + /* Copy whatever these are holding today. */ + 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) + { + /* for a class w/o baseclasses, `finish_struct' has set + * CLASS_TYPE_ABSTRACT_VIRTUALS correctly (by definition). Similarly + * for a class who's base classes do not have vtables. When neither of + * these is true, we might have removed abstract virtuals (by + * providing a definition), added some (by declaring new ones), or + * redeclared ones from a base class. We need to recalculate what's + * really an abstract virtual at this point (by looking in the vtables). + */ + CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t); + } + + if (n_baseclasses) + { + /* Notice whether this class has type conversion functions defined. */ + 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 (CLASSTYPE_MAX_DEPTH (basetype) >= CLASSTYPE_MAX_DEPTH (t)) + CLASSTYPE_MAX_DEPTH (t) = CLASSTYPE_MAX_DEPTH (basetype) + 1; + } + } + + /* If this type has a copy constructor, force its mode to be BLKmode, and + force its TREE_ADDRESSABLE bit to be nonzero. This will cause it to + be passed by invisible reference and prevent it from being returned in + a register. + + Also do this if the class has BLKmode but can still be returned in + registers, since function_cannot_inline_p won't let us inline + functions returning such a type. This affects the HP-PA. */ + 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; + } + } +} + +/* Issue warnings about T having private constructors, but no friends, + and so forth. + + HAS_NONPRIVATE_METHOD is nonzero if T has any non-private methods or + static members. HAS_NONPRIVATE_STATIC_FN is nonzero if T has any + non-private static member functions. */ + +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 + /* If the class has friends, those entities might create and + access instances, so we should not warn. */ + || (CLASSTYPE_FRIEND_CLASSES (t) + || DECL_FRIENDLIST (TYPE_MAIN_DECL (t))) + /* We will have warned when the template was declared; there's + no need to warn on every instantiation. */ + || CLASSTYPE_TEMPLATE_INSTANTIATION (t)) + /* There's no reason to even consider warning about this + class. */ + return; + + /* We only issue one warning, if more than one applies, because + otherwise, on code like: + + class A { + // Oops - forgot `public:' + A(); + A(const A&); + ~A(); + }; + + we warn several times about essentially the same problem. */ + + /* Check to see if all (non-constructor, non-destructor) member + functions are private. (Since there are no friends or + non-private statics, we can't ever call any of the private member + functions.) */ + for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn)) + /* We're not interested in compiler-generated methods; they don't + provide any way to call private members. */ + if (!DECL_ARTIFICIAL (fn)) + { + if (!TREE_PRIVATE (fn)) + { + if (DECL_STATIC_FUNCTION_P (fn)) + /* A non-private static member function is just like a + friend; it can create and invoke private member + functions, and be accessed without a class + instance. */ + 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) + { + /* There are no non-private methods, and there's at least one + private member function that isn't a constructor or + destructor. (If all the private members are + constructors/destructors we want to use the code below that + issues error messages specifically referring to + constructors/destructors.) */ + 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; + } + } + + /* Even if some of the member functions are non-private, the class + won't be useful for much if all the constructors or destructors + are private: such an object can never be created or destroyed. */ + 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 a non-template class does not define a copy + constructor, one is defined for it, enabling it to avoid + this warning. For a template class, this does not + happen, and so we would normally get a warning on: + + template <class T> class C { private: C(); }; + + To avoid this asymmetry, we check TYPE_HAS_INIT_REF. All + complete non-template or fully instantiated classes have this + flag set. */ + 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); + /* Ideally, we wouldn't count copy constructors (or, in + fact, any constructor that takes an argument of the + class type as a parameter) because such things cannot + be used to construct an instance of the class unless + you already have one. But, for now at least, we're + more generous. */ + 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; + } + } +} + + +/* Warn about duplicate methods in fn_fields. Also compact method + lists so that lookup can be made faster. + + Data Structure: List of method lists. The outer list is a + TREE_LIST, whose TREE_PURPOSE field is the field name and the + TREE_VALUE is the DECL_CHAIN of the FUNCTION_DECLs. TREE_CHAIN + links the entire list of methods for TYPE_METHODS. Friends are + chained in the same way as member functions (? TREE_CHAIN or + DECL_CHAIN), but they live in the TREE_TYPE field of the outer + list. That allows them to be quickly deleted, and requires no + extra storage. + + If there are any constructors/destructors, they are moved to the + front of the list. This makes pushclass more efficient. + + We also link each field which has shares a name with its baseclass + to the head of the list of fields for that base class. This allows + us to reduce search time in places like `build_method_call' to + consider only reasonably likely functions. */ + +static void +finish_struct_methods (t) + tree t; +{ + tree fn_fields; + tree method_vec = CLASSTYPE_METHOD_VEC (t); + tree ctor_name = constructor_name (t); + int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t); + + /* First fill in entry 0 with the constructors, entry 1 with destructors, + and the next few with type conversion operators (if any). */ + for (fn_fields = TYPE_METHODS (t); fn_fields; + fn_fields = TREE_CHAIN (fn_fields)) + { + tree fn_name = DECL_NAME (fn_fields); + + /* Clear out this flag. + + @@ Doug may figure out how to break + @@ this with nested classes and friends. */ + DECL_IN_AGGR_P (fn_fields) = 0; + + /* Note here that a copy ctor is private, so we don't dare generate + a default copy constructor for a class that has a member + of this type without making sure they have access to it. */ + 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)) + /* We thought there was a destructor, but there wasn't. Some + parse errors cause this anomalous situation. */ + TYPE_HAS_DESTRUCTOR (t) = 0; + + /* Issue warnings about private constructors and such. If there are + no methods, then some public defaults are generated. */ + maybe_warn_about_overly_private_class (t); + + /* Now for each member function (except for constructors and + destructors), compute where member functions of the same + name reside in base classes. */ + if (n_baseclasses != 0 + && method_vec + && TREE_VEC_LENGTH (method_vec) > 2) + { + int len = TREE_VEC_LENGTH (method_vec); + tree baselink_vec = make_tree_vec (len); + int any_links = 0; + tree baselink_binfo = build_tree_list (NULL_TREE, TYPE_BINFO (t)); + + for (i = 2; i < len && TREE_VEC_ELT (method_vec, i); i++) + { + tree ovl = TREE_VEC_ELT (method_vec, i); + + TREE_VEC_ELT (baselink_vec, i) + = get_baselinks (baselink_binfo, t, + DECL_NAME (OVL_CURRENT (ovl))); + if (TREE_VEC_ELT (baselink_vec, i) != 0) + any_links = 1; + } + if (any_links != 0) + CLASSTYPE_BASELINK_VEC (t) = baselink_vec; + else + obstack_free (current_obstack, baselink_vec); + } +} + +/* Emit error when a duplicate definition of a type is seen. Patch up. */ + +void +duplicate_tag_error (t) + tree t; +{ + cp_error ("redefinition of `%#T'", t); + cp_error_at ("previous definition here", t); + + /* Pretend we haven't defined this type. */ + + /* All of the component_decl's were TREE_CHAINed together in the parser. + finish_struct_methods walks these chains and assembles all methods with + the same base name into DECL_CHAINs. Now we don't need the parser chains + anymore, so we unravel them. */ + + /* This used to be in finish_struct, but it turns out that the + TREE_CHAIN is used by dbxout_type_methods and perhaps some other + things... */ + 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 as_list = CLASSTYPE_AS_LIST (t); + tree binfo = TYPE_BINFO (t); + tree binfo_as_list = CLASSTYPE_BINFO_AS_LIST (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; + + CLASSTYPE_AS_LIST (t) = as_list; + TYPE_BINFO (t) = binfo; + CLASSTYPE_BINFO_AS_LIST (t) = binfo_as_list; + 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; +} + +/* finish up all new vtables. */ + +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; + + /* Should we use something besides CLASSTYPE_VFIELDS? */ + 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; + } + 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); + } +} + +/* True if we should override the given BASE_FNDECL with the given + FNDECL. */ + +static int +overrides (fndecl, base_fndecl) + tree fndecl, base_fndecl; +{ + /* Destructors have special names. */ + 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); + /* See if we have a new value */ + if (nrval && (nrval != error_mark_node || rval==0)) + { + /* Only compare if we have two offsets */ + if (rval && rval != error_mark_node + && ! tree_int_cst_equal (nrval, rval)) + { + /* Only give error if the two offsets are different */ + 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; +} + +/* Get the offset to the CONTEXT subobject that is related to the + given BINFO. */ + +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); + + /* Check less derived binfos first. */ + 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); + } + + /* Ok, not found in the less derived binfos, now check the more + derived binfos. */ + 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); /* we have to find it. */ + return offset; +} + +/* Skip RTTI information at the front of the virtual list. */ + +unsigned HOST_WIDE_INT +skip_rtti_stuff (virtuals) + tree *virtuals; +{ + int n; + + n = 0; + if (*virtuals) + { + /* We always reserve a slot for the offset/tdesc entry. */ + ++n; + *virtuals = TREE_CHAIN (*virtuals); + } + if (flag_vtable_thunks && *virtuals) + { + /* The second slot is reserved for the tdesc pointer when thunks + are used. */ + ++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; + + /* update rtti entry */ + 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); + + 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); + + /* Find the right offset for the this pointer based on the + base class we just found. We have to take into + consideration the virtual base class pointers that we + stick in before the virtual function table pointer. + + Also, we want just the delta between the most base class + that we derived this vfield from and us. */ + 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)) + { + /* In this case, it is *type*'s vtable we are modifying. + We start with the approximation that it's vtable is that + of the immediate base class. */ + if (! BINFO_NEW_VTABLE_MARKED (binfo)) + build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t); + } + else + { + /* This is our very own copy of `basetype' to play with. + Later, we will fill in all the virtual functions + that override the virtual functions in these base classes + which are not defined by the current type. */ + 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); + } +} + +/* These are the ones that are not through virtual base classes. */ + +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; + + /* Should we use something besides CLASSTYPE_VFIELDS? */ + 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); + } +} + +/* Fixup all the delta entries in this one vtable that need updating. */ + +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); + + 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); + + /* Find the right offset for the this pointer based on the + base class we just found. We have to take into + consideration the virtual base class pointers that we + stick in before the virtual function table pointer. + + Also, we want just the delta between the most base class + that we derived this vfield from and us. */ + 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)) + { + /* Make sure we can modify the derived association with immunity. */ + if (binfo == TYPE_BINFO (t)) + { + /* In this case, it is *type*'s vtable we are modifying. + We start with the approximation that it's vtable is that + of the immediate base class. */ + if (! BINFO_NEW_VTABLE_MARKED (binfo)) + build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t); + } + else + { + /* This is our very own copy of `basetype' to play with. + Later, we will fill in all the virtual functions + that override the virtual functions in these base classes + which are not defined by the current type. */ + 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); + } +} + +/* Fixup all the delta entries in all the direct vtables that need updating. + This happens when we have non-overridden virtual functions from a + virtual base class, that are at a different offset, in the new + hierarchy, because the layout of the virtual bases has changed. */ + +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); + } + /* Should we use something besides CLASSTYPE_VFIELDS? */ + if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) + { + fixup_vtable_deltas1 (binfo, t); + } +} + +/* These are the ones that are through virtual base classes. */ + +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; + + /* Should we use something besides CLASSTYPE_VFIELDS? */ + 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; +{ + /* Do these first, so that we will make use of any non-virtual class's + vtable, over a virtual classes vtable. */ + 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); +} + +/* Here, we already know that they match in every respect. + All we have to check is where they had their declarations. */ + +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; +} + +/* Merge overrides for one vtable. + If we want to merge in same function, we are fine. + else + if one has a DECL_CLASS_CONTEXT that is a parent of the + other, than choose the more derived one + else + potentially ill-formed (see 10.3 [class.virtual]) + we have to check later to see if there was an + override in this class. If there was ok, if not + then it is ill-formed. (mrs) + + We take special care to reuse a vtable, if we can. */ + +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 we have already committed to modifying it, then don't try and + reuse another vtable. */ + if (BINFO_NEW_VTABLE_MARKED (binfo)) + choose = NEITHER; + + skip_rtti_stuff (&virtuals); + skip_rtti_stuff (&old_virtuals); + + 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); + /* First check to see if they are the same. */ + if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl)) + { + /* No need to do anything. */ + } + 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; + } + { + /* This MUST be overridden, or the class is ill-formed. */ + 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; + /* Make sure we search for it later. */ + 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; + + /* We can use integer_zero_node, as we will core dump + if this is used anyway. */ + TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn); + } + } + virtuals = TREE_CHAIN (virtuals); + old_virtuals = TREE_CHAIN (old_virtuals); + } + + /* Let's reuse the old vtable. */ + if (choose == REUSE_OLD) + { + BINFO_VTABLE (binfo) = BINFO_VTABLE (old); + BINFO_VIRTUALS (binfo) = BINFO_VIRTUALS (old); + } +} + +/* Merge in overrides for virtual bases. + BINFO is the hierarchy we want to modify, and OLD has the potential + overrides. */ + +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; + + /* Should we use something besides CLASSTYPE_VFIELDS? */ + 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); + } +} + +/* Get the base virtual function declarations in T that are either + overridden or hidden by FNDECL as a list. We set TREE_PURPOSE with + the overrider/hider. */ + +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; +} + +/* Mark the functions that have been hidden with their overriders. + Since we start out with all functions already marked with a hider, + no need to mark functions that are just hidden. */ + +static void +mark_overriders (fndecl, base_fndecls) + tree fndecl, base_fndecls; +{ + while (base_fndecls) + { + if (overrides (TREE_VALUE (base_fndecls), fndecl)) + TREE_PURPOSE (base_fndecls) = fndecl; + + base_fndecls = TREE_CHAIN (base_fndecls); + } +} + +/* If this declaration supersedes the declaration of + a method declared virtual in the base class, then + mark this field as being virtual as well. */ + +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); + + 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) + { + /* If this function overrides some virtual in some base + class, then the function itself is also necessarily + virtual, even if the user didn't explicitly say so. */ + DECL_VIRTUAL_P (decl) = 1; + + /* The TMP we really want is the one from the deepest + baseclass on this path, taking care not to + duplicate if we have already found it (via another + path to its virtual baseclass. */ + 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; + +#if 0 /* The signature of an overriding function is not changed. */ + { + /* The argument types may have changed... */ + tree type = TREE_TYPE (decl); + tree argtypes = TYPE_ARG_TYPES (type); + tree base_variant = TREE_TYPE (TREE_VALUE (argtypes)); + tree raises = TYPE_RAISES_EXCEPTIONS (type); + + argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))), + TREE_CHAIN (argtypes)); + /* But the return type has not. */ + type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes); + if (raises) + type = build_exception_variant (type, raises); + TREE_TYPE (decl) = type; + } +#endif + DECL_VINDEX (decl) + = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl)); + break; + } + } + } + if (virtualp) + { + if (DECL_VINDEX (decl) == NULL_TREE) + DECL_VINDEX (decl) = error_mark_node; + IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1; + } +} + +/* Warn about hidden virtual functions that are not overridden in t. + We know that constructors and destructors don't apply. */ + +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; + + /* We go through each separately named virtual function. */ + 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; + + fndecl = OVL_CURRENT (fns); + if (DECL_VINDEX (fndecl) == NULL_TREE) + continue; + + /* First we get a list of all possible functions that might be + hidden from each base class. */ + 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 (fns) + fndecl = OVL_CURRENT (fns); + else + fndecl = NULL_TREE; + + /* ...then mark up all the base functions with overriders, preferring + overriders to hiders. */ + if (base_fndecls) + while (fndecl) + { + mark_overriders (fndecl, base_fndecls); + + fns = OVL_NEXT (fns); + if (fns) + fndecl = OVL_CURRENT (fns); + else + fndecl = NULL_TREE; + } + + /* Now give a warning for all base functions without overriders, + as they are hidden. */ + while (base_fndecls) + { + if (! overrides (TREE_VALUE (base_fndecls), + TREE_PURPOSE (base_fndecls))) + { + /* Here we know it is a hider, and no overrider exists. */ + cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls)); + cp_warning_at (" by `%D'", TREE_PURPOSE (base_fndecls)); + } + + base_fndecls = TREE_CHAIN (base_fndecls); + } + } +} + +/* Check for things that are invalid. There are probably plenty of other + things we should check for also. */ + +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; + +/* Create default constructors, assignment operators, and so forth for + the type indicated by T, if they are needed. + CANT_HAVE_DEFAULT_CTOR, CANT_HAVE_CONST_CTOR, and + CANT_HAVE_ASSIGNMENT are nonzero if, for whatever reason, the class + cannot have a default constructor, copy constructor taking a const + reference argument, or an assignment operator, respectively. If a + virtual destructor is created, its DECL is returned; otherwise the + return value is NULL_TREE. */ + +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; + + /* Destructor. */ + 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 we couldn't make it work, then pretend we didn't need it. */ + 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); + + /* Default constructor. */ + if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor + && ! IS_SIGNATURE (t)) + { + default_fn = cons_up_default_function (t, name, 2); + TREE_CHAIN (default_fn) = implicit_fns; + implicit_fns = default_fn; + } + + /* Copy constructor. */ + if (! TYPE_HAS_INIT_REF (t) && ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t)) + { + /* ARM 12.18: You get either X(X&) or X(const X&), but + not both. --Chip */ + default_fn = cons_up_default_function (t, name, + 3 + cant_have_const_cctor); + TREE_CHAIN (default_fn) = implicit_fns; + implicit_fns = default_fn; + } + + /* Assignment operator. */ + 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; + } + + /* Now, hook all of the new functions on to TYPE_METHODS, + and add them to the CLASSTYPE_METHOD_VEC. */ + 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; +} + +/* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration + (or C++ class declaration). + + For C++, we must handle the building of derived classes. + Also, C++ allows static class members. The way that this is + handled is to keep the field name where it is (as the DECL_NAME + of the field), and place the overloaded decl in the DECL_FIELD_BITPOS + of the field. layout_record and layout_union will know about this. + + More C++ hair: inline functions have text in their + DECL_PENDING_INLINE_INFO nodes which must somehow be parsed into + meaningful tree structure. After the struct has been laid out, set + things up so that this can happen. + + And still more: virtual functions. In the case of single inheritance, + when a new virtual function is seen which redefines a virtual function + from the base class, the new virtual function is placed into + the virtual function table at exactly the same address that + it had in the base class. When this is extended to multiple + inheritance, the same thing happens, except that multiple virtual + function tables must be maintained. The first virtual function + table is treated in exactly the same way as in the case of single + inheritance. Additional virtual function tables have different + DELTAs, which tell how to adjust `this' to point to the right thing. + + ATTRIBUTES is the set of decl attributes to be applied, if any. */ + +tree +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; + + /* The index of the first base class which has virtual + functions. Only applied to non-virtual baseclasses. */ + 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; + + 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 (0); + return t; + } + + GNU_xref_decl (current_function_decl, t); + + /* If this type was previously laid out as a forward reference, + make sure we lay it out again. */ + + TYPE_SIZE (t) = NULL_TREE; + CLASSTYPE_GOT_SEMICOLON (t) = 0; + +#if 0 + /* This is in general too late to do this. I moved the main case up to + left_curly, what else needs to move? */ + 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 (); + + /* Install struct as DECL_FIELD_CONTEXT of each field decl. + Also process specified field sizes. + Set DECL_FIELD_SIZE to the specified size, or 0 if none specified. + The specified size is found in the DECL_INITIAL. + Store 0 there, except for ": 0" fields (so we can find them + and delete them, below). */ + + 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); + /* Remember where we got our vfield from. */ + CLASSTYPE_VFIELD_PARENT (t) = first_vfn_base_index; + has_virtual = base_info.has_virtual; + max_has_virtual = base_info.max_has_virtual; + CLASSTYPE_N_SUPERCLASSES (t) += base_info.n_ancestors; + vfield = base_info.vfield; + vfields = base_info.vfields; + 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 + /* Both of these should be done before now. */ + 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 + + /* The three of these are approximations which may later be + modified. Needed at this point to make add_virtual_function + and modify_vtable_entries work. */ + CLASSTYPE_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 this was an evil function, don't keep it in class. */ + if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x))) + continue; + + /* Do both of these, even though they're in the same union; + if the insn `r' member and the size `i' member are + different sizes, as on the alpha, the larger of the two + will end up with garbage in it. */ + 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); + + /* The name of the field is the original field name + Save this in auxiliary field for later overloading. */ + 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 + /* XXX Why did I comment this out? (jason) */ + 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))) + /* A zero-width bitfield doesn't do the trick. */; + else + empty = 0; + } + + if (TREE_CODE (x) == USING_DECL) + { + /* Save access declarations for later. */ + 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; + + /* If we've gotten this far, it's a data member, possibly static, + or an enumerator. */ + + DECL_FIELD_CONTEXT (x) = t; + + /* ``A local class cannot have static data members.'' ARM 9.4 */ + if (current_function_decl && TREE_STATIC (x)) + cp_error_at ("field `%D' in local class cannot be static", x); + + /* Perform error checking that did not get done in + grokdeclarator. */ + 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; + + /* When this goes into scope, it will be a non-local reference. */ + DECL_NONLOCAL (x) = 1; + + if (TREE_CODE (x) == CONST_DECL) + continue; + + if (TREE_CODE (x) == VAR_DECL) + { + if (TREE_CODE (t) == UNION_TYPE) + /* Unions cannot have static members. */ + cp_error_at ("field `%D' declared static in union", x); + + continue; + } + + /* Now it can only be a FIELD_DECL. */ + + if (TREE_PRIVATE (x) || TREE_PROTECTED (x)) + aggregate = 0; + + /* If this is of reference type, check if it needs an init. + Also do a little ANSI jig if necessary. */ + if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE) + { + if (DECL_INITIAL (x) == NULL_TREE) + ref_sans_init = 1; + + /* ARM $12.6.2: [A member initializer list] (or, for an + aggregate, initialization by a brace-enclosed list) is the + only way to initialize nonstatic const and reference + members. */ + 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 any field is const, the structure type is pseudo-const. */ + if (TREE_READONLY (x)) + { + C_TYPE_FIELDS_READONLY (t) = 1; + if (DECL_INITIAL (x) == NULL_TREE) + const_sans_init = 1; + + /* ARM $12.6.2: [A member initializer list] (or, for an + aggregate, initialization by a brace-enclosed list) is the + only way to initialize nonstatic const and reference + members. */ + 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 + { + /* A field that is pseudo-const makes the structure + likewise. */ + tree t1 = TREE_TYPE (x); + while (TREE_CODE (t1) == ARRAY_TYPE) + t1 = TREE_TYPE (t1); + if (IS_AGGR_TYPE (t1)) + { + if (C_TYPE_FIELDS_READONLY (t1)) + C_TYPE_FIELDS_READONLY (t) = 1; + if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (t1)) + const_sans_init = 1; + } + } + + /* We set DECL_C_BIT_FIELD in grokbitfield. + If the type and width are valid, we'll also set DECL_BIT_FIELD. */ + if (DECL_C_BIT_FIELD (x)) + { + /* Invalid bit-field size done by grokfield. */ + /* Detect invalid bit-field type. */ + 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; + } + + /* Detect and ignore out of range field width. */ + if (DECL_INITIAL (x)) + { + tree w = DECL_INITIAL (x); + register int width = 0; + + /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs. */ + STRIP_NOPS (w); + + /* detect invalid field size. */ + 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)) + { + /* The backend will dump if you try to use something + too big; avoid that. */ + 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 + /* Non-bit-fields are aligned for their type. */ + 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)) + { + /* Never let anything with uninheritable virtuals + make it through without complaint. */ + if (CLASSTYPE_ABSTRACT_VIRTUALS (type)) + abstract_virtuals_error (x, type); + + /* Don't let signatures make it through either. */ + if (IS_SIGNATURE (type)) + signature_error (x, type); + + if (code == UNION_TYPE) + { + 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 + /* This is wrong for aggregates. */ + 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) + { + /* `build_class_init_list' does not recognize + non-FIELD_DECLs. */ + if (code == UNION_TYPE && any_default_members != 0) + cp_error_at ("multiple fields in union `%T' initialized"); + any_default_members = 1; + } + } + } + + /* If this type has any constant members which did not come + with their own initialization, mark that fact here. It is + not an error here, since such types can be saved either by their + constructors, or by fortuitous initialization. */ + CLASSTYPE_READONLY_FIELDS_NEED_INIT (t) = const_sans_init; + CLASSTYPE_REF_FIELDS_NEED_INIT (t) = ref_sans_init; + CLASSTYPE_ABSTRACT_VIRTUALS (t) = abstract_virtuals; + CLASSTYPE_HAS_MUTABLE (t) = has_mutable; + + /* Effective C++ rule 11. */ + 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); + } + + /* Do some bookkeeping that will guide the generation of implicitly + declared member functions. */ + 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); + TYPE_HAS_REAL_ASSIGNMENT (t) |= TYPE_HAS_ASSIGNMENT (t); + 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); + + /* Synthesize any needed methods. Note that methods will be synthesized + for anonymous unions; grok_x_components undoes that. */ + 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; + + /* Just in case these got accidentally + filled in by syntax errors. */ + 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) + { + /* We build this decl with vtbl_ptr_type_node, which is a + `vtable_entry_type*'. It might seem more precise to use + `vtable_entry_type (*)[N]' where N is the number of firtual + functions. However, that would require the vtable pointer in + base classes to have a different type than the vtable pointer + in derived classes. We could make that happen, but that + still wouldn't solve all the problems. In particular, the + type-based alias analysis code would decide that assignments + to the base class vtable pointer can't alias assignments to + the derived class vtable pointer, since they have different + types. Thus, in an derived class destructor, where the base + class constructor was inlined, we could generate bad code for + setting up the vtable pointer. + + Therefore, we use one type for all vtable pointers. We still + use a type-correct type; it's just doesn't indicate the array + bounds. That's better than using `void*' or some such; it's + cleaner, and it let's the alias analysis code know that these + stores cannot alias stores to void*! */ + vfield = build_lang_field_decl (FIELD_DECL, get_vfield_name (t), + vtbl_ptr_type_node); + /* If you change any of the below, take a look at all the + other VFIELD_BASEs and VTABLE_BASEs in the code, and change + them too. */ + 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 + /* This is more efficient, but breaks binary compatibility, turn + it on sometime when we don't care. If we turn it on, we also + have to enable the code in dfs_init_vbase_pointers. */ + /* vfield is always first entry in structure. */ + 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, CLASSTYPE_AS_LIST (t)); + } + + /* Now DECL_INITIAL is null on all members except for zero-width bit-fields. + + C++: maybe we will support default field initialization some day... */ + + /* Delete all duplicate fields from the fields */ + delete_duplicate_fields (fields); + + /* Catch function/field name conflict. We don't need to do this for a + signature, since it can only contain the fields constructed in + append_signature_fields. */ + if (! IS_SIGNATURE (t)) + { + int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0; + for (x = fields; x; x = TREE_CHAIN (x)) + { + tree name = DECL_NAME (x); + int i; + + if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)) + continue; + + 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_at ("data member `%#D' conflicts with", x); + cp_error_at ("function member `%#D'", + OVL_CURRENT (TREE_VEC_ELT (method_vec, i))); + break; + } + } + } + + /* Now we have the nearly final fieldlist for the data fields. Record it, + then lay out the structure or union (including the fields). */ + + TYPE_FIELDS (t) = fields; + + if (n_baseclasses) + { + last_x = build_base_fields (t); + + /* If all our bases are empty, we can be empty too. */ + for (x = last_x; empty && x; x = TREE_CHAIN (x)) + if (DECL_SIZE (x) != integer_zero_node) + empty = 0; + } + if (empty) + { + /* C++: do not let empty structures exist. */ + tree decl = build_lang_field_decl + (FIELD_DECL, NULL_TREE, char_type_node); + TREE_CHAIN (decl) = fields; + TYPE_FIELDS (t) = decl; + } + if (n_baseclasses) + TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t)); + + layout_type (t); + + /* Remember the size and alignment of the class before adding + the virtual bases. */ + 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); + + /* Set the TYPE_DECL for this type to contain the right + value for DECL_OFFSET, so that we can use it as part + of a COMPONENT_REF for multiple inheritance. */ + + layout_decl (TYPE_MAIN_DECL (t), 0); + + /* Now fix up any virtual base class types that we left lying + around. We must get these done before we try to lay out the + virtual function table. */ + pending_hard_virtuals = nreverse (pending_hard_virtuals); + + if (n_baseclasses) + /* layout_basetypes will remove the base subobject fields. */ + max_has_virtual = layout_basetypes (t, max_has_virtual); + else if (empty) + TYPE_FIELDS (t) = fields; + + my_friendly_assert (TYPE_FIELDS (t) == fields, 981117); + + /* Delete all zero-width bit-fields from the front of the fieldlist */ + while (fields && DECL_C_BIT_FIELD (fields) + && DECL_INITIAL (fields)) + fields = TREE_CHAIN (fields); + /* Delete all such fields from the rest of the fields. */ + for (x = fields; x;) + { + if (TREE_CHAIN (x) && 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); + CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases); + + { + /* Now fixup overrides of all functions in vtables from all + direct or indirect virtual base classes. */ + 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); + } + } + } + } + + /* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we + might need to know it for setting up the offsets in the vtable + (or in thunks) below. */ + 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; + /* Now fixup any virtual function entries from virtual bases + that have different deltas. This has to come after we do the + pending hard virtuals, as we might have a function that comes + from multiple virtual base instances that is only overridden + by a hard virtual above. */ + vbases = CLASSTYPE_VBASECLASSES (t); + while (vbases) + { + /* We might be able to shorten the amount of work we do by + only doing this for vtables that come from virtual bases + that have differing offsets, but don't want to miss any + entries. */ + fixup_vtable_deltas (vbases, 1, t); + vbases = TREE_CHAIN (vbases); + } + } + + /* Under our model of GC, every C++ class gets its own virtual + function table, at least virtually. */ + if (pending_virtuals) + { + pending_virtuals = nreverse (pending_virtuals); + /* We must enter these virtuals into the table. */ + if (first_vfn_base_index < 0) + { + /* The second slot is for the tdesc pointer when thunks are used. */ + if (flag_vtable_thunks) + pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals); + + /* The first slot is for the rtti offset. */ + 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 + { + /* Here we know enough to change the type of our virtual + function table, but we will wait until later this function. */ + + if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t))) + build_vtable (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index), t); + } + + /* If this type has basetypes with constructors, then those + constructors might clobber the virtual function table. But + they don't if the derived class shares the exact vtable of the base + class. */ + + CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1; + } + else if (first_vfn_base_index >= 0) + { + tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index); + /* This class contributes nothing new to the virtual function + table. However, it may have declared functions which + went into the virtual function table "inherited" from the + base class. If so, we grab a copy of those updated functions, + and pretend they are ours. */ + + /* See if we should steal the virtual info from base class. */ + 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; + } + } + + /* Now lay out the virtual function table. */ + if (has_virtual) + { + /* Use size_int so values are memoized in common cases. */ + 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; + + /* We may have to grow the vtable. */ + 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); + /* At one time the vtable info was grabbed 2 words at a time. This + fails on sparc unless you have 8-byte alignment. (tiemann) */ + 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); + + /* Complete the rtl for any static member objects of the type we're + working on. */ + 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) + { + /* Mark the fact that constructor for T + could affect anybody inheriting from T + who wants to initialize vtables for VFIELDS's type. */ + if (VF_DERIVED_VALUE (vfields)) + TREE_ADDRESSABLE (vfields) = 1; + vfields = TREE_CHAIN (vfields); + } + if (any_default_members != 0) + build_class_init_list (t); + } + else if (TYPE_NEEDS_CONSTRUCTING (t)) + build_class_init_list (t); + + /* Write out inline function definitions. */ + do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t)); + CLASSTYPE_INLINE_FRIENDS (t) = 0; + + if (CLASSTYPE_VSIZE (t) != 0) + { +#if 0 + /* This is now done above. */ + 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 + + /* In addition to this one, all the other vfields should be listed. */ + /* Before that can be done, we have to have FIELD_DECLs for them, and + a place to find them. */ + TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (TYPE_BINFO_VTABLE (t)), vfield); + + 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); + } + + /* Make the rtl for any new vtables we have created, and unmark + the base types we marked. */ + 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 + /* This has to be done after we have sorted out what to do with + the enclosing type. */ + if (write_symbols != DWARF_DEBUG) + { + /* Be smarter about nested classes here. If a type is nested, + only output it if we would output the enclosing type. */ + 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 the type has methods, we want to think about cutting down + the amount of symbol table stuff we output. The value stored in + the TYPE_DECL's DECL_IGNORED_P slot is a first approximation. + For example, if a member function is seen and we decide to + write out that member function, then we can change the value + of the DECL_IGNORED_P slot, and the type will be output when + that member function's debug info is written out. + + We can't do this with DWARF, which does not support name + references between translation units. */ + if (CLASSTYPE_METHOD_VEC (t)) + { + /* Don't output full info about any type + which does not have its implementation defined here. */ + if (CLASSTYPE_INTERFACE_ONLY (t)) + TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1; +#if 0 + /* XXX do something about this. */ + else if (CLASSTYPE_INTERFACE_UNKNOWN (t)) + /* Only a first approximation! */ + 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; + } + + /* Finish debugging output for this type. */ + rest_of_type_compilation (t, toplevel_bindings_p ()); + + return t; +} + +/* In [basic.scope.class] we have: + + A name N used in a class S shall refer to the same declaration in + its context and when re-evaluated in the completed scope of S. + + This function checks this condition for X, which is a member of + T. */ + +static void +check_member_decl_is_same_in_complete_scope (t, x) + tree t; + tree x; +{ + /* A name N used in a class S shall refer to the same declaration in + its context and when re-evaluated in the completed scope of S. + + Enums, types and static vars have already been checked. */ + if (TREE_CODE (x) != USING_DECL + && TREE_CODE (x) != TYPE_DECL && !DECL_CLASS_TEMPLATE_P (x) + && TREE_CODE (x) != CONST_DECL && TREE_CODE (x) != VAR_DECL) + { + tree name = DECL_NAME (x); + tree icv; + + /* Don't get confused by access decls. */ + if (name && TREE_CODE (name) == IDENTIFIER_NODE) + icv = IDENTIFIER_CLASS_VALUE (name); + else + icv = NULL_TREE; + + /* This should match pushdecl_class_level. */ + if (icv && icv != x + && flag_optional_diags + /* Don't complain about constructors. */ + && name != constructor_name (current_class_type) + /* Or inherited names. */ + && id_in_current_class (name) + /* Or shadowed tags. */ + && !(TREE_CODE (icv) == TYPE_DECL && DECL_CONTEXT (icv) == t)) + { + cp_pedwarn_at ("declaration of identifier `%D' as `%+#D'", + name, x); + cp_pedwarn_at ("conflicts with other use in class as `%#D'", + icv); + } + } +} + +/* When T was built up, the member declarations were added in reverse + order. Rearrange them to declaration order. */ + +void +unreverse_member_declarations (t) + tree t; +{ + tree next; + tree prev; + tree x; + + /* The TYPE_FIELDS, TYPE_METHODS, and CLASSTYPE_TAGS are all in + reverse order. Put them in declaration order now. */ + TYPE_METHODS (t) = nreverse (TYPE_METHODS (t)); + CLASSTYPE_TAGS (t) = nreverse (CLASSTYPE_TAGS (t)); + + /* Actually, for the TYPE_FIELDS, only the non TYPE_DECLs are in + reverse order, so we can't just use nreverse. */ + 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); + tree x; + + if (TREE_CODE (name) == TYPE_DECL) + { + extern int lineno; + + DECL_SOURCE_FILE (name) = input_filename; + /* For TYPE_DECL that are not typedefs (those marked with a line + number of zero, we don't want to mark them as real typedefs. + If this fails one needs to make sure real typedefs have a + previous line number, even if it is wrong, that way the below + will fill in the right line number. (mrs) */ + if (DECL_SOURCE_LINE (name)) + DECL_SOURCE_LINE (name) = lineno; + name = DECL_NAME (name); + } + + /* Append the fields we need for constructing signature tables. */ + if (IS_SIGNATURE (t)) + append_signature_fields (t); + + /* Now that we've got all the field declarations, reverse everything + as necessary. */ + unreverse_member_declarations (t); + + if (flag_optional_diags) + { + for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) + check_member_decl_is_same_in_complete_scope (t, x); + for (x = TYPE_FIELDS (t); x; x = TREE_CHAIN (x)) + check_member_decl_is_same_in_complete_scope (t, x); + } + + /* Mark all the tags in the class as class-local. */ + for (x = CLASSTYPE_TAGS (t); x; x = TREE_CHAIN (x)) + TREE_NONLOCAL_FLAG (TREE_VALUE (x)) = 0; + + cplus_decl_attributes (t, attributes, NULL_TREE); + + if (processing_template_decl) + { + tree d = getdecls (); + for (; d; d = TREE_CHAIN (d)) + { + /* If this is the decl for the class or one of the template + parms, we've seen all the injected decls. */ + 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; + /* Don't inject cache decls. */ + 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 + t = finish_struct_1 (t, warn_anon); + + TYPE_BEING_DEFINED (t) = 0; + if (current_class_type) + popclass (0); + else + error ("trying to finish struct, but kicked out due to previous parse errors."); + + return t; +} + +/* Return the dynamic type of INSTANCE, if known. + Used to determine whether the virtual function table is needed + or not. + + *NONNULL is set iff INSTANCE can be known to be nonnull, regardless + of our knowledge of its type. */ + +tree +fixed_type_or_null (instance, nonnull) + tree instance; + int *nonnull; +{ + switch (TREE_CODE (instance)) + { + case INDIRECT_REF: + /* Check that we are not going through a cast of some sort. */ + if (TREE_TYPE (instance) + == TREE_TYPE (TREE_TYPE (TREE_OPERAND (instance, 0)))) + instance = TREE_OPERAND (instance, 0); + /* fall through... */ + case CALL_EXPR: + /* This is a call to a constructor, hence it's never zero. */ + if (TREE_HAS_CONSTRUCTOR (instance)) + { + if (nonnull) + *nonnull = 1; + return TREE_TYPE (instance); + } + return NULL_TREE; + + case SAVE_EXPR: + /* This is a call to a constructor, hence it's never zero. */ + 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) + /* Propagate nonnull. */ + 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)); + } + /* fall through... */ + 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) + { + /* Normally, 'this' must be non-null. */ + if (flag_this_is_variable == 0) + *nonnull = 1; + + /* <0 means we're in a constructor and we know our type. */ + if (flag_this_is_variable < 0) + return TREE_TYPE (TREE_TYPE (instance)); + } + else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE) + /* Reference variables should be references to objects. */ + *nonnull = 1; + } + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* Return non-zero if the dynamic type of INSTANCE is known, and equivalent + to the static type. We also handle the case where INSTANCE is really + a pointer. + + Used to determine whether the virtual function table is needed + or not. + + *NONNULL is set iff INSTANCE can be known to be nonnull, regardless + of our knowledge of its type. */ + +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); + + /* Keep these values lying around. */ + 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); +} + +/* Set current scope to NAME. CODE tells us if this is a + STRUCT, UNION, or ENUM environment. + + NAME may end up being NULL_TREE if this is an anonymous or + late-bound struct (as in "struct { ... } foo;") */ + +/* Set global variables CURRENT_CLASS_NAME and CURRENT_CLASS_TYPE to + appropriate values, found by looking up the type definition of + NAME (as a CODE). + + If MODIFY is 1, we set IDENTIFIER_CLASS_VALUE's of names + which can be seen locally to the class. They are shadowed by + any subsequent local declaration (including parameter names). + + If MODIFY is 2, we set IDENTIFIER_CLASS_VALUE's of names + which have static meaning (i.e., static members, static + member functions, enum declarations, etc). + + If MODIFY is 3, we set IDENTIFIER_CLASS_VALUE of names + which can be seen locally to the class (as in 1), but + know that we are doing this for declaration purposes + (i.e. friend foo::bar (int)). + + So that we may avoid calls to lookup_name, we cache the _TYPE + nodes of local TYPE_DECLs in the TREE_TYPE field of the name. + + For multiple inheritance, we perform a two-pass depth-first search + of the type lattice. The first pass performs a pre-order search, + marking types after the type has had its fields installed in + the appropriate IDENTIFIER_CLASS_VALUE slot. The second pass merely + unmarks the marked types. If a field or member function name + appears in an ambiguous way, the IDENTIFIER_CLASS_VALUE of + that name becomes `error_mark_node'. */ + +void +pushclass (type, modify) + tree type; + int modify; +{ + type = TYPE_MAIN_VARIANT (type); + + /* Make sure there is enough room for the new entry on the stack. */ + 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)); + } + + /* Insert a new entry on the class stack. */ + 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_depth++; + + /* Now set up the new type. */ + current_class_name = TYPE_NAME (type); + if (TREE_CODE (current_class_name) == TYPE_DECL) + current_class_name = DECL_NAME (current_class_name); + current_class_type = type; + + /* By default, things in classes are private, while things in + structures or unions are public. */ + 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) + { + /* Forcibly remove any old class remnants. */ + popclass (-1); + previous_class_type = NULL_TREE; + + /* Now, free the obstack on which we cached all the values. */ + obstack_free (&class_cache_obstack, class_cache_firstobj); + class_cache_firstobj + = (char*) obstack_finish (&class_cache_obstack); + } + + pushlevel_class (); + +#if 0 + if (CLASSTYPE_TEMPLATE_INFO (type)) + overload_template_name (type); +#endif + + if (modify) + { + tree tags; + tree this_fndecl = current_function_decl; + + if (current_function_decl + && DECL_CONTEXT (current_function_decl) + && TREE_CODE (DECL_CONTEXT (current_function_decl)) == FUNCTION_DECL) + current_function_decl = DECL_CONTEXT (current_function_decl); + else + current_function_decl = NULL_TREE; + + if (type != previous_class_type || current_class_depth > 1) + { +#ifdef MI_MATRIX + build_mi_matrix (type); + push_class_decls (type); + free_mi_matrix (); +#else + push_class_decls (type); +#endif + } + else + { + tree item; + + /* We are re-entering the same class we just left, so we + don't have to search the whole inheritance matrix to find + all the decls to bind again. Instead, we install the + cached class_shadowed list, and walk through it binding + names and setting up IDENTIFIER_TYPE_VALUEs. */ + 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); + } + + for (tags = CLASSTYPE_TAGS (type); tags; tags = TREE_CHAIN (tags)) + { + tree tag_type = TREE_VALUE (tags); + + TREE_NONLOCAL_FLAG (tag_type) = 1; + if (! TREE_PURPOSE (tags)) + continue; + if (! (IS_AGGR_TYPE_CODE (TREE_CODE (tag_type)) + && CLASSTYPE_IS_TEMPLATE (tag_type))) + pushtag (TREE_PURPOSE (tags), tag_type, 0); + } + + current_function_decl = this_fndecl; + } +} + +/* Get out of the current class scope. If we were in a class scope + previously, that is the one popped to. The flag MODIFY tells whether + the current scope declarations needs to be modified as a result of + popping to the previous scope. 0 is used for class definitions. */ + +void +popclass (modify) + int modify; +{ + if (modify < 0) + { + /* Back this old class out completely. */ + tree tags = CLASSTYPE_TAGS (previous_class_type); + tree t; + + /* This code can be seen as a cache miss. When we've cached a + class' scope's bindings and we can't use them, we need to reset + them. This is it! */ + for (t = previous_class_values; t; t = TREE_CHAIN (t)) + IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE; + while (tags) + { + TREE_NONLOCAL_FLAG (TREE_VALUE (tags)) = 0; + tags = TREE_CHAIN (tags); + } + + return; + } + + if (modify) + { + /* Just remove from this class what didn't make + it into IDENTIFIER_CLASS_VALUE. */ + tree tags = CLASSTYPE_TAGS (current_class_type); + + while (tags) + { + TREE_NONLOCAL_FLAG (TREE_VALUE (tags)) = 0; + tags = TREE_CHAIN (tags); + } + } + + /* Force clearing of IDENTIFIER_CLASS_VALUEs after a class definition, + since not all class decls make it there currently. */ + poplevel_class (! modify); + + /* Since poplevel_class does the popping of class decls nowadays, + this really only frees the obstack used for these decls. + That's why it had to be moved down here. */ + if (modify) + 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; +} + +/* Returns 1 if current_class_type is either T or a nested type of T. */ + +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; +} + +/* When entering a class scope, all enclosing class scopes' names with + static meaning (static variables, static functions, types and enumerators) + have to be visible. This recursive function calls pushclass for all + enclosing class contexts until global or a local scope is reached. + TYPE is the enclosed class and MODIFY is equivalent with the pushclass + formal of the same name. */ + +void +push_nested_class (type, modify) + tree type; + int modify; +{ + tree context; + + my_friendly_assert (!type || TREE_CODE (type) != NAMESPACE_DECL, 980711); + + if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type) + || TREE_CODE (type) == TEMPLATE_TYPE_PARM + || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM) + return; + + context = DECL_CONTEXT (TYPE_MAIN_DECL (type)); + + if (context && TREE_CODE (context) == RECORD_TYPE) + push_nested_class (context, 2); + pushclass (type, modify); +} + +/* Undoes a push_nested_class call. MODIFY is passed on to popclass. */ + +void +pop_nested_class (modify) + int modify; +{ + tree context = DECL_CONTEXT (TYPE_MAIN_DECL (current_class_type)); + + popclass (modify); + if (context && TREE_CODE (context) == RECORD_TYPE) + pop_nested_class (modify); +} + +/* Set global variables CURRENT_LANG_NAME to appropriate value + so that behavior of name-mangling machinery is correct. */ + +void +push_lang_context (name) + tree name; +{ + *current_lang_stack++ = current_lang_name; + if (current_lang_stack >= current_lang_base + current_lang_stacksize) + { + current_lang_base + = (tree *)xrealloc (current_lang_base, + sizeof (tree) * (current_lang_stacksize + 10)); + current_lang_stack = current_lang_base + current_lang_stacksize; + current_lang_stacksize += 10; + } + + if (name == lang_name_cplusplus || name == lang_name_java) + { + strict_prototype = strict_prototypes_lang_cplusplus; + current_lang_name = name; + } + else if (name == lang_name_c) + { + strict_prototype = strict_prototypes_lang_c; + current_lang_name = name; + } + else + error ("language string `\"%s\"' not recognized", IDENTIFIER_POINTER (name)); +} + +/* Get out of the current language scope. */ + +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; + else if (current_lang_name == lang_name_c) + strict_prototype = strict_prototypes_lang_c; +} + +/* Type instantiation routines. */ + +/* Given an OVERLOAD and a TARGET_TYPE, return the function that + matches the TARGET_TYPE. If there is no satisfactory match, return + error_mark_node, and issue an error message if COMPLAIN is + non-zero. If TEMPLATE_ONLY, the name of the overloaded function + was a template-id, and EXPLICIT_TARGS are the explicitly provided + template arguments. */ + +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; +{ + /* Here's what the standard says: + + [over.over] + + If the name is a function template, template argument deduction + is done, and if the argument deduction succeeds, the deduced + arguments are used to generate a single template function, which + is added to the set of overloaded functions considered. + + Non-member functions and static member functions match targets of + type "pointer-to-function" or "reference-to-function." Nonstatic + member functions match targets of type "pointer-to-member + function;" the function type of the pointer to member is used to + select the member function from the set of overloaded member + functions. If a nonstatic member function is selected, the + reference to the overloaded function name is required to have the + form of a pointer to member as described in 5.3.1. + + If more than one function is selected, any template functions in + the set are eliminated if the set also contains a non-template + function, and any given template function is eliminated if the + set contains a second template function that is more specialized + than the first according to the partial ordering rules 14.5.5.2. + After such eliminations, if any, there shall remain exactly one + selected function. */ + + int is_ptrmem = 0; + int is_reference = 0; + /* We store the matches in a TREE_LIST rooted here. The functions + are the TREE_PURPOSE, not the TREE_VALUE, in this list, for easy + interoperability with most_specialized_instantiation. */ + tree matches = NULL_TREE; + tree fn; + + /* By the time we get here, we should be seeing only real + pointer-to-member types, not the internal POINTER_TYPE to + METHOD_TYPE representation. */ + my_friendly_assert (!(TREE_CODE (target_type) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (target_type)) + == METHOD_TYPE)), 0); + + /* Check that the TARGET_TYPE is reasonable. */ + if (TYPE_PTRFN_P (target_type)) + /* This is OK. */ + ; + else if (TYPE_PTRMEMFUNC_P (target_type)) + /* This is OK, too. */ + is_ptrmem = 1; + else if (TREE_CODE (target_type) == FUNCTION_TYPE) + { + /* This is OK, too. This comes from a conversion to reference + 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 we can find a non-template function that matches, we can just + use it. There's no point in generating template instantiations + if we're just going to throw them out anyhow. But, of course, we + can only do this when we don't *need* a template function. */ + 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) + /* We're not looking for templates just yet. */ + continue; + + if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) + != is_ptrmem) + /* We're looking for a non-static member, and this isn't + one, or vice versa. */ + continue; + + /* See if there's a match. */ + 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); + } + } + + /* Now, if we've already got a match (or matches), there's no need + to proceed to the template functions. But, if we don't have a + match we need to look at them, too. */ + 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)); + target_arg_types = TREE_CHAIN (TYPE_ARG_TYPES (target_fn_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 fn_arg_types; + tree instantiation; + tree instantiation_type; + tree targs; + + if (TREE_CODE (fn) != TEMPLATE_DECL) + /* We're only looking for templates. */ + continue; + + if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) + != is_ptrmem) + /* We're looking for a non-static member, and this isn't + one, or vice versa. */ + continue; + + /* We don't use the `this' argument to do argument deduction + since that would prevent us from converting a base class + pointer-to-member to a derived class pointer-to-member. */ + fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + if (is_ptrmem) + fn_arg_types = TREE_CHAIN (fn_arg_types); + + /* Try to do argument deduction. */ + targs = make_scratch_vec (DECL_NTPARMS (fn)); + if (type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), + targs, + fn_arg_types, + target_arg_types, + explicit_targs, + DEDUCE_EXACT, + /*allow_incomplete=*/1) != 0) + /* Argument deduction failed. */ + continue; + + /* Instantiate the template. */ + instantiation = instantiate_template (fn, targs); + if (instantiation == error_mark_node) + /* Instantiation failed. */ + continue; + + /* See if there's a match. */ + 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); + } + + /* Now, remove all but the most specialized of the 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); + } + } + + /* Now we should have exactly one function in MATCHES. */ + if (matches == NULL_TREE) + { + /* There were *no* matches. */ + if (complain) + { + cp_error ("no matches converting function `%D' to type `%#T'", + DECL_NAME (OVL_FUNCTION (overload)), + target_type); + + /* print_candidates expects a chain with the functions in + TREE_VALUE slots, so we cons one up here (we're losing anyway, + so why be clever?). */ + 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)) + { + /* There were too many matches. */ + + if (complain) + { + tree match; + + cp_error ("converting overloaded function `%D' to type `%#T' is ambiguous", + DECL_NAME (OVL_FUNCTION (overload)), + target_type); + + /* Since print_candidates expects the functions in the + TREE_VALUE slot, we flip them here. */ + for (match = matches; match; match = TREE_CHAIN (match)) + TREE_VALUE (match) = TREE_PURPOSE (match); + + print_candidates (matches); + } + + return error_mark_node; + } + + /* Good, exactly one match. Now, convert it to the correct type. */ + 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 + { + /* The target must be a REFERENCE_TYPE. Above, build_unary_op + will mark the function as addressed, but here we must do it + explicitly. */ + mark_addressable (fn); + + return fn; + } +} + +/* This function will instantiate the type of the expression given in + RHS to match the type of LHSTYPE. If errors exist, then return + error_mark_node. We only complain is COMPLAIN is set. If we are + not complaining, never modify rhs, as overload resolution wants to + try many possible instantiations, in hopes that at least one will + work. + + For non-recursive calls, LHSTYPE should be a function, pointer to + function, or a pointer to member function. */ + +tree +instantiate_type (lhstype, rhs, complain) + tree lhstype, rhs; + int complain; +{ + 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 (same_type_p (lhstype, TREE_TYPE (rhs))) + return rhs; + if (complain) + cp_error ("argument of type `%T' does not match `%T'", + TREE_TYPE (rhs), lhstype); + return error_mark_node; + } + + /* We don't overwrite rhs if it is an overloaded function. + Copying it would destroy the tree link. */ + if (TREE_CODE (rhs) != OVERLOAD) + rhs = copy_node (rhs); + + /* This should really only be used when attempting to distinguish + what sort of a pointer to function we have. For now, any + arithmetic operation which is not supported on pointers + is rejected as an error. */ + + switch (TREE_CODE (rhs)) + { + case TYPE_EXPR: + case CONVERT_EXPR: + case SAVE_EXPR: + case CONSTRUCTOR: + case BUFFER_REF: + 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), complain); + 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, complain); + + case COMPONENT_REF: + { + tree field = TREE_OPERAND (rhs, 1); + tree r; + + my_friendly_assert (TREE_CODE (field) == TREE_LIST, 0); + + r = instantiate_type (lhstype, field, complain); + + if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype)) + { + if (complain) + { + tree t = TYPE_PTRMEMFUNC_OBJECT_TYPE (lhstype); + tree fn = TREE_VALUE (field); + if (TREE_CODE (fn) == OVERLOAD) + fn = OVL_FUNCTION (fn); + if (TREE_CODE (fn) == FUNCTION_DECL) + { + cp_error ("object-dependent reference `%E' can only be used in a call", + DECL_NAME (fn)); + cp_error (" to form a pointer to member function, say `&%T::%E'", + t, DECL_NAME (fn)); + } + else + cp_error ("object-dependent reference can only be used in a call"); + } + return error_mark_node; + } + + return r; + } + + case OFFSET_REF: + /* This can happen if we are forming a pointer-to-member for a + member template. */ + rhs = TREE_OPERAND (rhs, 1); + my_friendly_assert (TREE_CODE (rhs) == TEMPLATE_ID_EXPR, 0); + + /* Fall through. */ + + case TEMPLATE_ID_EXPR: + return + resolve_address_of_overloaded_function (lhstype, + TREE_OPERAND (rhs, 0), + complain, + /*template_only=*/1, + TREE_OPERAND (rhs, 1)); + + case OVERLOAD: + return + resolve_address_of_overloaded_function (lhstype, + rhs, + complain, + /*template_only=*/0, + /*explicit_targs=*/NULL_TREE); + + case TREE_LIST: + { + if (TREE_PURPOSE (rhs) == error_mark_node) + { + /* Make sure we don't drop the non-local flag, as the old code + would rely on it. */ + int nl = TREE_NONLOCAL_FLAG (rhs); + /* We don't need the type of this node. */ + rhs = TREE_VALUE (rhs); + my_friendly_assert (TREE_NONLOCAL_FLAG (rhs) == nl, 980331); + } + + /* Now we should have a baselink. */ + my_friendly_assert (TREE_CODE (TREE_PURPOSE (rhs)) == TREE_VEC, + 980331); + my_friendly_assert (TREE_CHAIN (rhs) == NULL_TREE, 181); + my_friendly_assert (TREE_CODE (TREE_VALUE (rhs)) == FUNCTION_DECL + || TREE_CODE (TREE_VALUE (rhs)) == OVERLOAD, + 182); + + return instantiate_type (lhstype, TREE_VALUE (rhs), complain); + } + + case CALL_EXPR: + /* This is too hard for now. */ + 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), complain); + if (TREE_OPERAND (rhs, 0) == error_mark_node) + return error_mark_node; + TREE_OPERAND (rhs, 1) + = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain); + if (TREE_OPERAND (rhs, 1) == error_mark_node) + return error_mark_node; + + TREE_TYPE (rhs) = lhstype; + return rhs; + + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + case CEIL_MOD_EXPR: + case ROUND_MOD_EXPR: + case FIX_ROUND_EXPR: + case FIX_FLOOR_EXPR: + case FIX_CEIL_EXPR: + case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + case NEGATE_EXPR: + case ABS_EXPR: + case MAX_EXPR: + case MIN_EXPR: + case FFS_EXPR: + + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + if (complain) + error ("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), complain); + if (TREE_OPERAND (rhs, 1) == error_mark_node) + return error_mark_node; + TREE_OPERAND (rhs, 2) + = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), complain); + if (TREE_OPERAND (rhs, 2) == error_mark_node) + return error_mark_node; + + TREE_TYPE (rhs) = lhstype; + return rhs; + + case MODIFY_EXPR: + TREE_OPERAND (rhs, 1) + = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), complain); + if (TREE_OPERAND (rhs, 1) == error_mark_node) + return error_mark_node; + + TREE_TYPE (rhs) = lhstype; + return rhs; + + case ADDR_EXPR: + return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain); + + 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; + } +} + +/* Return the name of the virtual function pointer field + (as an IDENTIFIER_NODE) for the given TYPE. Note that + this may have to look back through base types to find the + ultimate field name. (For single inheritance, these could + all be the same name. Who knows for multiple inheritance). */ + +static tree +get_vfield_name (type) + tree type; +{ + 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 +} + +/* Push an obstack which is sufficiently long-lived to hold such class + decls that may be cached in the previous_class_values list. The + effect is undone by pop_obstacks. */ + +void +maybe_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; +} + +/* Build a dummy reference to ourselves so Derived::Base (and A::A) works, + according to [class]: + The class-name is also inserted + into the scope of the class itself. For purposes of access checking, + the inserted class name is treated as if it were a public member name. */ + +tree +build_self_reference () +{ + tree name = constructor_name (current_class_type); + tree value = build_lang_decl (TYPE_DECL, name, current_class_type); + DECL_NONLOCAL (value) = 1; + DECL_CONTEXT (value) = current_class_type; + DECL_CLASS_CONTEXT (value) = current_class_type; + DECL_ARTIFICIAL (value) = 1; + + pushdecl_class_level (value); + return value; +} + +/* Returns 1 if TYPE contains only padding bytes. */ + +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); +} + +/* Find the enclosing class of the given NODE. NODE can be a *_DECL or + a *_TYPE node. NODE can also be a local class. */ + +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; +} + +/* Return 1 if TYPE or one of its enclosing classes is derived from BASE. */ + +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; +} |