diff options
Diffstat (limited to 'gnu/usr.bin/cc/cc1plus/tree.c')
-rw-r--r-- | gnu/usr.bin/cc/cc1plus/tree.c | 1763 |
1 files changed, 1763 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc1plus/tree.c b/gnu/usr.bin/cc/cc1plus/tree.c new file mode 100644 index 0000000..88466b8 --- /dev/null +++ b/gnu/usr.bin/cc/cc1plus/tree.c @@ -0,0 +1,1763 @@ +/* Language-dependent node constructors for parse phase of GNU compiler. + Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc. + Hacked by Michael Tiemann (tiemann@cygnus.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include <stdio.h> +#include "obstack.h" +#include "tree.h" +#include "cp-tree.h" +#include "flags.h" + +#define CEIL(x,y) (((x) + (y) - 1) / (y)) + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless they have TREE_READONLY. + Lvalues can have their address taken, unless they have DECL_REGISTER. */ + +int +lvalue_p (ref) + tree ref; +{ + register enum tree_code code = TREE_CODE (ref); + + if (language_lvalue_valid (ref)) + { + if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) + return 1; + + switch (code) + { + /* preincrements and predecrements are valid lvals, provided + what they refer to are valid lvals. */ + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case COMPONENT_REF: + case SAVE_EXPR: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case STRING_CST: + return 1; + + case VAR_DECL: + if (TREE_READONLY (ref) && ! TREE_STATIC (ref) + && DECL_LANG_SPECIFIC (ref) + && DECL_IN_AGGR_P (ref)) + return 0; + case INDIRECT_REF: + case ARRAY_REF: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) + return 1; + break; + + case TARGET_EXPR: + case WITH_CLEANUP_EXPR: + return 1; + + /* A currently unresolved scope ref. */ + case SCOPE_REF: + my_friendly_abort (103); + case OFFSET_REF: + if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL) + return 1; + return lvalue_p (TREE_OPERAND (ref, 0)) + && lvalue_p (TREE_OPERAND (ref, 1)); + break; + + case COND_EXPR: + return (lvalue_p (TREE_OPERAND (ref, 1)) + && lvalue_p (TREE_OPERAND (ref, 2))); + + case MODIFY_EXPR: + return 1; + + case COMPOUND_EXPR: + return lvalue_p (TREE_OPERAND (ref, 1)); + } + } + return 0; +} + +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. */ + +int +lvalue_or_else (ref, string) + tree ref; + char *string; +{ + int win = lvalue_p (ref); + if (! win) + error ("non-lvalue in %s", string); + return win; +} + +/* INIT is a CALL_EXPR which needs info about its target. + TYPE is the type that this initialization should appear to have. + + Build an encapsulation of the initialization to perform + and return it so that it can be processed by language-independent + and language-specific expression expanders. + + If WITH_CLEANUP_P is nonzero, we build a cleanup for this expression. + Otherwise, cleanups are not built here. For example, when building + an initialization for a stack slot, since the called function handles + the cleanup, we would not want to do it here. */ +tree +build_cplus_new (type, init, with_cleanup_p) + tree type; + tree init; + int with_cleanup_p; +{ + tree slot = build (VAR_DECL, type); + tree rval = build (NEW_EXPR, type, + TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot); + TREE_SIDE_EFFECTS (rval) = 1; + TREE_ADDRESSABLE (rval) = 1; + rval = build (TARGET_EXPR, type, slot, rval, 0); + TREE_SIDE_EFFECTS (rval) = 1; + TREE_ADDRESSABLE (rval) = 1; + +#if 0 + if (with_cleanup_p && TYPE_NEEDS_DESTRUCTOR (type)) + { + TREE_OPERAND (rval, 2) = error_mark_node; + rval = build (WITH_CLEANUP_EXPR, type, rval, 0, + build_delete (TYPE_POINTER_TO (type), + build_unary_op (ADDR_EXPR, slot, 0), + integer_two_node, + LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0)); + TREE_SIDE_EFFECTS (rval) = 1; + TREE_ADDRESSABLE (rval) = 1; + } +#endif + return rval; +} + +/* Recursively search EXP for CALL_EXPRs that need cleanups and replace + these CALL_EXPRs with tree nodes that will perform the cleanups. */ + +tree +break_out_cleanups (exp) + tree exp; +{ + tree tmp = exp; + + if (TREE_CODE (tmp) == CALL_EXPR + && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp))) + return build_cplus_new (TREE_TYPE (tmp), tmp, 1); + + while (TREE_CODE (tmp) == NOP_EXPR + || TREE_CODE (tmp) == CONVERT_EXPR + || TREE_CODE (tmp) == NON_LVALUE_EXPR) + { + if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR + && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0)))) + { + TREE_OPERAND (tmp, 0) + = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)), + TREE_OPERAND (tmp, 0), 1); + break; + } + else + tmp = TREE_OPERAND (tmp, 0); + } + return exp; +} + +/* Recursively perform a preorder search EXP for CALL_EXPRs, making + copies where they are found. Returns a deep copy all nodes transitively + containing CALL_EXPRs. */ + +tree +break_out_calls (exp) + tree exp; +{ + register tree t1, t2; + register enum tree_code code; + register int changed = 0; + register int i; + + if (exp == NULL_TREE) + return exp; + + code = TREE_CODE (exp); + + if (code == CALL_EXPR) + return copy_node (exp); + + /* Don't try and defeat a save_expr, as it should only be done once. */ + if (code == SAVE_EXPR) + return exp; + + switch (TREE_CODE_CLASS (code)) + { + default: + abort (); + + case 'c': /* a constant */ + case 't': /* a type node */ + case 'x': /* something random, like an identifier or an ERROR_MARK. */ + return exp; + + case 'd': /* A decl node */ + t1 = break_out_calls (DECL_INITIAL (exp)); + if (t1 != DECL_INITIAL (exp)) + { + exp = copy_node (exp); + DECL_INITIAL (exp) = t1; + } + return exp; + + case 'b': /* A block node */ + { + /* Don't know how to handle these correctly yet. Must do a + break_out_calls on all DECL_INITIAL values for local variables, + and also break_out_calls on all sub-blocks and sub-statements. */ + abort (); + } + return exp; + + case 'e': /* an expression */ + case 'r': /* a reference */ + case 's': /* an expression with side effects */ + for (i = tree_code_length[(int) code] - 1; i >= 0; i--) + { + t1 = break_out_calls (TREE_OPERAND (exp, i)); + if (t1 != TREE_OPERAND (exp, i)) + { + exp = copy_node (exp); + TREE_OPERAND (exp, i) = t1; + } + } + return exp; + + case '<': /* a comparison expression */ + case '2': /* a binary arithmetic expression */ + t2 = break_out_calls (TREE_OPERAND (exp, 1)); + if (t2 != TREE_OPERAND (exp, 1)) + changed = 1; + case '1': /* a unary arithmetic expression */ + t1 = break_out_calls (TREE_OPERAND (exp, 0)); + if (t1 != TREE_OPERAND (exp, 0)) + changed = 1; + if (changed) + { + if (tree_code_length[(int) code] == 1) + return build1 (code, TREE_TYPE (exp), t1); + else + return build (code, TREE_TYPE (exp), t1, t2); + } + return exp; + } + +} + +extern struct obstack *current_obstack; +extern struct obstack permanent_obstack, class_obstack; +extern struct obstack *saveable_obstack; + +/* Here is how primitive or already-canonicalized types' hash + codes are made. MUST BE CONSISTENT WITH tree.c !!! */ +#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777) + +/* Construct, lay out and return the type of methods belonging to class + BASETYPE and whose arguments are described by ARGTYPES and whose values + are described by RETTYPE. If each type exists already, reuse it. */ +tree +build_cplus_method_type (basetype, rettype, argtypes) + tree basetype, rettype, argtypes; +{ + register tree t; + tree ptype; + int hashcode; + + /* Make a node of the sort we want. */ + t = make_node (METHOD_TYPE); + + TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype); + TREE_TYPE (t) = rettype; + if (IS_SIGNATURE (basetype)) + ptype = build_signature_pointer_type (TYPE_MAIN_VARIANT (basetype), + TYPE_READONLY (basetype), + TYPE_VOLATILE (basetype)); + else + { + ptype = build_pointer_type (basetype); + ptype = build_type_variant (ptype, 1, 0); + } + /* The actual arglist for this function includes a "hidden" argument + which is "this". Put it into the list of argument types. */ + + argtypes = tree_cons (NULL_TREE, ptype, argtypes); + TYPE_ARG_TYPES (t) = argtypes; + TREE_SIDE_EFFECTS (argtypes) = 1; /* Mark first argtype as "artificial". */ + + /* If we already have such a type, use the old one and free this one. + Note that it also frees up the above cons cell if found. */ + hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes); + t = type_hash_canon (hashcode, t); + + if (TYPE_SIZE (t) == 0) + layout_type (t); + + return t; +} + +tree +build_cplus_staticfn_type (basetype, rettype, argtypes) + tree basetype, rettype, argtypes; +{ + register tree t; + int hashcode; + + /* Make a node of the sort we want. */ + t = make_node (FUNCTION_TYPE); + + TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype); + TREE_TYPE (t) = rettype; + + TYPE_ARG_TYPES (t) = argtypes; + + /* If we already have such a type, use the old one and free this one. + Note that it also frees up the above cons cell if found. */ + hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes); + t = type_hash_canon (hashcode, t); + + if (TYPE_SIZE (t) == 0) + layout_type (t); + + return t; +} + +tree +build_cplus_array_type (elt_type, index_type) + tree elt_type; + tree index_type; +{ + register struct obstack *ambient_obstack = current_obstack; + register struct obstack *ambient_saveable_obstack = saveable_obstack; + tree t; + + /* We need a new one. If both ELT_TYPE and INDEX_TYPE are permanent, + make this permanent too. */ + if (TREE_PERMANENT (elt_type) + && (index_type == 0 || TREE_PERMANENT (index_type))) + { + current_obstack = &permanent_obstack; + saveable_obstack = &permanent_obstack; + } + + t = build_array_type (elt_type, index_type); + + /* Push these needs up so that initialization takes place + more easily. */ + TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type)); + TYPE_NEEDS_DESTRUCTOR (t) = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); + current_obstack = ambient_obstack; + saveable_obstack = ambient_saveable_obstack; + return t; +} + +/* Add OFFSET to all base types of T. + + OFFSET, which is a type offset, is number of bytes. + + Note that we don't have to worry about having two paths to the + same base type, since this type owns its association list. */ +void +propagate_binfo_offsets (binfo, offset) + tree binfo; + tree offset; +{ + tree binfos = BINFO_BASETYPES (binfo); + int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; + + for (i = 0; i < n_baselinks; /* note increment is done in the loop. */) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + + if (TREE_VIA_VIRTUAL (base_binfo)) + i += 1; + else + { + int j; + tree base_binfos = BINFO_BASETYPES (base_binfo); + tree delta; + + for (j = i+1; j < n_baselinks; j++) + if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j))) + { + /* The next basetype offset must take into account the space + between the classes, not just the size of each class. */ + delta = size_binop (MINUS_EXPR, + BINFO_OFFSET (TREE_VEC_ELT (binfos, j)), + BINFO_OFFSET (base_binfo)); + break; + } + +#if 0 + if (BINFO_OFFSET_ZEROP (base_binfo)) + BINFO_OFFSET (base_binfo) = offset; + else + BINFO_OFFSET (base_binfo) + = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset); +#else + BINFO_OFFSET (base_binfo) = offset; +#endif + if (base_binfos) + { + int k; + tree chain = NULL_TREE; + + /* Now unshare the structure beneath BASE_BINFO. */ + for (k = TREE_VEC_LENGTH (base_binfos)-1; + k >= 0; k--) + { + tree base_base_binfo = TREE_VEC_ELT (base_binfos, k); + if (! TREE_VIA_VIRTUAL (base_base_binfo)) + TREE_VEC_ELT (base_binfos, k) + = 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, k); + TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo); + TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo); + } + /* Now propagate the offset to the base types. */ + propagate_binfo_offsets (base_binfo, offset); + } + + /* Go to our next class that counts for offset propagation. */ + i = j; + if (i < n_baselinks) + offset = size_binop (PLUS_EXPR, offset, delta); + } + } +} + +/* Compute the actual offsets that our virtual base classes + will have *for this type*. This must be performed after + the fields are laid out, since virtual baseclasses must + lay down at the end of the record. + + Returns the maximum number of virtual functions any of the virtual + baseclasses provide. */ +int +layout_vbasetypes (rec, max) + tree rec; + int max; +{ + /* Get all the virtual base types that this type uses. + The TREE_VALUE slot holds the virtual baseclass type. */ + tree vbase_types = get_vbase_types (rec); + +#ifdef STRUCTURE_SIZE_BOUNDARY + unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec)); +#else + unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec)); +#endif + int desired_align; + + /* Record size so far is CONST_SIZE + VAR_SIZE bits, + where CONST_SIZE is an integer + and VAR_SIZE is a tree expression. + If VAR_SIZE is null, the size is just CONST_SIZE. + Naturally we try to avoid using VAR_SIZE. */ + register unsigned const_size = 0; + register tree var_size = 0; + int nonvirtual_const_size; + tree nonvirtual_var_size; + + CLASSTYPE_VBASECLASSES (rec) = vbase_types; + + if (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST) + const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec)); + else + var_size = TYPE_SIZE (rec); + + nonvirtual_const_size = const_size; + nonvirtual_var_size = var_size; + + while (vbase_types) + { + tree basetype = BINFO_TYPE (vbase_types); + tree offset; + + desired_align = TYPE_ALIGN (basetype); + record_align = MAX (record_align, desired_align); + + if (const_size == 0) + offset = integer_zero_node; + else + { + /* Give each virtual base type the alignment it wants. */ + const_size = CEIL (const_size, TYPE_ALIGN (basetype)) + * TYPE_ALIGN (basetype); + offset = size_int (CEIL (const_size, BITS_PER_UNIT)); + } + + if (CLASSTYPE_VSIZE (basetype) > max) + max = CLASSTYPE_VSIZE (basetype); + BINFO_OFFSET (vbase_types) = offset; + + if (TREE_CODE (TYPE_SIZE (basetype)) == INTEGER_CST) + const_size += MAX (BITS_PER_UNIT, + TREE_INT_CST_LOW (TYPE_SIZE (basetype)) + - TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype))); + else if (var_size == 0) + var_size = TYPE_SIZE (basetype); + else + var_size = size_binop (PLUS_EXPR, var_size, TYPE_SIZE (basetype)); + + vbase_types = TREE_CHAIN (vbase_types); + } + + /* Set the alignment in the complete type. We don't set CLASSTYPE_ALIGN + here, as that is for this class, without any virtual base classes. */ + TYPE_ALIGN (rec) = record_align; + if (const_size != nonvirtual_const_size) + { + CLASSTYPE_VBASE_SIZE (rec) + = size_int (const_size - nonvirtual_const_size); + TYPE_SIZE (rec) = size_int (const_size); + } + + /* Now propagate offset information throughout the lattice + under the vbase type. */ + for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types; + vbase_types = TREE_CHAIN (vbase_types)) + { + tree base_binfos = BINFO_BASETYPES (vbase_types); + + if (base_binfos) + { + 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); + } + + propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types)); + } + } + + return max; +} + +/* Lay out the base types of a record type, REC. + Tentatively set the size and alignment of REC + according to the base types alone. + + Offsets for immediate nonvirtual baseclasses are also computed here. + + TYPE_BINFO (REC) should be NULL_TREE on entry, and this routine + creates a list of base_binfos in TYPE_BINFO (REC) from BINFOS. + + Returns list of virtual base classes in a FIELD_DECL chain. */ +tree +layout_basetypes (rec, binfos) + tree rec, binfos; +{ + /* Chain to hold all the new FIELD_DECLs which point at virtual + base classes. */ + tree vbase_decls = NULL_TREE; + +#ifdef STRUCTURE_SIZE_BOUNDARY + unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec)); +#else + unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec)); +#endif + + /* Record size so far is CONST_SIZE + VAR_SIZE bits, where CONST_SIZE is + an integer and VAR_SIZE is a tree expression. If VAR_SIZE is null, + the size is just CONST_SIZE. Naturally we try to avoid using + VAR_SIZE. And so far, we've been sucessful. */ +#if 0 + register tree var_size = 0; +#endif + + register unsigned const_size = 0; + int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; + + /* Handle basetypes almost like fields, but record their + offsets differently. */ + + for (i = 0; i < n_baseclasses; i++) + { + int inc, desired_align, int_vbase_size; + register tree base_binfo = TREE_VEC_ELT (binfos, i); + register tree basetype = BINFO_TYPE (base_binfo); + tree decl, offset; + + if (TYPE_SIZE (basetype) == 0) + { +#if 0 + /* This error is now reported in xref_tag, thus giving better + location information. */ + error_with_aggr_type (base_binfo, + "base class `%s' has incomplete type"); + + TREE_VIA_PUBLIC (base_binfo) = 1; + TREE_VIA_PROTECTED (base_binfo) = 0; + TREE_VIA_VIRTUAL (base_binfo) = 0; + + /* Should handle this better so that + + class A; + class B: private A { virtual void F(); }; + + does not dump core when compiled. */ + my_friendly_abort (121); +#endif + continue; + } + + /* All basetypes are recorded in the association list of the + derived type. */ + + if (TREE_VIA_VIRTUAL (base_binfo)) + { + int j; + char *name = (char *)alloca (TYPE_NAME_LENGTH (basetype) + + sizeof (VBASE_NAME) + 1); + + /* The offset for a virtual base class is only used in computing + virtual function tables and for initializing virtual base + pointers. It is built once `get_vbase_types' is called. */ + + /* If this basetype can come from another vbase pointer + without an additional indirection, we will share + that pointer. If an indirection is involved, we + make our own pointer. */ + for (j = 0; j < n_baseclasses; j++) + { + tree other_base_binfo = TREE_VEC_ELT (binfos, j); + if (! TREE_VIA_VIRTUAL (other_base_binfo) + && binfo_member (basetype, + CLASSTYPE_VBASECLASSES (BINFO_TYPE (other_base_binfo)))) + goto got_it; + } + sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype)); + decl = build_lang_decl (FIELD_DECL, get_identifier (name), + build_pointer_type (basetype)); + /* If you change any of the below, take a look at all the + other VFIELD_BASEs and VTABLE_BASEs in the code, and change + them too. */ + DECL_ASSEMBLER_NAME (decl) = get_identifier (VTABLE_BASE); + DECL_VIRTUAL_P (decl) = 1; + DECL_FIELD_CONTEXT (decl) = rec; + DECL_CLASS_CONTEXT (decl) = rec; + DECL_FCONTEXT (decl) = basetype; + DECL_FIELD_SIZE (decl) = 0; + DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node); + TREE_CHAIN (decl) = vbase_decls; + BINFO_VPTR_FIELD (base_binfo) = decl; + vbase_decls = decl; + + if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype) + && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE) + { + warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0), + "destructor `%s' non-virtual"); + warning ("in inheritance relationship `%s: virtual %s'", + TYPE_NAME_STRING (rec), + TYPE_NAME_STRING (basetype)); + } + got_it: + /* The space this decl occupies has already been accounted for. */ + continue; + } + + if (const_size == 0) + offset = integer_zero_node; + else + { + /* Give each base type the alignment it wants. */ + const_size = CEIL (const_size, TYPE_ALIGN (basetype)) + * TYPE_ALIGN (basetype); + offset = size_int ((const_size + BITS_PER_UNIT - 1) / BITS_PER_UNIT); + +#if 0 + /* bpk: Disabled this check until someone is willing to + claim it as theirs and explain exactly what circumstances + warrant the warning. */ + if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype) + && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE) + { + warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0), + "destructor `%s' non-virtual"); + warning ("in inheritance relationship `%s:%s %s'", + TYPE_NAME_STRING (rec), + TREE_VIA_VIRTUAL (base_binfo) ? " virtual" : "", + TYPE_NAME_STRING (basetype)); + } +#endif + } + BINFO_OFFSET (base_binfo) = offset; + if (CLASSTYPE_VSIZE (basetype)) + { + BINFO_VTABLE (base_binfo) = TYPE_BINFO_VTABLE (basetype); + BINFO_VIRTUALS (base_binfo) = TYPE_BINFO_VIRTUALS (basetype); + } + TREE_CHAIN (base_binfo) = TYPE_BINFO (rec); + TYPE_BINFO (rec) = base_binfo; + + /* Add only the amount of storage not present in + the virtual baseclasses. */ + + int_vbase_size = TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype)); + if (TREE_INT_CST_LOW (TYPE_SIZE (basetype)) > int_vbase_size) + { + inc = MAX (record_align, + (TREE_INT_CST_LOW (TYPE_SIZE (basetype)) + - int_vbase_size)); + + /* Record must have at least as much alignment as any field. */ + desired_align = TYPE_ALIGN (basetype); + record_align = MAX (record_align, desired_align); + + const_size += inc; + } + } + + if (const_size) + CLASSTYPE_SIZE (rec) = size_int (const_size); + else + CLASSTYPE_SIZE (rec) = integer_zero_node; + CLASSTYPE_ALIGN (rec) = record_align; + + return vbase_decls; +} + +/* Hashing of lists so that we don't make duplicates. + The entry point is `list_hash_canon'. */ + +/* Each hash table slot is a bucket containing a chain + of these structures. */ + +struct list_hash +{ + struct list_hash *next; /* Next structure in the bucket. */ + int hashcode; /* Hash code of this list. */ + tree list; /* The list recorded here. */ +}; + +/* Now here is the hash table. When recording a list, it is added + to the slot whose index is the hash code mod the table size. + Note that the hash table is used for several kinds of lists. + While all these live in the same table, they are completely independent, + and the hash code is computed differently for each of these. */ + +#define TYPE_HASH_SIZE 59 +struct list_hash *list_hash_table[TYPE_HASH_SIZE]; + +/* Compute a hash code for a list (chain of TREE_LIST nodes + with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the + TREE_COMMON slots), by adding the hash codes of the individual entries. */ + +int +list_hash (list) + tree list; +{ + register int hashcode = 0; + + if (TREE_CHAIN (list)) + hashcode += TYPE_HASH (TREE_CHAIN (list)); + + if (TREE_VALUE (list)) + hashcode += TYPE_HASH (TREE_VALUE (list)); + else + hashcode += 1007; + if (TREE_PURPOSE (list)) + hashcode += TYPE_HASH (TREE_PURPOSE (list)); + else + hashcode += 1009; + return hashcode; +} + +/* Look in the type hash table for a type isomorphic to TYPE. + If one is found, return it. Otherwise return 0. */ + +tree +list_hash_lookup (hashcode, list) + int hashcode; + tree list; +{ + register struct list_hash *h; + for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next) + if (h->hashcode == hashcode + && TREE_VIA_VIRTUAL (h->list) == TREE_VIA_VIRTUAL (list) + && TREE_VIA_PUBLIC (h->list) == TREE_VIA_PUBLIC (list) + && TREE_VIA_PROTECTED (h->list) == TREE_VIA_PROTECTED (list) + && TREE_PURPOSE (h->list) == TREE_PURPOSE (list) + && TREE_VALUE (h->list) == TREE_VALUE (list) + && TREE_CHAIN (h->list) == TREE_CHAIN (list)) + { + my_friendly_assert (TREE_TYPE (h->list) == TREE_TYPE (list), 299); + return h->list; + } + return 0; +} + +/* Add an entry to the list-hash-table + for a list TYPE whose hash code is HASHCODE. */ + +void +list_hash_add (hashcode, list) + int hashcode; + tree list; +{ + register struct list_hash *h; + + h = (struct list_hash *) obstack_alloc (&class_obstack, sizeof (struct list_hash)); + h->hashcode = hashcode; + h->list = list; + h->next = list_hash_table[hashcode % TYPE_HASH_SIZE]; + list_hash_table[hashcode % TYPE_HASH_SIZE] = h; +} + +/* Given TYPE, and HASHCODE its hash code, return the canonical + object for an identical list if one already exists. + Otherwise, return TYPE, and record it as the canonical object + if it is a permanent object. + + To use this function, first create a list of the sort you want. + Then compute its hash code from the fields of the list that + make it different from other similar lists. + Then call this function and use the value. + This function frees the list you pass in if it is a duplicate. */ + +/* Set to 1 to debug without canonicalization. Never set by program. */ +static int debug_no_list_hash = 0; + +tree +list_hash_canon (hashcode, list) + int hashcode; + tree list; +{ + tree t1; + + if (debug_no_list_hash) + return list; + + t1 = list_hash_lookup (hashcode, list); + if (t1 != 0) + { + obstack_free (&class_obstack, list); + return t1; + } + + /* If this is a new list, record it for later reuse. */ + list_hash_add (hashcode, list); + + return list; +} + +tree +hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain) + int via_public, via_virtual, via_protected; + tree purpose, value, chain; +{ + struct obstack *ambient_obstack = current_obstack; + tree t; + int hashcode; + + current_obstack = &class_obstack; + t = tree_cons (purpose, value, chain); + TREE_VIA_PUBLIC (t) = via_public; + TREE_VIA_PROTECTED (t) = via_protected; + TREE_VIA_VIRTUAL (t) = via_virtual; + hashcode = list_hash (t); + t = list_hash_canon (hashcode, t); + current_obstack = ambient_obstack; + return t; +} + +/* Constructor for hashed lists. */ +tree +hash_tree_chain (value, chain) + tree value, chain; +{ + struct obstack *ambient_obstack = current_obstack; + tree t; + int hashcode; + + current_obstack = &class_obstack; + t = tree_cons (NULL_TREE, value, chain); + hashcode = list_hash (t); + t = list_hash_canon (hashcode, t); + current_obstack = ambient_obstack; + return t; +} + +/* Similar, but used for concatenating two lists. */ +tree +hash_chainon (list1, list2) + tree list1, list2; +{ + if (list2 == 0) + return list1; + if (list1 == 0) + return list2; + if (TREE_CHAIN (list1) == NULL_TREE) + return hash_tree_chain (TREE_VALUE (list1), list2); + return hash_tree_chain (TREE_VALUE (list1), + hash_chainon (TREE_CHAIN (list1), list2)); +} + +static tree +get_identifier_list (value) + tree value; +{ + tree list = IDENTIFIER_AS_LIST (value); + if (list != NULL_TREE + && (TREE_CODE (list) != TREE_LIST + || TREE_VALUE (list) != value)) + list = NULL_TREE; + else if (IDENTIFIER_HAS_TYPE_VALUE (value) + && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE + && IDENTIFIER_TYPE_VALUE (value) + == TYPE_MAIN_VARIANT (IDENTIFIER_TYPE_VALUE (value))) + { + tree type = IDENTIFIER_TYPE_VALUE (value); + + if (TYPE_PTRMEMFUNC_P (type)) + list = NULL_TREE; + else if (type == current_class_type) + /* Don't mess up the constructor name. */ + list = tree_cons (NULL_TREE, value, NULL_TREE); + else + { + register tree id; + /* This will return the correct thing for regular types, + nested types, and templates. Yay! */ + if (TYPE_NESTED_NAME (type)) + id = TYPE_NESTED_NAME (type); + else + id = TYPE_IDENTIFIER (type); + + if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE) + CLASSTYPE_ID_AS_LIST (type) + = perm_tree_cons (NULL_TREE, id, NULL_TREE); + list = CLASSTYPE_ID_AS_LIST (type); + } + } + return list; +} + +tree +get_decl_list (value) + tree value; +{ + tree list = NULL_TREE; + + if (TREE_CODE (value) == IDENTIFIER_NODE) + list = get_identifier_list (value); + else if (TREE_CODE (value) == RECORD_TYPE + && TYPE_LANG_SPECIFIC (value)) + list = CLASSTYPE_AS_LIST (value); + + if (list != NULL_TREE) + { + my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 301); + return list; + } + + return build_decl_list (NULL_TREE, value); +} + +/* Look in the type hash table for a type isomorphic to + `build_tree_list (NULL_TREE, VALUE)'. + If one is found, return it. Otherwise return 0. */ + +tree +list_hash_lookup_or_cons (value) + tree value; +{ + register int hashcode = TYPE_HASH (value); + register struct list_hash *h; + struct obstack *ambient_obstack; + tree list = NULL_TREE; + + if (TREE_CODE (value) == IDENTIFIER_NODE) + list = get_identifier_list (value); + else if (TREE_CODE (value) == TYPE_DECL + && TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE + && TYPE_LANG_SPECIFIC (TREE_TYPE (value))) + list = CLASSTYPE_ID_AS_LIST (TREE_TYPE (value)); + else if (TREE_CODE (value) == RECORD_TYPE + && TYPE_LANG_SPECIFIC (value)) + list = CLASSTYPE_AS_LIST (value); + + if (list != NULL_TREE) + { + my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 302); + return list; + } + + if (debug_no_list_hash) + return hash_tree_chain (value, NULL_TREE); + + for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next) + if (h->hashcode == hashcode + && TREE_VIA_VIRTUAL (h->list) == 0 + && TREE_VIA_PUBLIC (h->list) == 0 + && TREE_VIA_PROTECTED (h->list) == 0 + && TREE_PURPOSE (h->list) == 0 + && TREE_VALUE (h->list) == value) + { + my_friendly_assert (TREE_TYPE (h->list) == 0, 303); + my_friendly_assert (TREE_CHAIN (h->list) == 0, 304); + return h->list; + } + + ambient_obstack = current_obstack; + current_obstack = &class_obstack; + list = build_tree_list (NULL_TREE, value); + list_hash_add (hashcode, list); + current_obstack = ambient_obstack; + return list; +} + +/* Build an association between TYPE and some parameters: + + OFFSET is the offset added to `this' to convert it to a pointer + of type `TYPE *' + + BINFO is the base binfo to use, if we are deriving from one. This + is necessary, as we want specialized parent binfos from base + classes, so that the VTABLE_NAMEs of bases are for the most derived + type, instead of of the simple type. + + VTABLE is the virtual function table with which to initialize + sub-objects of type TYPE. + + VIRTUALS are the virtual functions sitting in VTABLE. + + CHAIN are more associations we must retain. */ + +tree +make_binfo (offset, binfo, vtable, virtuals, chain) + tree offset, binfo; + tree vtable, virtuals; + tree chain; +{ + tree new_binfo = make_tree_vec (6); + tree type; + + if (TREE_CODE (binfo) == TREE_VEC) + type = BINFO_TYPE (binfo); + else + { + type = binfo; + binfo = TYPE_BINFO (binfo); + } + + TREE_CHAIN (new_binfo) = chain; + if (chain) + TREE_USED (new_binfo) = TREE_USED (chain); + + TREE_TYPE (new_binfo) = TYPE_MAIN_VARIANT (type); + BINFO_OFFSET (new_binfo) = offset; + BINFO_VTABLE (new_binfo) = vtable; + BINFO_VIRTUALS (new_binfo) = virtuals; + BINFO_VPTR_FIELD (new_binfo) = NULL_TREE; + + if (binfo && BINFO_BASETYPES (binfo) != NULL_TREE) + BINFO_BASETYPES (new_binfo) = copy_node (BINFO_BASETYPES (binfo)); + return new_binfo; +} + +tree +copy_binfo (list) + tree list; +{ + tree binfo = copy_list (list); + tree rval = binfo; + while (binfo) + { + TREE_USED (binfo) = 0; + if (BINFO_BASETYPES (binfo)) + BINFO_BASETYPES (binfo) = copy_node (BINFO_BASETYPES (binfo)); + binfo = TREE_CHAIN (binfo); + } + return rval; +} + +/* Return the binfo value for ELEM in TYPE. */ + +tree +binfo_value (elem, type) + tree elem; + tree type; +{ + if (get_base_distance (elem, type, 0, (tree *)0) == -2) + compiler_error ("base class `%s' ambiguous in binfo_value", + TYPE_NAME_STRING (elem)); + if (elem == type) + return TYPE_BINFO (type); + if (TREE_CODE (elem) == RECORD_TYPE && TYPE_BINFO (elem) == type) + return type; + return get_binfo (elem, type, 0); +} + +tree +reverse_path (path) + tree path; +{ + register tree prev = 0, tmp, next; + for (tmp = path; tmp; tmp = next) + { + next = BINFO_INHERITANCE_CHAIN (tmp); + BINFO_INHERITANCE_CHAIN (tmp) = prev; + prev = tmp; + } + return prev; +} + +tree +virtual_member (elem, list) + tree elem; + tree list; +{ + tree t; + tree rval, nval; + + for (t = list; t; t = TREE_CHAIN (t)) + if (elem == BINFO_TYPE (t)) + return t; + rval = 0; + for (t = list; t; t = TREE_CHAIN (t)) + { + tree binfos = BINFO_BASETYPES (t); + int i; + + if (binfos != NULL_TREE) + for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) + { + nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i))); + if (nval) + { + if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval)) + my_friendly_abort (104); + rval = nval; + } + } + } + return rval; +} + +/* Return the offset (as an INTEGER_CST) for ELEM in LIST. + INITIAL_OFFSET is the value to add to the offset that ELEM's + binfo entry in LIST provides. + + Returns NULL if ELEM does not have an binfo value in LIST. */ + +tree +virtual_offset (elem, list, initial_offset) + tree elem; + tree list; + tree initial_offset; +{ + tree vb, offset; + tree rval, nval; + + for (vb = list; vb; vb = TREE_CHAIN (vb)) + if (elem == BINFO_TYPE (vb)) + return size_binop (PLUS_EXPR, initial_offset, BINFO_OFFSET (vb)); + rval = 0; + for (vb = list; vb; vb = TREE_CHAIN (vb)) + { + tree binfos = BINFO_BASETYPES (vb); + int i; + + if (binfos == NULL_TREE) + continue; + + for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) + { + nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i))); + if (nval) + { + if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval)) + my_friendly_abort (105); + offset = BINFO_OFFSET (vb); + rval = nval; + } + } + } + if (rval == NULL_TREE) + return rval; + return size_binop (PLUS_EXPR, offset, BINFO_OFFSET (rval)); +} + +void +debug_binfo (elem) + tree elem; +{ + int i; + tree virtuals; + + fprintf (stderr, "type \"%s\"; offset = %d\n", + TYPE_NAME_STRING (BINFO_TYPE (elem)), + TREE_INT_CST_LOW (BINFO_OFFSET (elem))); + fprintf (stderr, "vtable type:\n"); + debug_tree (BINFO_TYPE (elem)); + if (BINFO_VTABLE (elem)) + fprintf (stderr, "vtable decl \"%s\"\n", IDENTIFIER_POINTER (DECL_NAME (BINFO_VTABLE (elem)))); + else + fprintf (stderr, "no vtable decl yet\n"); + fprintf (stderr, "virtuals:\n"); + virtuals = BINFO_VIRTUALS (elem); + if (virtuals != 0) + { + virtuals = TREE_CHAIN (virtuals); + if (flag_dossier) + virtuals = TREE_CHAIN (virtuals); + } + i = 1; + while (virtuals) + { + tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0); + fprintf (stderr, "%s [%d =? %d]\n", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)), + i, TREE_INT_CST_LOW (DECL_VINDEX (fndecl))); + virtuals = TREE_CHAIN (virtuals); + i += 1; + } +} + +/* Return the length of a chain of nodes chained through DECL_CHAIN. + We expect a null pointer to mark the end of the chain. + This is the Lisp primitive `length'. */ + +int +decl_list_length (t) + tree t; +{ + register tree tail; + register int len = 0; + + my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL + || TREE_CODE (t) == TEMPLATE_DECL, 300); + for (tail = t; tail; tail = DECL_CHAIN (tail)) + len++; + + return len; +} + +int +count_functions (t) + tree t; +{ + if (TREE_CODE (t) == FUNCTION_DECL) + return 1; + else if (TREE_CODE (t) == TREE_LIST) + return decl_list_length (TREE_VALUE (t)); + + my_friendly_abort (359); + return 0; +} + +/* Like value_member, but for DECL_CHAINs. */ +tree +decl_value_member (elem, list) + tree elem, list; +{ + while (list) + { + if (elem == list) + return list; + list = DECL_CHAIN (list); + } + return NULL_TREE; +} + +int +is_overloaded_fn (x) + tree x; +{ + if (TREE_CODE (x) == FUNCTION_DECL) + return 1; + + if (TREE_CODE (x) == TREE_LIST + && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL + || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL)) + return 1; + + return 0; +} + +int +really_overloaded_fn (x) + tree x; +{ + if (TREE_CODE (x) == TREE_LIST + && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL + || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL)) + return 1; + + return 0; +} + +tree +get_first_fn (from) + tree from; +{ + if (TREE_CODE (from) == FUNCTION_DECL) + return from; + + my_friendly_assert (TREE_CODE (from) == TREE_LIST, 9); + + return TREE_VALUE (from); +} + +tree +fnaddr_from_vtable_entry (entry) + tree entry; +{ + if (flag_vtable_thunks) + { + tree func = entry; + if (TREE_CODE (func) == ADDR_EXPR) + func = TREE_OPERAND (func, 0); + if (TREE_CODE (func) == THUNK_DECL) + return DECL_INITIAL (func); + else + return entry; + } + else + return TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))); +} + +void +set_fnaddr_from_vtable_entry (entry, value) + tree entry, value; +{ + if (flag_vtable_thunks) + abort (); + else + TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))) = value; +} + +tree +function_arg_chain (t) + tree t; +{ + return TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (t))); +} + +int +promotes_to_aggr_type (t, code) + tree t; + enum tree_code code; +{ + if (TREE_CODE (t) == code) + t = TREE_TYPE (t); + return IS_AGGR_TYPE (t); +} + +int +is_aggr_type_2 (t1, t2) + tree t1, t2; +{ + if (TREE_CODE (t1) != TREE_CODE (t2)) + return 0; + return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2); +} + +/* Give message using types TYPE1 and TYPE2 as arguments. + PFN is the function which will print the message; + S is the format string for PFN to use. */ +void +message_2_types (pfn, s, type1, type2) + void (*pfn) (); + char *s; + tree type1, type2; +{ + tree name1 = TYPE_NAME (type1); + tree name2 = TYPE_NAME (type2); + if (TREE_CODE (name1) == TYPE_DECL) + name1 = DECL_NAME (name1); + if (TREE_CODE (name2) == TYPE_DECL) + name2 = DECL_NAME (name2); + (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2)); +} + +#define PRINT_RING_SIZE 4 + +char * +lang_printable_name (decl) + tree decl; +{ + static tree decl_ring[PRINT_RING_SIZE]; + static char *print_ring[PRINT_RING_SIZE]; + static int ring_counter; + int i; + + /* Only cache functions. */ + if (TREE_CODE (decl) != FUNCTION_DECL + || DECL_LANG_SPECIFIC (decl) == 0) + return decl_as_string (decl, 1); + + /* See if this print name is lying around. */ + for (i = 0; i < PRINT_RING_SIZE; i++) + if (decl_ring[i] == decl) + /* yes, so return it. */ + return print_ring[i]; + + if (++ring_counter == PRINT_RING_SIZE) + ring_counter = 0; + + if (current_function_decl != NULL_TREE) + { + if (decl_ring[ring_counter] == current_function_decl) + ring_counter += 1; + if (ring_counter == PRINT_RING_SIZE) + ring_counter = 0; + if (decl_ring[ring_counter] == current_function_decl) + my_friendly_abort (106); + } + + if (print_ring[ring_counter]) + free (print_ring[ring_counter]); + + { + int print_ret_type_p + = (!DECL_CONSTRUCTOR_P (decl) + && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl))); + + char *name = (char *)decl_as_string (decl, print_ret_type_p); + print_ring[ring_counter] = (char *)malloc (strlen (name) + 1); + strcpy (print_ring[ring_counter], name); + decl_ring[ring_counter] = decl; + } + return print_ring[ring_counter]; +} + +/* Comparison function for sorting identifiers in RAISES lists. + Note that because IDENTIFIER_NODEs are unique, we can sort + them by address, saving an indirection. */ +static int +id_cmp (p1, p2) + tree *p1, *p2; +{ + return (HOST_WIDE_INT)TREE_VALUE (*p1) - (HOST_WIDE_INT)TREE_VALUE (*p2); +} + +/* Build the FUNCTION_TYPE or METHOD_TYPE which may raise exceptions + listed in RAISES. */ +tree +build_exception_variant (ctype, type, raises) + tree ctype, type; + tree raises; +{ + int i; + tree v = TYPE_MAIN_VARIANT (type); + tree t, t2, cname; + tree *a = (tree *)alloca ((list_length (raises)+1) * sizeof (tree)); + int constp = TYPE_READONLY (type); + int volatilep = TYPE_VOLATILE (type); + + for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v)) + { + if (TYPE_READONLY (v) != constp + || TYPE_VOLATILE (v) != volatilep) + continue; + + t = raises; + t2 = TYPE_RAISES_EXCEPTIONS (v); + while (t && t2) + { + if (TREE_TYPE (t) == TREE_TYPE (t2)) + { + t = TREE_CHAIN (t); + t2 = TREE_CHAIN (t2); + } + else break; + } + if (t || t2) + continue; + /* List of exceptions raised matches previously found list. + + @@ Nice to free up storage used in consing up the + @@ list of exceptions raised. */ + return v; + } + + /* Need to build a new variant. */ + v = copy_node (type); + TYPE_NEXT_VARIANT (v) = TYPE_NEXT_VARIANT (type); + TYPE_NEXT_VARIANT (type) = v; + if (raises && ! TREE_PERMANENT (raises)) + { + push_obstacks_nochange (); + end_temporary_allocation (); + raises = copy_list (raises); + pop_obstacks (); + } + TYPE_RAISES_EXCEPTIONS (v) = raises; + return v; +} + +/* Subroutine of copy_to_permanent + + Assuming T is a node build bottom-up, make it all exist on + permanent obstack, if it is not permanent already. */ +static tree +make_deep_copy (t) + tree t; +{ + enum tree_code code; + + if (t == NULL_TREE || TREE_PERMANENT (t)) + return t; + + switch (code = TREE_CODE (t)) + { + case ERROR_MARK: + return error_mark_node; + + case VAR_DECL: + case FUNCTION_DECL: + case CONST_DECL: + break; + + case PARM_DECL: + { + tree chain = TREE_CHAIN (t); + t = copy_node (t); + TREE_CHAIN (t) = make_deep_copy (chain); + TREE_TYPE (t) = make_deep_copy (TREE_TYPE (t)); + DECL_INITIAL (t) = make_deep_copy (DECL_INITIAL (t)); + DECL_SIZE (t) = make_deep_copy (DECL_SIZE (t)); + return t; + } + + case TREE_LIST: + { + tree chain = TREE_CHAIN (t); + t = copy_node (t); + TREE_PURPOSE (t) = make_deep_copy (TREE_PURPOSE (t)); + TREE_VALUE (t) = make_deep_copy (TREE_VALUE (t)); + TREE_CHAIN (t) = make_deep_copy (chain); + return t; + } + + case TREE_VEC: + { + int len = TREE_VEC_LENGTH (t); + + t = copy_node (t); + while (len--) + TREE_VEC_ELT (t, len) = make_deep_copy (TREE_VEC_ELT (t, len)); + return t; + } + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + return copy_node (t); + + case COND_EXPR: + case TARGET_EXPR: + case NEW_EXPR: + t = copy_node (t); + TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); + TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1)); + TREE_OPERAND (t, 2) = make_deep_copy (TREE_OPERAND (t, 2)); + return t; + + case SAVE_EXPR: + t = copy_node (t); + TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); + return t; + + case MODIFY_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case BIT_ANDTC_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case COMPOUND_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case CALL_EXPR: + t = copy_node (t); + TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); + TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1)); + return t; + + case CONVERT_EXPR: + case ADDR_EXPR: + case INDIRECT_REF: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case NOP_EXPR: + case COMPONENT_REF: + t = copy_node (t); + TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0)); + return t; + + /* This list is incomplete, but should suffice for now. + It is very important that `sorry' does not call + `report_error_function'. That could cause an infinite loop. */ + default: + sorry ("initializer contains unrecognized tree code"); + return error_mark_node; + + } + my_friendly_abort (107); + /* NOTREACHED */ + return NULL_TREE; +} + +/* Assuming T is a node built bottom-up, make it all exist on + permanent obstack, if it is not permanent already. */ +tree +copy_to_permanent (t) + tree t; +{ + register struct obstack *ambient_obstack = current_obstack; + register struct obstack *ambient_saveable_obstack = saveable_obstack; + + if (t == NULL_TREE || TREE_PERMANENT (t)) + return t; + + saveable_obstack = &permanent_obstack; + current_obstack = saveable_obstack; + + t = make_deep_copy (t); + + current_obstack = ambient_obstack; + saveable_obstack = ambient_saveable_obstack; + + return t; +} + +void +print_lang_statistics () +{ + extern struct obstack maybepermanent_obstack; + print_obstack_statistics ("class_obstack", &class_obstack); + print_obstack_statistics ("permanent_obstack", &permanent_obstack); + print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack); + print_search_statistics (); + print_class_statistics (); +} + +/* This is used by the `assert' macro. It is provided in libgcc.a, + which `cc' doesn't know how to link. Note that the C++ front-end + no longer actually uses the `assert' macro (instead, it calls + my_friendly_assert). But all of the back-end files still need this. */ +void +__eprintf (string, expression, line, filename) +#ifdef __STDC__ + const char *string; + const char *expression; + unsigned line; + const char *filename; +#else + char *string; + char *expression; + unsigned line; + char *filename; +#endif +{ + fprintf (stderr, string, expression, line, filename); + fflush (stderr); + abort (); +} + +/* Return, as an INTEGER_CST node, the number of elements for + TYPE (which is an ARRAY_TYPE). This counts only elements of the top array. */ + +tree +array_type_nelts_top (type) + tree type; +{ + return fold (build (PLUS_EXPR, integer_type_node, + array_type_nelts (type), + integer_one_node)); +} + +/* Return, as an INTEGER_CST node, the number of elements for + TYPE (which is an ARRAY_TYPE). This one is a recursive count of all + ARRAY_TYPEs that are clumped together. */ + +tree +array_type_nelts_total (type) + tree type; +{ + tree sz = array_type_nelts_top (type); + type = TREE_TYPE (type); + while (TREE_CODE (type) == ARRAY_TYPE) + { + tree n = array_type_nelts_top (type); + sz = fold (build (MULT_EXPR, integer_type_node, sz, n)); + type = TREE_TYPE (type); + } + return sz; +} |