| /* Functions related to building classes and their related objects. |
| Copyright (C) 1987, 92, 93, 94, 95, 1996 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 "tree.h" |
| #include <stdio.h> |
| #include "cp-tree.h" |
| #include "flags.h" |
| #include "rtl.h" |
| #include "output.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)); |
| |
| /* Way of stacking class types. */ |
| static tree *current_class_base, *current_class_stack; |
| static int current_class_stacksize; |
| int current_class_depth; |
| |
| struct class_level |
| { |
| /* The previous class level. */ |
| struct class_level *level_chain; |
| |
| /* The class instance variable, as a PARM_DECL. */ |
| tree decl; |
| /* The class instance variable, as an object. */ |
| tree object; |
| /* The virtual function table pointer |
| for the class instance variable. */ |
| tree vtable_decl; |
| |
| /* Name of the current class. */ |
| tree name; |
| /* Type of the current class. */ |
| tree type; |
| |
| /* Flags for this class level. */ |
| int this_is_variable; |
| int memoized_lookups; |
| int save_memoized; |
| int unused; |
| }; |
| |
| /* The currect_class_ptr is the pointer to the current class. |
| current_class_ref is the actual current class. */ |
| 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 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. */ |
| static tree get_vfield_name PROTO((tree)); |
| |
| /* 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; |
| 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_private_virtual_node; /* 6 */ |
| |
| /* 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; |
| |
| name = (char *) alloca (TYPE_NAME_LENGTH (type) + sizeof (VBASE_NAME) + 1); |
| sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (type)); |
| return build_component_ref (exp, get_identifier (name), NULL_TREE, 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; |
| } |
| |
| /* Build multi-level access to EXPR using hierarchy path PATH. |
| CODE is PLUS_EXPR if we are going with the grain, |
| and MINUS_EXPR if we are not (in which case, we cannot traverse |
| virtual baseclass links). |
| |
| TYPE is the type we want this path to have on exit. |
| |
| ALIAS_THIS is non-zero if EXPR in an expression involving `this'. */ |
| |
| tree |
| build_vbase_path (code, type, expr, path, alias_this) |
| enum tree_code code; |
| tree type, expr, path; |
| int alias_this; |
| { |
| register int changed = 0; |
| tree last = NULL_TREE, last_virtual = NULL_TREE; |
| int nonnull = 0; |
| 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 (nonnull == 0 && (alias_this && flag_this_is_variable <= 0)) |
| nonnull = 1; |
| |
| #if 0 |
| /* We need 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, or until we can |
| recognize when that is, we cannot do the short cut logic. (mrs) */ |
| fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); |
| #else |
| /* Do this, until we can undo any previous conversions. See net35.C |
| for a testcase. */ |
| fixed_type_p = complete_type_p (expr); |
| #endif |
| |
| if (!fixed_type_p && TREE_SIDE_EFFECTS (expr)) |
| expr = save_expr (expr); |
| nonnull_expr = expr; |
| |
| if (BINFO_INHERITANCE_CHAIN (path)) |
| { |
| tree reverse_path = NULL_TREE; |
| |
| while (path) |
| { |
| tree r = copy_node (path); |
| BINFO_INHERITANCE_CHAIN (r) = reverse_path; |
| reverse_path = r; |
| path = BINFO_INHERITANCE_CHAIN (path); |
| } |
| path = reverse_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 |
| || !flag_assume_nonnull_objects) |
| && 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 (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 |
| |
| /* For multiple inheritance: if `this' can be set by any |
| function, then it could be 0 on entry to any function. |
| Preserve such zeroness here. Otherwise, only in the |
| case of constructors need we worry, and in those cases, |
| it will be zero, or initialized to some valid value to |
| which we may add. */ |
| 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. */ |
| |
| /* Virtual functions to be dealt with after laying out our base |
| classes. We do all overrides after we layout virtual base classes. */ |
| |
| static tree pending_hard_virtuals; |
| |
| /* 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 = tree_cons (NULL_TREE, delta, |
| tree_cons (NULL_TREE, integer_zero_node, |
| build_tree_list (NULL_TREE, pfn))); |
| tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems); |
| |
| /* DELTA is constructed by `size_int', which means it may be an |
| unsigned quantity on some platforms. Therefore, we cannot use |
| `int_fits_type_p', because when DELTA is really negative, |
| `force_fit_type' will make it look like a very large number. */ |
| |
| if ((TREE_INT_CST_LOW (TYPE_MAX_VALUE (delta_type_node)) |
| < TREE_INT_CST_LOW (delta)) |
| || (TREE_INT_CST_LOW (delta) |
| < TREE_INT_CST_LOW (TYPE_MIN_VALUE (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; |
| } |
| } |
| |
| /* 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_indirect_ref (build_vfield_ref (instance, basetype), |
| NULL_PTR); |
| 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_indirect_ref (build_vfield_ref (instance, basetype), |
| NULL_PTR); |
| } |
| assemble_external (vtbl); |
| 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; |
| { |
| return size_binop (PLUS_EXPR, |
| size_binop (FLOOR_DIV_EXPR, |
| DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))), |
| size_int (BITS_PER_UNIT)), |
| 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 (size_zero_node, voff); |
| |
| /* The second slot is for the tdesc pointer when thunks are used. */ |
| TREE_VALUE (TREE_CHAIN (virtuals)) |
| = build_vtable_entry (size_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 = size_binop (MINUS_EXPR, size_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); |
| |
| IDENTIFIER_GLOBAL_VALUE (name) = decl = pushdecl_top_level (decl); |
| /* Initialize the association list for this type, based |
| on our first approximation. */ |
| TYPE_BINFO_VTABLE (type) = decl; |
| TYPE_BINFO_VIRTUALS (type) = virtuals; |
| |
| 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)); |
| |
| /* Why is this conditional? (mrs) */ |
| if (binfo && write_virtuals >= 0) |
| DECL_VIRTUAL_P (decl) = 1; |
| DECL_CONTEXT (decl) = type; |
| |
| binfo = TYPE_BINFO (type); |
| SET_BINFO_NEW_VTABLE_MARKED (binfo); |
| return decl; |
| } |
| |
| /* Given a base type PARENT, and a derived type TYPE, build |
| a name which distinguishes exactly the PARENT member of TYPE's type. |
| |
| FORMAT is a string which controls how sprintf formats the name |
| we have generated. |
| |
| For example, given |
| |
| class A; class B; class C : A, B; |
| |
| it is possible to distinguish "A" from "C's A". And given |
| |
| class L; |
| class A : L; class B : L; class C : A, B; |
| |
| it is possible to distinguish "L" from "A's L", and also from |
| "C's L from A". |
| |
| Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the |
| type, as template have DECL_NAMEs like: X<int>, whereas the |
| DECL_ASSEMBLER_NAME is set to be something the assembler can handle. */ |
| |
| static tree |
| build_type_pathname (format, parent, type) |
| char *format; |
| tree parent, type; |
| { |
| extern struct obstack temporary_obstack; |
| char *first, *base, *name; |
| int i; |
| tree id; |
| |
| parent = TYPE_MAIN_VARIANT (parent); |
| |
| /* Remember where to cut the obstack to. */ |
| first = obstack_base (&temporary_obstack); |
| |
| /* Put on TYPE+PARENT. */ |
| obstack_grow (&temporary_obstack, |
| TYPE_ASSEMBLER_NAME_STRING (type), |
| TYPE_ASSEMBLER_NAME_LENGTH (type)); |
| #ifdef JOINER |
| obstack_1grow (&temporary_obstack, JOINER); |
| #else |
| obstack_1grow (&temporary_obstack, '_'); |
| #endif |
| obstack_grow0 (&temporary_obstack, |
| TYPE_ASSEMBLER_NAME_STRING (parent), |
| TYPE_ASSEMBLER_NAME_LENGTH (parent)); |
| i = obstack_object_size (&temporary_obstack); |
| base = obstack_base (&temporary_obstack); |
| obstack_finish (&temporary_obstack); |
| |
| /* Put on FORMAT+TYPE+PARENT. */ |
| obstack_blank (&temporary_obstack, strlen (format) + i + 1); |
| name = obstack_base (&temporary_obstack); |
| sprintf (name, format, base); |
| id = get_identifier (name); |
| obstack_free (&temporary_obstack, first); |
| |
| return id; |
| } |
| |
| 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. */ |
| |
| static void |
| prepare_fresh_vtable (binfo, for_type) |
| tree binfo, for_type; |
| { |
| tree basetype = BINFO_TYPE (binfo); |
| tree orig_decl = BINFO_VTABLE (binfo); |
| /* This name is too simplistic. We can have multiple basetypes for |
| for_type, and we really want different names. (mrs) */ |
| tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type); |
| tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); |
| tree offset; |
| |
| /* Remember which class this vtable is really for. */ |
| DECL_CONTEXT (new_decl) = for_type; |
| |
| 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), |
| size_binop (MINUS_EXPR, signed_size_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 tree |
| add_virtual_function (pending_virtuals, has_virtual, fndecl, t) |
| tree pending_virtuals; |
| int *has_virtual; |
| tree fndecl; |
| tree t; /* Structure type. */ |
| { |
| /* 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); |
| } |
| return pending_virtuals; |
| } |
| |
| /* Obstack on which to build the vector of class methods. */ |
| struct obstack class_obstack; |
| extern struct obstack *current_obstack; |
| |
| /* Add method METHOD to class TYPE. This is used when a method |
| has been defined which did not initially appear in the class definition, |
| and helps cut down on spurious error messages. |
| |
| FIELDS is the entry in the METHOD_VEC vector entry of the class type where |
| the method should be added. */ |
| |
| void |
| add_method (type, fields, method) |
| tree type, *fields, method; |
| { |
| /* We must make a copy of METHOD here, since we must be sure that |
| we have exclusive title to this method's DECL_CHAIN. */ |
| tree decl; |
| |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| { |
| decl = copy_node (method); |
| if (DECL_RTL (decl) == 0 |
| && (!processing_template_decl |
| || !uses_template_parms (decl))) |
| { |
| make_function_rtl (decl); |
| DECL_RTL (method) = DECL_RTL (decl); |
| } |
| } |
| |
| if (fields && *fields) |
| { |
| /* Take care not to hide destructor. */ |
| DECL_CHAIN (decl) = DECL_CHAIN (*fields); |
| DECL_CHAIN (*fields) = decl; |
| } |
| else if (CLASSTYPE_METHOD_VEC (type) == 0) |
| { |
| tree method_vec = make_node (TREE_VEC); |
| if (TYPE_IDENTIFIER (type) == DECL_NAME (decl)) |
| { |
| /* ??? Is it possible for there to have been enough room in the |
| current chunk for the tree_vec structure but not a tree_vec |
| plus a tree*? Will this work in that case? */ |
| obstack_free (current_obstack, method_vec); |
| obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *)); |
| if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl))) |
| TREE_VEC_ELT (method_vec, 1) = decl; |
| else |
| TREE_VEC_ELT (method_vec, 0) = decl; |
| TREE_VEC_LENGTH (method_vec) = 2; |
| } |
| else |
| { |
| /* ??? Is it possible for there to have been enough room in the |
| current chunk for the tree_vec structure but not a tree_vec |
| plus a tree*? Will this work in that case? */ |
| obstack_free (current_obstack, method_vec); |
| obstack_blank (current_obstack, sizeof (struct tree_vec) + 2*sizeof (tree *)); |
| TREE_VEC_ELT (method_vec, 2) = decl; |
| TREE_VEC_LENGTH (method_vec) = 3; |
| obstack_finish (current_obstack); |
| } |
| CLASSTYPE_METHOD_VEC (type) = method_vec; |
| } |
| else |
| { |
| tree method_vec = CLASSTYPE_METHOD_VEC (type); |
| int len = TREE_VEC_LENGTH (method_vec); |
| |
| /* Adding a new ctor or dtor. This is easy because our |
| METHOD_VEC always has a slot for such entries. */ |
| if (TYPE_IDENTIFIER (type) == DECL_NAME (decl)) |
| { |
| int idx = !!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)); |
| /* TREE_VEC_ELT (method_vec, idx) = decl; */ |
| if (decl != TREE_VEC_ELT (method_vec, idx)) |
| { |
| DECL_CHAIN (decl) = TREE_VEC_ELT (method_vec, idx); |
| TREE_VEC_ELT (method_vec, idx) = decl; |
| } |
| } |
| else |
| { |
| /* This is trickier. We try to extend the TREE_VEC in-place, |
| but if that does not work, we copy all its data to a new |
| TREE_VEC that's large enough. */ |
| struct obstack *ob = &class_obstack; |
| tree *end = (tree *)obstack_next_free (ob); |
| |
| if (end != TREE_VEC_END (method_vec)) |
| { |
| ob = current_obstack; |
| TREE_VEC_LENGTH (method_vec) += 1; |
| TREE_VEC_ELT (method_vec, len) = NULL_TREE; |
| method_vec = copy_node (method_vec); |
| TREE_VEC_LENGTH (method_vec) -= 1; |
| } |
| else |
| { |
| tree tmp_vec = (tree) obstack_base (ob); |
| if (obstack_room (ob) < sizeof (tree)) |
| { |
| obstack_blank (ob, sizeof (struct tree_common) |
| + tree_code_length[(int) TREE_VEC] |
| * sizeof (char *) |
| + len * sizeof (tree)); |
| tmp_vec = (tree) obstack_base (ob); |
| bcopy ((char *) method_vec, (char *) tmp_vec, |
| (sizeof (struct tree_common) |
| + tree_code_length[(int) TREE_VEC] * sizeof (char *) |
| + (len-1) * sizeof (tree))); |
| method_vec = tmp_vec; |
| } |
| else |
| obstack_blank (ob, sizeof (tree)); |
| } |
| |
| obstack_finish (ob); |
| TREE_VEC_ELT (method_vec, len) = decl; |
| TREE_VEC_LENGTH (method_vec) = len + 1; |
| CLASSTYPE_METHOD_VEC (type) = method_vec; |
| |
| 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; |
| } |
| } |
| } |
| DECL_CONTEXT (decl) = type; |
| DECL_CLASS_CONTEXT (decl) = type; |
| |
| 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 (TREE_CODE (field) == TYPE_DECL |
| && TREE_CODE (x) == TYPE_DECL) |
| { |
| if (TREE_TYPE (field) == TREE_TYPE (x)) |
| continue; |
| cp_error_at ("duplicate nested type `%D'", x); |
| } |
| else if (TREE_CODE (field) == TYPE_DECL |
| || TREE_CODE (x) == TYPE_DECL) |
| { |
| /* 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. |
| Return 1 if change was legit, otherwise return 0. */ |
| |
| static int |
| alter_access (t, fdecl, access) |
| tree t; |
| tree fdecl; |
| tree access; |
| { |
| tree elem = purpose_member (t, DECL_ACCESS (fdecl)); |
| if (elem && 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 if (TREE_PRIVATE (fdecl)) |
| { |
| if (access != access_private_node) |
| cp_error_at ("cannot make private `%D' non-private", fdecl); |
| goto alter; |
| } |
| else if (TREE_PROTECTED (fdecl)) |
| { |
| if (access != access_protected_node) |
| cp_error_at ("cannot make protected `%D' non-protected", fdecl); |
| goto alter; |
| } |
| /* ARM 11.3: an access declaration may not be used to restrict access |
| to a member that is accessible in the base class. */ |
| else if (access != access_public_node) |
| cp_error_at ("cannot reduce access of public member `%D'", fdecl); |
| else if (elem == NULL_TREE) |
| { |
| alter: |
| DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl)); |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* If FOR_TYPE needs to reinitialize virtual function table pointers |
| for TYPE's sub-objects, add such reinitializations to BASE_INIT_LIST. |
| Returns BASE_INIT_LIST appropriately modified. */ |
| |
| static tree |
| maybe_fixup_vptrs (for_type, 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. |
| |
| Note that at this point TYPE_BINFO (t) != t_binfo. */ |
| |
| static int |
| finish_base_struct (t, b, t_binfo) |
| tree t; |
| struct base_info *b; |
| tree t_binfo; |
| { |
| tree binfos = BINFO_BASETYPES (t_binfo); |
| int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; |
| int first_vfn_base_index = -1; |
| bzero ((char *) b, sizeof (struct base_info)); |
| |
| for (i = 0; i < n_baseclasses; i++) |
| { |
| tree base_binfo = TREE_VEC_ELT (binfos, i); |
| tree basetype = BINFO_TYPE (base_binfo); |
| |
| /* If 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) |
| && BINFO_BASETYPES (base_binfo)) |
| { |
| tree base_binfos = BINFO_BASETYPES (base_binfo); |
| tree chain = NULL_TREE; |
| int j; |
| |
| /* Now unshare the structure beneath BASE_BINFO. */ |
| for (j = TREE_VEC_LENGTH (base_binfos)-1; |
| j >= 0; j--) |
| { |
| tree base_base_binfo = TREE_VEC_ELT (base_binfos, j); |
| if (! TREE_VIA_VIRTUAL (base_base_binfo)) |
| TREE_VEC_ELT (base_binfos, j) |
| = make_binfo (BINFO_OFFSET (base_base_binfo), |
| base_base_binfo, |
| BINFO_VTABLE (base_base_binfo), |
| BINFO_VIRTUALS (base_base_binfo), |
| chain); |
| chain = TREE_VEC_ELT (base_binfos, j); |
| TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo); |
| TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo); |
| BINFO_INHERITANCE_CHAIN (chain) = base_binfo; |
| } |
| |
| /* Completely unshare potentially shared data, and |
| update what is ours. */ |
| propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo)); |
| } |
| |
| 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. */ |
| BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype); |
| BINFO_VIRTUALS (t_binfo) = 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. */ |
| BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype); |
| BINFO_VIRTUALS (t_binfo) = 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); |
| } |
| } |
| } |
| } |
| } |
| |
| /* Must come after offsets are fixed for all bases. */ |
| for (i = 0; i < n_baseclasses; i++) |
| { |
| tree base_binfo = TREE_VEC_ELT (binfos, i); |
| tree basetype = BINFO_TYPE (base_binfo); |
| |
| if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2) |
| { |
| cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity", |
| basetype, t); |
| } |
| } |
| { |
| tree v = get_vbase_types (t_binfo); |
| |
| for (; v; v = TREE_CHAIN (v)) |
| { |
| tree basetype = BINFO_TYPE (v); |
| if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2) |
| { |
| if (extra_warnings) |
| cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity", |
| basetype, t); |
| } |
| } |
| } |
| |
| { |
| 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; |
| } |
| |
| static int |
| typecode_p (type, code) |
| tree type; |
| enum tree_code code; |
| { |
| return (TREE_CODE (type) == code |
| || (TREE_CODE (type) == REFERENCE_TYPE |
| && TREE_CODE (TREE_TYPE (type)) == code)); |
| } |
| |
| /* Set memoizing fields and bits of T (and its variants) for later use. |
| 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); |
| variants = TYPE_NEXT_VARIANT (variants); |
| } |
| |
| if (n_baseclasses && max_has_virtual) |
| { |
| /* Done by `finish_struct' for classes without baseclasses. */ |
| int might_have_abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (t) != 0; |
| tree binfos = TYPE_BINFO_BASETYPES (t); |
| for (i = n_baseclasses-1; i >= 0; i--) |
| { |
| might_have_abstract_virtuals |
| |= (CLASSTYPE_ABSTRACT_VIRTUALS (BINFO_TYPE (TREE_VEC_ELT (binfos, i))) != 0); |
| if (might_have_abstract_virtuals) |
| break; |
| } |
| if (might_have_abstract_virtuals) |
| { |
| /* We use error_mark_node from override_one_vtable to signal |
| an artificial abstract. */ |
| if (CLASSTYPE_ABSTRACT_VIRTUALS (t) == error_mark_node) |
| CLASSTYPE_ABSTRACT_VIRTUALS (t) = NULL_TREE; |
| 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)); |
| |
| if (TYPE_HAS_CONVERSION (basetype)) |
| { |
| TYPE_HAS_CONVERSION (t) = 1; |
| TYPE_HAS_INT_CONVERSION (t) |= TYPE_HAS_INT_CONVERSION (basetype); |
| TYPE_HAS_REAL_CONVERSION (t) |= TYPE_HAS_REAL_CONVERSION (basetype); |
| } |
| if (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; |
| } |
| } |
| } |
| |
| /* Add FNDECL to the method_vec growing on the class_obstack. Used by |
| finish_struct_methods. Note, FNDECL cannot be a constructor or |
| destructor, those cases are handled by the caller. */ |
| |
| static void |
| grow_method (fndecl, method_vec_ptr) |
| tree fndecl; |
| tree *method_vec_ptr; |
| { |
| tree method_vec = (tree)obstack_base (&class_obstack); |
| |
| /* Start off past the constructors and destructor. */ |
| tree *testp = &TREE_VEC_ELT (method_vec, 2); |
| |
| while (testp < (tree *) obstack_next_free (&class_obstack) |
| && (*testp == NULL_TREE || DECL_NAME (*testp) != DECL_NAME (fndecl))) |
| testp++; |
| |
| if (testp < (tree *) obstack_next_free (&class_obstack)) |
| { |
| tree x, prev_x; |
| |
| for (x = *testp; x; x = DECL_CHAIN (x)) |
| { |
| if (DECL_NAME (fndecl) == ansi_opname[(int) DELETE_EXPR] |
| || DECL_NAME (fndecl) == ansi_opname[(int) VEC_DELETE_EXPR]) |
| { |
| /* ANSI C++ June 5 1992 WP 12.5.5.1 */ |
| cp_error_at ("`%D' overloaded", fndecl); |
| cp_error_at ("previous declaration as `%D' here", x); |
| } |
| if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (x)) |
| { |
| /* Friend-friend ambiguities are warned about outside |
| this loop. */ |
| cp_error_at ("ambiguous method `%#D' in structure", fndecl); |
| break; |
| } |
| prev_x = x; |
| } |
| if (x == 0) |
| { |
| if (*testp) |
| DECL_CHAIN (prev_x) = fndecl; |
| else |
| *testp = fndecl; |
| } |
| } |
| else |
| { |
| obstack_ptr_grow (&class_obstack, fndecl); |
| *method_vec_ptr = (tree)obstack_base (&class_obstack); |
| } |
| } |
| |
| /* Warn about duplicate methods in fn_fields. Also compact method |
| lists so that lookup can be made faster. |
| |
| Algorithm: Outer loop builds lists by method name. Inner loop |
| checks for redundant method names within a list. |
| |
| Data Structure: List of method lists. The outer list is a |
| TREE_LIST, whose TREE_PURPOSE field is the field name and the |
| TREE_VALUE is the 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. */ |
| |
| tree |
| finish_struct_methods (t, fn_fields, nonprivate_method) |
| tree t; |
| tree fn_fields; |
| int nonprivate_method; |
| { |
| tree method_vec; |
| tree save_fn_fields = fn_fields; |
| tree ctor_name = constructor_name (t); |
| int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t); |
| |
| /* Now prepare to gather fn_fields into vector. */ |
| struct obstack *ambient_obstack = current_obstack; |
| current_obstack = &class_obstack; |
| method_vec = make_tree_vec (2); |
| current_obstack = ambient_obstack; |
| |
| /* Now make this a live vector. */ |
| obstack_free (&class_obstack, method_vec); |
| |
| /* Save room for constructors and destructors. */ |
| obstack_blank (&class_obstack, sizeof (struct tree_vec) + sizeof (struct tree *)); |
| |
| /* 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; 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; |
| } |
| } |
| if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fn_fields))) |
| { |
| /* Destructors go in slot 1. */ |
| DECL_CHAIN (fn_fields) = TREE_VEC_ELT (method_vec, 1); |
| TREE_VEC_ELT (method_vec, 1) = fn_fields; |
| } |
| else |
| { |
| /* Constructors go in slot 0. */ |
| DECL_CHAIN (fn_fields) = TREE_VEC_ELT (method_vec, 0); |
| TREE_VEC_ELT (method_vec, 0) = fn_fields; |
| } |
| } |
| else if (IDENTIFIER_TYPENAME_P (fn_name)) |
| { |
| tree return_type = TREE_TYPE (TREE_TYPE (fn_fields)); |
| |
| if (typecode_p (return_type, INTEGER_TYPE) |
| || typecode_p (return_type, BOOLEAN_TYPE) |
| || typecode_p (return_type, ENUMERAL_TYPE)) |
| TYPE_HAS_INT_CONVERSION (t) = 1; |
| else if (typecode_p (return_type, REAL_TYPE)) |
| TYPE_HAS_REAL_CONVERSION (t) = 1; |
| |
| grow_method (fn_fields, &method_vec); |
| } |
| } |
| |
| fn_fields = save_fn_fields; |
| for (; fn_fields; fn_fields = TREE_CHAIN (fn_fields)) |
| { |
| tree fn_name = DECL_NAME (fn_fields); |
| |
| if (fn_name == ctor_name || IDENTIFIER_TYPENAME_P (fn_name)) |
| continue; |
| |
| 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; |
| } |
| } |
| |
| grow_method (fn_fields, &method_vec); |
| } |
| |
| TREE_VEC_LENGTH (method_vec) = (tree *)obstack_next_free (&class_obstack) |
| - (&TREE_VEC_ELT (method_vec, 0)); |
| obstack_finish (&class_obstack); |
| CLASSTYPE_METHOD_VEC (t) = method_vec; |
| |
| if (nonprivate_method == 0 |
| && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE |
| && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE) |
| { |
| tree binfos = BINFO_BASETYPES (TYPE_BINFO (t)); |
| for (i = 0; i < n_baseclasses; i++) |
| if (TREE_VIA_PUBLIC (TREE_VEC_ELT (binfos, i)) |
| || TREE_VIA_PROTECTED (TREE_VEC_ELT (binfos, i))) |
| { |
| nonprivate_method = 1; |
| break; |
| } |
| if (nonprivate_method == 0 |
| && warn_ctor_dtor_privacy) |
| cp_warning ("all member functions in class `%T' are private", t); |
| } |
| |
| /* Warn if all destructors are private (in which case this class is |
| effectively unusable. */ |
| if (TYPE_HAS_DESTRUCTOR (t)) |
| { |
| tree dtor = TREE_VEC_ELT (method_vec, 1); |
| |
| /* Wild parse errors can cause this to happen. */ |
| if (dtor == NULL_TREE) |
| TYPE_HAS_DESTRUCTOR (t) = 0; |
| else if (TREE_PRIVATE (dtor) |
| && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE |
| && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE |
| && warn_ctor_dtor_privacy) |
| cp_warning ("`%#T' only defines a private destructor and has no friends", |
| 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 |
| && 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; i++) |
| { |
| TREE_VEC_ELT (baselink_vec, i) |
| = get_baselinks (baselink_binfo, t, DECL_NAME (TREE_VEC_ELT (method_vec, i))); |
| if (TREE_VEC_ELT (baselink_vec, i) != 0) |
| any_links = 1; |
| } |
| if (any_links != 0) |
| CLASSTYPE_BASELINK_VEC (t) = baselink_vec; |
| else |
| obstack_free (current_obstack, baselink_vec); |
| } |
| |
| return method_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 (unchain) = NULL_TREE; |
| unchain = DECL_CHAIN (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); |
| CLASSTYPE_VBASE_SIZE (t) = integer_zero_node; |
| 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 (write_virtuals >= 0 |
| && 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_READONLY (TREE_TYPE (TREE_VALUE (base_types))) |
| == TYPE_READONLY (TREE_TYPE (TREE_VALUE (types)))) |
| && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types), 3)) |
| 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 = size_binop (MINUS_EXPR, offset, base_offset); |
| |
| /* Make sure we can modify the derived association with immunity. */ |
| if (TREE_USED (binfo)) |
| my_friendly_assert (0, 999); |
| |
| 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 = size_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 (TREE_USED (binfo)) |
| my_friendly_assert (0, 999); |
| |
| 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. */ |
| /* For now, we just make it abstract. */ |
| tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0); |
| tree vfn; |
| |
| fndecl = copy_node (fndecl); |
| copy_lang_decl (fndecl); |
| DECL_ABSTRACT_VIRTUAL_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 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. */ |
| |
| 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)) |
| || flag_all_virtual == 1) |
| { |
| 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; ++i) |
| { |
| tree fndecl = TREE_VEC_ELT (method_vec, i); |
| |
| tree base_fndecls = NULL_TREE; |
| tree binfos = BINFO_BASETYPES (TYPE_BINFO (t)); |
| int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; |
| |
| 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); |
| } |
| |
| if (TREE_CHAIN (fndecl) |
| && DECL_NAME (TREE_CHAIN (fndecl)) == DECL_NAME (fndecl)) |
| fndecl = TREE_CHAIN (fndecl); |
| 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); |
| |
| if (TREE_CHAIN (fndecl) |
| && DECL_NAME (TREE_CHAIN (fndecl)) == DECL_NAME (fndecl)) |
| fndecl = TREE_CHAIN (fndecl); |
| 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 (TREE_CODE (*uelt) != FIELD_DECL) |
| 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 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. |
| |
| LIST_OF_FIELDLISTS is just that. The elements of the list are |
| TREE_LIST elements, whose TREE_PURPOSE field tells what access |
| the list has, and the TREE_VALUE slot gives the actual fields. |
| |
| ATTRIBUTES is the set of decl attributes to be applied, if any. |
| |
| If flag_all_virtual == 1, then we lay all functions into |
| the virtual function table, as though they were declared |
| virtual. Constructors do not lay down in the virtual function table. |
| |
| If flag_all_virtual == 2, then we lay all functions into |
| the virtual function table, such that virtual functions |
| occupy a space by themselves, and then all functions |
| of the class occupy a space by themselves. This is illustrated |
| in the following diagram: |
| |
| class A; class B : A; |
| |
| Class A's vtbl: Class B's vtbl: |
| -------------------------------------------------------------------- |
| | A's virtual functions| | B's virtual functions | |
| | | | (may inherit some from A). | |
| -------------------------------------------------------------------- |
| | All of A's functions | | All of A's functions | |
| | (such as a->A::f). | | (such as b->A::f) | |
| -------------------------------------------------------------------- |
| | B's new virtual functions | |
| | (not defined in A.) | |
| ------------------------------- |
| | All of B's functions | |
| | (such as b->B::f) | |
| ------------------------------- |
| |
| this allows the program to make references to any function, virtual |
| or otherwise in a type-consistent manner. */ |
| |
| tree |
| finish_struct_1 (t, warn_anon) |
| tree t; |
| int warn_anon; |
| { |
| int old; |
| tree name = TYPE_IDENTIFIER (t); |
| enum tree_code code = TREE_CODE (t); |
| tree fields = TYPE_FIELDS (t); |
| tree fn_fields = TYPE_METHODS (t); |
| tree x, last_x, method_vec; |
| int all_virtual; |
| int has_virtual; |
| int max_has_virtual; |
| tree pending_virtuals = NULL_TREE; |
| tree abstract_virtuals = NULL_TREE; |
| tree vfield; |
| tree vfields; |
| int cant_have_default_ctor; |
| int cant_have_const_ctor; |
| int no_const_asn_ref; |
| |
| /* 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; |
| int nonprivate_method = 0; |
| tree t_binfo = TYPE_BINFO (t); |
| 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 |
| |
| #if 0 |
| if (flag_rtti) |
| build_t_desc (t, 0); |
| #endif |
| |
| TYPE_BINFO (t) = NULL_TREE; |
| |
| 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 (t_binfo && BINFO_BASETYPES (t_binfo)) |
| n_baseclasses = TREE_VEC_LENGTH (BINFO_BASETYPES (t_binfo)); |
| else |
| n_baseclasses = 0; |
| |
| if (n_baseclasses > 0) |
| { |
| struct base_info base_info; |
| |
| /* If using multiple inheritance, this may cause variants of our |
| basetypes to be used (instead of their canonical forms). */ |
| tree vf = layout_basetypes (t, BINFO_BASETYPES (t_binfo)); |
| last_x = tree_last (vf); |
| fields = chainon (vf, fields); |
| |
| first_vfn_base_index = finish_base_struct (t, &base_info, t_binfo); |
| /* 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; |
| n_baseclasses = TREE_VEC_LENGTH (BINFO_BASETYPES (t_binfo)); |
| 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; |
| last_x = 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. */ |
| TREE_CHAIN (t_binfo) = TYPE_BINFO (t); |
| TYPE_BINFO (t) = t_binfo; |
| CLASSTYPE_VFIELDS (t) = vfields; |
| CLASSTYPE_VFIELD (t) = vfield; |
| |
| if (IS_SIGNATURE (t)) |
| all_virtual = 0; |
| else if (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (t)) |
| all_virtual = 1; |
| else |
| all_virtual = 0; |
| |
| for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) |
| { |
| GNU_xref_member (current_class_name, x); |
| |
| nonprivate_method |= ! TREE_PRIVATE (x); |
| |
| /* If this was an evil function, don't keep it in class. */ |
| if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x))) |
| continue; |
| |
| DECL_CLASS_CONTEXT (x) = t; |
| |
| /* Do both of these, even though they're in the same union; |
| if the insn `r' member and the size `i' member are |
|