#include "config.h"
#include "system.h"
#include "obstack.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#include "rtl.h"
#include "toplev.h"
static tree bot_manip PROTO((tree));
static tree perm_manip PROTO((tree));
static tree build_cplus_array_type_1 PROTO((tree, tree));
static void list_hash_add PROTO((int, tree));
static int list_hash PROTO((tree, tree, tree));
static tree list_hash_lookup PROTO((int, tree, tree, tree));
static void propagate_binfo_offsets PROTO((tree, tree));
static int avoid_overlap PROTO((tree, tree));
static int lvalue_p_1 PROTO((tree, int));
static int equal_functions PROTO((tree, tree));
static tree no_linkage_helper PROTO((tree));
static tree build_srcloc PROTO((char *, int));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
static int
lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
tree ref;
int treat_class_rvalues_as_lvalues;
{
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
return 1;
if (ref == current_class_ptr && flag_this_is_variable <= 0)
return 0;
switch (TREE_CODE (ref))
{
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case COMPONENT_REF:
case SAVE_EXPR:
case UNSAVE_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
case NOP_EXPR:
return lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues);
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:
if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
return 1;
break;
case SCOPE_REF:
my_friendly_abort (103);
case OFFSET_REF:
if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
return 1;
return (lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues)
&& lvalue_p_1 (TREE_OPERAND (ref, 1),
treat_class_rvalues_as_lvalues));
break;
case COND_EXPR:
return (lvalue_p_1 (TREE_OPERAND (ref, 1),
treat_class_rvalues_as_lvalues)
&& lvalue_p_1 (TREE_OPERAND (ref, 2),
treat_class_rvalues_as_lvalues));
case MODIFY_EXPR:
return 1;
case COMPOUND_EXPR:
return lvalue_p_1 (TREE_OPERAND (ref, 1),
treat_class_rvalues_as_lvalues);
case MAX_EXPR:
case MIN_EXPR:
return (lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues)
&& lvalue_p_1 (TREE_OPERAND (ref, 1),
treat_class_rvalues_as_lvalues));
case TARGET_EXPR:
return treat_class_rvalues_as_lvalues;
case CALL_EXPR:
return (treat_class_rvalues_as_lvalues
&& IS_AGGR_TYPE (TREE_TYPE (ref)));
case FUNCTION_DECL:
return !DECL_NONSTATIC_MEMBER_FUNCTION_P (ref);
default:
break;
}
return 0;
}
int
real_lvalue_p (ref)
tree ref;
{
return lvalue_p_1 (ref, 0);
}
int
lvalue_p (ref)
tree ref;
{
return lvalue_p_1 (ref, 1);
}
int
lvalue_or_else (ref, string)
tree ref;
const char *string;
{
int win = lvalue_p (ref);
if (! win)
error ("non-lvalue in %s", string);
return win;
}
tree
build_cplus_new (type, init)
tree type;
tree init;
{
tree slot;
tree rval;
if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
return convert (type, init);
slot = build (VAR_DECL, type);
DECL_ARTIFICIAL (slot) = 1;
layout_decl (slot, 0);
rval = build (AGGR_INIT_EXPR, type,
TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
TREE_SIDE_EFFECTS (rval) = 1;
rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (rval) = 1;
return rval;
}
tree
get_target_expr (init)
tree init;
{
tree slot;
tree rval;
slot = build (VAR_DECL, TREE_TYPE (init));
DECL_ARTIFICIAL (slot) = 1;
layout_decl (slot, 0);
rval = build (TARGET_EXPR, TREE_TYPE (init), slot, init,
NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (rval) = 1;
return rval;
}
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);
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));
break;
}
else
tmp = TREE_OPERAND (tmp, 0);
}
return exp;
}
tree
break_out_calls (exp)
tree exp;
{
register tree t1, t2 = NULL_TREE;
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);
if (code == SAVE_EXPR)
return exp;
switch (TREE_CODE_CLASS (code))
{
default:
abort ();
case 'c':
case 't':
case 'x':
return exp;
case 'd':
#if 0
t1 = break_out_calls (DECL_INITIAL (exp));
if (t1 != DECL_INITIAL (exp))
{
exp = copy_node (exp);
DECL_INITIAL (exp) = t1;
}
#endif
return exp;
case 'b':
{
abort ();
}
return exp;
case 'e':
case 'r':
case 's':
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 '<':
case '2':
t2 = break_out_calls (TREE_OPERAND (exp, 1));
if (t2 != TREE_OPERAND (exp, 1))
changed = 1;
case '1':
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;
extern struct obstack *expression_obstack;
#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
tree
build_cplus_method_type (basetype, rettype, argtypes)
tree basetype, rettype, argtypes;
{
register tree t;
tree ptype;
int hashcode;
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 (basetype);
else
ptype = build_pointer_type (basetype);
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
TREE_SIDE_EFFECTS (argtypes) = 1;
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;
}
static tree
build_cplus_array_type_1 (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;
if (TREE_PERMANENT (elt_type)
&& (index_type == 0 || TREE_PERMANENT (index_type)))
{
current_obstack = &permanent_obstack;
saveable_obstack = &permanent_obstack;
}
if (processing_template_decl
|| uses_template_parms (elt_type)
|| uses_template_parms (index_type))
{
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
}
else
t = build_array_type (elt_type, index_type);
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;
}
tree
build_cplus_array_type (elt_type, index_type)
tree elt_type;
tree index_type;
{
tree t;
int type_quals = CP_TYPE_QUALS (elt_type);
elt_type = TYPE_MAIN_VARIANT (elt_type);
t = build_cplus_array_type_1 (elt_type, index_type);
if (type_quals != TYPE_UNQUALIFIED)
t = cp_build_qualified_type (t, type_quals);
return t;
}
tree
cp_build_qualified_type (type, type_quals)
tree type;
int type_quals;
{
if (type == error_mark_node)
return type;
if ((type_quals & TYPE_QUAL_RESTRICT)
&& (!POINTER_TYPE_P (type)
|| TYPE_PTRMEM_P (type)
|| TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
{
cp_error ("`%T' cannot be `restrict'-qualified", type);
type_quals &= ~TYPE_QUAL_RESTRICT;
}
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree real_main_variant = TYPE_MAIN_VARIANT (type);
push_obstacks (TYPE_OBSTACK (real_main_variant),
TYPE_OBSTACK (real_main_variant));
type = build_cplus_array_type_1 (cp_build_qualified_type
(TREE_TYPE (type), type_quals),
TYPE_DOMAIN (type));
if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
{
type = copy_node (type);
TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
}
TYPE_MAIN_VARIANT (type) = real_main_variant;
pop_obstacks ();
return type;
}
return build_qualified_type (type, type_quals);
}
tree
canonical_type_variant (t)
tree t;
{
return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), CP_TYPE_QUALS (t));
}
static 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; )
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (TREE_VIA_VIRTUAL (base_binfo))
i += 1;
else
{
int j;
tree delta = NULL_TREE;
for (j = i+1; j < n_baselinks; j++)
if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
{
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
propagate_binfo_offsets (base_binfo, offset);
i = j;
if (i < n_baselinks)
offset = size_binop (PLUS_EXPR, offset, delta);
}
}
}
void
unshare_base_binfos (binfo)
tree binfo;
{
tree binfos = BINFO_BASETYPES (binfo);
tree new_binfo;
int j;
if (binfos == NULL_TREE)
return;
for (j = TREE_VEC_LENGTH (binfos)-1;
j >= 0; j--)
{
tree base_binfo = TREE_VEC_ELT (binfos, j);
new_binfo = TREE_VEC_ELT (binfos, j)
= make_binfo (BINFO_OFFSET (base_binfo),
base_binfo,
BINFO_VTABLE (base_binfo),
BINFO_VIRTUALS (base_binfo));
TREE_VIA_PUBLIC (new_binfo) = TREE_VIA_PUBLIC (base_binfo);
TREE_VIA_PROTECTED (new_binfo) = TREE_VIA_PROTECTED (base_binfo);
TREE_VIA_VIRTUAL (new_binfo) = TREE_VIA_VIRTUAL (base_binfo);
BINFO_INHERITANCE_CHAIN (new_binfo) = binfo;
unshare_base_binfos (new_binfo);
}
}
int
layout_basetypes (rec, max)
tree rec;
int max;
{
tree binfos = TYPE_BINFO_BASETYPES (rec);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree vbase_types;
unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
unsigned int desired_align;
register unsigned int const_size = 0;
unsigned int nonvirtual_const_size;
#ifdef STRUCTURE_SIZE_BOUNDARY
if (! TYPE_PACKED (rec))
record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
#endif
vbase_types = CLASSTYPE_VBASECLASSES (rec);
my_friendly_assert (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST, 19970302);
const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec));
nonvirtual_const_size = const_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
{
const_size = CEIL (const_size, desired_align) * desired_align;
offset = size_int (CEIL (const_size, BITS_PER_UNIT));
}
if (CLASSTYPE_VSIZE (basetype) > max)
max = CLASSTYPE_VSIZE (basetype);
BINFO_OFFSET (vbase_types) = offset;
const_size += MAX (BITS_PER_UNIT,
TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
vbase_types = TREE_CHAIN (vbase_types);
}
if (const_size)
{
const_size = CEIL (const_size, record_align) * record_align;
}
TYPE_ALIGN (rec) = record_align;
if (const_size != nonvirtual_const_size)
{
TYPE_SIZE (rec) = size_int (const_size);
TYPE_SIZE_UNIT (rec) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (rec),
size_int (BITS_PER_UNIT));
}
for (i = 0; i < n_baseclasses; i++)
{
register tree base_binfo = TREE_VEC_ELT (binfos, i);
register tree basetype = BINFO_TYPE (base_binfo);
tree field = TYPE_FIELDS (rec);
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
my_friendly_assert (TREE_TYPE (field) == basetype, 23897);
if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
basetype, rec);
BINFO_OFFSET (base_binfo)
= size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)),
BITS_PER_UNIT));
propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
TYPE_FIELDS (rec) = TREE_CHAIN (field);
}
for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
vbase_types = TREE_CHAIN (vbase_types))
{
BINFO_INHERITANCE_CHAIN (vbase_types) = TYPE_BINFO (rec);
unshare_base_binfos (vbase_types);
propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
if (extra_warnings)
{
tree basetype = BINFO_TYPE (vbase_types);
if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
basetype, rec);
}
}
return max;
}
static int
avoid_overlap (decl, newdecl)
tree decl, newdecl;
{
tree field;
if (newdecl == NULL_TREE
|| ! types_overlap_p (TREE_TYPE (decl), TREE_TYPE (newdecl)))
return 0;
for (field = decl; TREE_CHAIN (field) && TREE_CHAIN (field) != newdecl;
field = TREE_CHAIN (field))
;
DECL_SIZE (field) = integer_one_node;
return 1;
}
tree
build_base_fields (rec)
tree rec;
{
tree base_decls = NULL_TREE;
tree binfos = TYPE_BINFO_BASETYPES (rec);
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree decl, nextdecl;
int i, saw_empty = 0;
unsigned int base_align = 0;
for (i = 0; i < n_baseclasses; ++i)
{
register tree base_binfo = TREE_VEC_ELT (binfos, i);
register tree basetype = BINFO_TYPE (base_binfo);
if (TYPE_SIZE (basetype) == 0)
continue;
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, basetype);
DECL_ARTIFICIAL (decl) = 1;
DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = rec;
DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
TREE_CHAIN (decl) = base_decls;
base_decls = decl;
if (! flag_new_abi)
{
base_align = MAX (base_align, DECL_ALIGN (decl));
DECL_SIZE (decl)
= size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
(int) base_align));
}
else if (DECL_SIZE (decl) == integer_zero_node)
saw_empty = 1;
}
base_decls = nreverse (base_decls);
if (flag_new_abi && saw_empty)
for (decl = base_decls; decl; decl = TREE_CHAIN (decl))
{
if (DECL_SIZE (decl) == integer_zero_node)
{
for (nextdecl = TREE_CHAIN (decl); nextdecl;
nextdecl = TREE_CHAIN (nextdecl))
{
if (avoid_overlap (decl, nextdecl)
|| DECL_SIZE (nextdecl) != integer_zero_node)
goto nextbase;
}
for (nextdecl = TYPE_FIELDS (rec);
nextdecl && TREE_CODE (nextdecl) != FIELD_DECL;
nextdecl = TREE_CHAIN (nextdecl))
;
avoid_overlap (decl, nextdecl);
}
nextbase:;
}
return base_decls;
}
tree
build_vbase_pointer_fields (rec)
tree rec;
{
tree vbase_decls = NULL_TREE;
tree binfos = TYPE_BINFO_BASETYPES (rec);
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree decl;
int i;
for (i = 0; i < n_baseclasses; i++)
{
register tree base_binfo = TREE_VEC_ELT (binfos, i);
register tree basetype = BINFO_TYPE (base_binfo);
if (TYPE_SIZE (basetype) == 0)
continue;
if (TREE_VIA_VIRTUAL (base_binfo))
{
int j;
const char *name;
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;
}
FORMAT_VBASE_NAME (name, basetype);
decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
build_pointer_type (basetype));
DECL_ASSEMBLER_NAME (decl) = get_identifier (VTABLE_BASE);
DECL_VIRTUAL_P (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_FIELD_CONTEXT (decl) = rec;
DECL_CLASS_CONTEXT (decl) = rec;
DECL_FCONTEXT (decl) = basetype;
DECL_SAVED_INSNS (decl) = NULL_RTX;
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;
got_it:
;
}
}
return vbase_decls;
}
struct list_hash
{
struct list_hash *next;
int hashcode;
tree list;
};
#define TYPE_HASH_SIZE 59
static struct list_hash *list_hash_table[TYPE_HASH_SIZE];
static int
list_hash (purpose, value, chain)
tree purpose, value, chain;
{
register int hashcode = 0;
if (chain)
hashcode += TYPE_HASH (chain);
if (value)
hashcode += TYPE_HASH (value);
else
hashcode += 1007;
if (purpose)
hashcode += TYPE_HASH (purpose);
else
hashcode += 1009;
return hashcode;
}
static tree
list_hash_lookup (hashcode, purpose, value, chain)
int hashcode;
tree purpose, value, chain;
{
register struct list_hash *h;
for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& TREE_PURPOSE (h->list) == purpose
&& TREE_VALUE (h->list) == value
&& TREE_CHAIN (h->list) == chain)
return h->list;
return 0;
}
static 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;
}
static int debug_no_list_hash = 0;
tree
hash_tree_cons (purpose, value, chain)
tree purpose, value, chain;
{
struct obstack *ambient_obstack = current_obstack;
tree t;
int hashcode = 0;
if (! debug_no_list_hash)
{
hashcode = list_hash (purpose, value, chain);
t = list_hash_lookup (hashcode, purpose, value, chain);
if (t)
return t;
}
current_obstack = &class_obstack;
t = tree_cons (purpose, value, chain);
if (! debug_no_list_hash)
list_hash_add (hashcode, t);
current_obstack = ambient_obstack;
return t;
}
tree
hash_tree_chain (value, chain)
tree value, chain;
{
return hash_tree_cons (NULL_TREE, value, chain);
}
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));
}
tree
make_binfo (offset, binfo, vtable, virtuals)
tree offset, binfo;
tree vtable, virtuals;
{
tree new_binfo = make_tree_vec (7);
tree type;
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else
{
type = binfo;
binfo = CLASS_TYPE_P (type) ? TYPE_BINFO (binfo) : NULL_TREE;
}
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
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 = NULL_TREE, cur;
push_expression_obstack ();
for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
{
tree r = copy_node (cur);
BINFO_INHERITANCE_CHAIN (r) = prev;
prev = r;
}
pop_obstacks ();
return prev;
}
void
debug_binfo (elem)
tree elem;
{
unsigned HOST_WIDE_INT n;
tree virtuals;
fprintf (stderr, "type \"%s\"; offset = %ld\n",
TYPE_NAME_STRING (BINFO_TYPE (elem)),
(long) 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);
n = skip_rtti_stuff (&virtuals, BINFO_TYPE (elem));
while (virtuals)
{
tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
fprintf (stderr, "%s [%ld =? %ld]\n",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
(long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
tree
binding_init (node)
struct tree_binding* node;
{
static struct tree_binding* source;
if (!source)
{
extern struct obstack permanent_obstack;
push_obstacks (&permanent_obstack, &permanent_obstack);
source = (struct tree_binding*)make_node (CPLUS_BINDING);
pop_obstacks ();
}
*node = *source;
TREE_PERMANENT ((tree)node) = 0;
return (tree)node;
}
int
count_functions (t)
tree t;
{
int i;
if (TREE_CODE (t) == FUNCTION_DECL)
return 1;
else if (TREE_CODE (t) == OVERLOAD)
{
for (i=0; t; t = OVL_CHAIN (t))
i++;
return i;
}
my_friendly_abort (359);
return 0;
}
int
is_overloaded_fn (x)
tree x;
{
if (TREE_CODE (x) == OFFSET_REF)
x = TREE_OPERAND (x, 1);
if (BASELINK_P (x))
x = TREE_VALUE (x);
return (TREE_CODE (x) == FUNCTION_DECL
|| TREE_CODE (x) == TEMPLATE_ID_EXPR
|| DECL_FUNCTION_TEMPLATE_P (x)
|| TREE_CODE (x) == OVERLOAD);
}
int
really_overloaded_fn (x)
tree x;
{
if (TREE_CODE (x) == OFFSET_REF)
x = TREE_OPERAND (x, 1);
if (BASELINK_P (x))
x = TREE_VALUE (x);
return (TREE_CODE (x) == OVERLOAD
&& (TREE_CHAIN (x) != NULL_TREE
|| DECL_FUNCTION_TEMPLATE_P (OVL_FUNCTION (x))));
}
tree
get_first_fn (from)
tree from;
{
my_friendly_assert (is_overloaded_fn (from), 9);
if (BASELINK_P (from))
from = TREE_VALUE (from);
return OVL_CURRENT (from);
}
int
bound_pmf_p (t)
tree t;
{
return (TREE_CODE (t) == OFFSET_REF
&& TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (t, 1))));
}
tree
ovl_cons (decl, chain)
tree decl;
tree chain;
{
tree result = make_node (OVERLOAD);
TREE_TYPE (result) = unknown_type_node;
OVL_FUNCTION (result) = decl;
TREE_CHAIN (result) = chain;
return result;
}
tree
scratch_ovl_cons (value, chain)
tree value, chain;
{
register tree node;
register struct obstack *ambient_obstack = current_obstack;
extern struct obstack *expression_obstack;
current_obstack = expression_obstack;
node = ovl_cons (value, chain);
current_obstack = ambient_obstack;
return node;
}
tree
build_overload (decl, chain)
tree decl;
tree chain;
{
if (! chain && TREE_CODE (decl) != TEMPLATE_DECL)
return decl;
if (chain && TREE_CODE (chain) != OVERLOAD)
chain = ovl_cons (chain, NULL_TREE);
return ovl_cons (decl, chain);
}
static int
equal_functions (fn1, fn2)
tree fn1;
tree fn2;
{
if (!TREE_PERMANENT (fn1) || !TREE_PERMANENT (fn2))
return decls_match (fn1, fn2);
return fn1 == fn2;
}
int
ovl_member (fn, ovl)
tree fn;
tree ovl;
{
if (ovl == NULL_TREE)
return 0;
if (TREE_CODE (ovl) != OVERLOAD)
return equal_functions (ovl, fn);
for (; ovl; ovl = OVL_CHAIN (ovl))
if (equal_functions (OVL_FUNCTION (ovl), fn))
return 1;
return 0;
}
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);
}
#define PRINT_RING_SIZE 4
char *
lang_printable_name (decl, v)
tree decl;
int v;
{
static tree decl_ring[PRINT_RING_SIZE];
static char *print_ring[PRINT_RING_SIZE];
static int ring_counter;
int i;
if (v < 2
|| TREE_CODE (decl) != FUNCTION_DECL
|| DECL_LANG_SPECIFIC (decl) == 0)
return lang_decl_name (decl, v);
for (i = 0; i < PRINT_RING_SIZE; i++)
if (decl_ring[i] == decl)
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]);
print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v));
decl_ring[ring_counter] = decl;
return print_ring[ring_counter];
}
tree
build_exception_variant (type, raises)
tree type;
tree raises;
{
tree v = TYPE_MAIN_VARIANT (type);
int type_quals = TYPE_QUALS (type);
for (; v; v = TYPE_NEXT_VARIANT (v))
{
tree t;
tree u;
if (TYPE_QUALS (v) != type_quals)
continue;
for (t = TYPE_RAISES_EXCEPTIONS (v), u = raises;
t != NULL_TREE && u != NULL_TREE;
t = TREE_CHAIN (t), u = TREE_CHAIN (u))
if (((TREE_VALUE (t) != NULL_TREE)
!= (TREE_VALUE (u) != NULL_TREE))
|| !same_type_p (TREE_VALUE (t), TREE_VALUE (u)))
break;
if (!t && !u)
return v;
}
v = build_type_copy (type);
if (raises && ! TREE_PERMANENT (raises))
raises = copy_to_permanent (raises);
TYPE_RAISES_EXCEPTIONS (v) = raises;
return v;
}
tree
copy_template_template_parm (t)
tree t;
{
tree template = TYPE_NAME (t);
tree t2;
push_obstacks_nochange ();
end_temporary_allocation ();
t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
template = copy_node (template);
copy_lang_decl (template);
pop_obstacks ();
TREE_TYPE (template) = t2;
TYPE_NAME (t2) = template;
TYPE_STUB_DECL (t2) = template;
TYPE_FIELDS (t2) = TYPE_FIELDS (t);
TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)
= TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
return t2;
}
tree
search_tree (t, func)
tree t;
tree (*func) PROTO((tree));
{
#define TRY(ARG) if (tmp=search_tree (ARG, func), tmp != NULL_TREE) return tmp
tree tmp;
if (t == NULL_TREE)
return t;
if (tmp = func (t), tmp != NULL_TREE)
return tmp;
switch (TREE_CODE (t))
{
case ERROR_MARK:
break;
case IDENTIFIER_NODE:
break;
case VAR_DECL:
case FUNCTION_DECL:
case CONST_DECL:
case TEMPLATE_DECL:
case NAMESPACE_DECL:
break;
case TYPE_DECL:
TRY (TREE_TYPE (t));
break;
case PARM_DECL:
TRY (TREE_TYPE (t));
TRY (TREE_CHAIN (t));
break;
case TREE_LIST:
TRY (TREE_PURPOSE (t));
TRY (TREE_VALUE (t));
TRY (TREE_CHAIN (t));
break;
case OVERLOAD:
TRY (OVL_FUNCTION (t));
TRY (OVL_CHAIN (t));
break;
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (t);
t = copy_node (t);
while (len--)
TRY (TREE_VEC_ELT (t, len));
}
break;
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
case DEFAULT_ARG:
break;
case PTRMEM_CST:
TRY (TREE_TYPE (t));
break;
case COND_EXPR:
case TARGET_EXPR:
case AGGR_INIT_EXPR:
case NEW_EXPR:
TRY (TREE_OPERAND (t, 0));
TRY (TREE_OPERAND (t, 1));
TRY (TREE_OPERAND (t, 2));
break;
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 ARRAY_REF:
case SCOPE_REF:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case CALL_EXPR:
TRY (TREE_OPERAND (t, 0));
TRY (TREE_OPERAND (t, 1));
break;
case SAVE_EXPR:
case CONVERT_EXPR:
case ADDR_EXPR:
case INDIRECT_REF:
case NEGATE_EXPR:
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case NOP_EXPR:
case NON_LVALUE_EXPR:
case COMPONENT_REF:
case CLEANUP_POINT_EXPR:
case LOOKUP_EXPR:
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
TRY (TREE_OPERAND (t, 0));
break;
case MODOP_EXPR:
case CAST_EXPR:
case REINTERPRET_CAST_EXPR:
case CONST_CAST_EXPR:
case STATIC_CAST_EXPR:
case DYNAMIC_CAST_EXPR:
case ARROW_EXPR:
case DOTSTAR_EXPR:
case TYPEID_EXPR:
break;
case VECTOR_CST:
TRY (TREE_VECTOR_CST_LOW (t));
TRY (TREE_VECTOR_CST_HIGH (t));
break;
case COMPLEX_CST:
TRY (TREE_REALPART (t));
TRY (TREE_IMAGPART (t));
break;
case CONSTRUCTOR:
TRY (CONSTRUCTOR_ELTS (t));
break;
case TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
case TEMPLATE_TYPE_PARM:
break;
case BIND_EXPR:
break;
case VECTOR_TYPE:
case REAL_TYPE:
case COMPLEX_TYPE:
case VOID_TYPE:
case BOOLEAN_TYPE:
case TYPENAME_TYPE:
case UNION_TYPE:
case ENUMERAL_TYPE:
case TYPEOF_TYPE:
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
TRY (TREE_TYPE (t));
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
TRY (TREE_TYPE (t));
TRY (TYPE_ARG_TYPES (t));
break;
case ARRAY_TYPE:
TRY (TREE_TYPE (t));
TRY (TYPE_DOMAIN (t));
break;
case INTEGER_TYPE:
TRY (TYPE_MAX_VALUE (t));
break;
case OFFSET_TYPE:
TRY (TREE_TYPE (t));
TRY (TYPE_OFFSET_BASETYPE (t));
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
TRY (TYPE_PTRMEMFUNC_FN_TYPE (t));
break;
default:
debug_tree(t);
sorry ("initializer contains unrecognized tree code");
return error_mark_node;
}
return NULL_TREE;
#undef TRY
}
static tree
no_linkage_helper (t)
tree t;
{
if (TYPE_P (t)
&& (IS_AGGR_TYPE (t) || TREE_CODE (t) == ENUMERAL_TYPE)
&& (decl_function_context (TYPE_MAIN_DECL (t))
|| ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))))
return t;
return NULL_TREE;
}
tree
no_linkage_check (t)
tree t;
{
t = search_tree (t, no_linkage_helper);
if (t != error_mark_node)
return t;
return NULL_TREE;
}
tree
mapcar (t, func)
tree t;
tree (*func) PROTO((tree));
{
tree tmp;
if (t == NULL_TREE)
return t;
if (func)
{
tmp = func (t);
if (tmp)
return tmp;
}
switch (TREE_CODE (t))
{
case ERROR_MARK:
return error_mark_node;
case VAR_DECL:
case FUNCTION_DECL:
case CONST_DECL:
if (TREE_READONLY_DECL_P (t))
{
tmp = decl_constant_value (t);
if (tmp != t)
return mapcar (tmp, func);
}
return error_mark_node;
case PARM_DECL:
{
tree chain = TREE_CHAIN (t);
t = copy_node (t);
TREE_CHAIN (t) = mapcar (chain, func);
TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
DECL_INITIAL (t) = mapcar (DECL_INITIAL (t), func);
DECL_SIZE (t) = mapcar (DECL_SIZE (t), func);
return t;
}
case TREE_LIST:
{
tree chain = TREE_CHAIN (t);
t = copy_node (t);
TREE_PURPOSE (t) = mapcar (TREE_PURPOSE (t), func);
TREE_VALUE (t) = mapcar (TREE_VALUE (t), func);
TREE_CHAIN (t) = mapcar (chain, func);
return t;
}
case OVERLOAD:
{
tree chain = OVL_CHAIN (t);
t = copy_node (t);
OVL_FUNCTION (t) = mapcar (OVL_FUNCTION (t), func);
OVL_CHAIN (t) = mapcar (chain, func);
return t;
}
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (t);
t = copy_node (t);
while (len--)
TREE_VEC_ELT (t, len) = mapcar (TREE_VEC_ELT (t, len), func);
return t;
}
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
return copy_node (t);
case PTRMEM_CST:
t = copy_node (t);
TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
PTRMEM_CST_MEMBER (t) = mapcar (PTRMEM_CST_MEMBER (t), func);
return t;
case COND_EXPR:
case TARGET_EXPR:
case AGGR_INIT_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
return t;
case SAVE_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
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 ARRAY_REF:
case SCOPE_REF:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
return t;
case CALL_EXPR:
t = copy_node (t);
TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
if (TREE_OPERAND (t, 2)
&& TREE_CODE (TREE_OPERAND (t, 2)) == TREE_LIST)
TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
else
TREE_OPERAND (t, 2) = NULL_TREE;
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:
case CLEANUP_POINT_EXPR:
case NON_LVALUE_EXPR:
t = copy_node (t);
TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
return t;
case POINTER_TYPE:
tmp = build_pointer_type (mapcar (TREE_TYPE (t), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case REFERENCE_TYPE:
tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case FUNCTION_TYPE:
tmp = build_function_type (mapcar (TREE_TYPE (t), func),
mapcar (TYPE_ARG_TYPES (t), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case ARRAY_TYPE:
tmp = build_cplus_array_type (mapcar (TREE_TYPE (t), func),
mapcar (TYPE_DOMAIN (t), func));
return cp_build_qualified_type (tmp, CP_TYPE_QUALS (t));
case INTEGER_TYPE:
tmp = build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case OFFSET_TYPE:
tmp = build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
mapcar (TREE_TYPE (t), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case METHOD_TYPE:
tmp = build_cplus_method_type
(mapcar (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), func),
mapcar (TREE_TYPE (t), func),
mapcar (TREE_CHAIN (TYPE_ARG_TYPES (t)), func));
return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case COMPLEX_CST:
t = copy_node (t);
TREE_REALPART (t) = mapcar (TREE_REALPART (t), func);
TREE_IMAGPART (t) = mapcar (TREE_REALPART (t), func);
return t;
case CONSTRUCTOR:
t = copy_node (t);
CONSTRUCTOR_ELTS (t) = mapcar (CONSTRUCTOR_ELTS (t), func);
return t;
case TEMPLATE_TEMPLATE_PARM:
return copy_template_template_parm (t);
case BIND_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
TREE_OPERAND (t, 2) = NULL_TREE;
return t;
case NEW_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
return t;
case VECTOR_CST:
t = copy_node (t);
TREE_VECTOR_CST_LOW (t) = mapcar (TREE_VECTOR_CST_LOW (t), func);
TREE_VECTOR_CST_HIGH (t) = mapcar (TREE_VECTOR_CST_HIGH (t), func);
return t;
case LOOKUP_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
return t;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
return build_ptrmemfunc_type
(mapcar (TYPE_PTRMEMFUNC_FN_TYPE (t), func));
default:
sorry ("initializer contains unrecognized tree code");
return error_mark_node;
}
my_friendly_abort (107);
return NULL_TREE;
}
tree
permanent_p (t)
tree t;
{
return TREE_PERMANENT (t) ? t : NULL_TREE;
}
static tree
perm_manip (t)
tree t;
{
if (TREE_PERMANENT (t))
return t;
if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
&& TREE_PUBLIC (t))
{
t = copy_node (t);
DECL_RTL (t) = 0;
make_decl_rtl (t, NULL_PTR, 1);
return t;
}
return NULL_TREE;
}
tree
copy_to_permanent (t)
tree t;
{
if (t == NULL_TREE || TREE_PERMANENT (t))
return t;
push_obstacks_nochange ();
end_temporary_allocation ();
t = mapcar (t, perm_manip);
pop_obstacks ();
return t;
}
#ifdef GATHER_STATISTICS
extern int depth_reached;
#endif
void
print_lang_statistics ()
{
extern struct obstack decl_obstack;
print_obstack_statistics ("class_obstack", &class_obstack);
print_obstack_statistics ("decl_obstack", &decl_obstack);
print_search_statistics ();
print_class_statistics ();
#ifdef GATHER_STATISTICS
fprintf (stderr, "maximum template instantiation depth reached: %d\n",
depth_reached);
#endif
}
void
__eprintf (string, expression, line, filename)
const char *string;
const char *expression;
unsigned line;
const char *filename;
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
abort ();
}
tree
array_type_nelts_top (type)
tree type;
{
return fold (build (PLUS_EXPR, sizetype,
array_type_nelts (type),
integer_one_node));
}
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, sizetype, sz, n));
type = TREE_TYPE (type);
}
return sz;
}
static
tree
bot_manip (t)
tree t;
{
if (TREE_CODE (t) != TREE_LIST && ! TREE_SIDE_EFFECTS (t))
return t;
else if (TREE_CODE (t) == TARGET_EXPR)
{
if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR)
{
mark_used (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 1), 0), 0));
return build_cplus_new
(TREE_TYPE (t), break_out_target_exprs (TREE_OPERAND (t, 1)));
}
t = copy_node (t);
TREE_OPERAND (t, 0) = build (VAR_DECL, TREE_TYPE (t));
layout_decl (TREE_OPERAND (t, 0), 0);
return t;
}
else if (TREE_CODE (t) == CALL_EXPR)
mark_used (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
return NULL_TREE;
}
tree
break_out_target_exprs (t)
tree t;
{
return mapcar (t, bot_manip);
}
tree
build_min_nt VPROTO((enum tree_code code, ...))
{
#ifndef __STDC__
enum tree_code code;
#endif
register struct obstack *ambient_obstack = expression_obstack;
va_list p;
register tree t;
register int length;
register int i;
VA_START (p, code);
#ifndef __STDC__
code = va_arg (p, enum tree_code);
#endif
expression_obstack = &permanent_obstack;
t = make_node (code);
length = tree_code_length[(int) code];
TREE_COMPLEXITY (t) = lineno;
for (i = 0; i < length; i++)
{
tree x = va_arg (p, tree);
TREE_OPERAND (t, i) = copy_to_permanent (x);
}
va_end (p);
expression_obstack = ambient_obstack;
return t;
}
tree
build_min VPROTO((enum tree_code code, tree tt, ...))
{
#ifndef __STDC__
enum tree_code code;
tree tt;
#endif
register struct obstack *ambient_obstack = expression_obstack;
va_list p;
register tree t;
register int length;
register int i;
VA_START (p, tt);
#ifndef __STDC__
code = va_arg (p, enum tree_code);
tt = va_arg (p, tree);
#endif
expression_obstack = &permanent_obstack;
t = make_node (code);
length = tree_code_length[(int) code];
TREE_TYPE (t) = copy_to_permanent (tt);
TREE_COMPLEXITY (t) = lineno;
for (i = 0; i < length; i++)
{
tree x = va_arg (p, tree);
TREE_OPERAND (t, i) = copy_to_permanent (x);
}
va_end (p);
expression_obstack = ambient_obstack;
return t;
}
tree
min_tree_cons (purpose, value, chain)
tree purpose, value, chain;
{
register tree node;
register struct obstack *ambient_obstack = current_obstack;
current_obstack = &permanent_obstack;
node = tree_cons (copy_to_permanent (purpose),
copy_to_permanent (value), chain);
current_obstack = ambient_obstack;
return node;
}
tree
get_type_decl (t)
tree t;
{
if (TREE_CODE (t) == TYPE_DECL)
return t;
if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
return TYPE_STUB_DECL (t);
my_friendly_abort (42);
return 0;
}
int
can_free (obstack, t)
struct obstack *obstack;
tree t;
{
int size = 0;
if (TREE_CODE (t) == TREE_VEC)
size = (TREE_VEC_LENGTH (t)-1) * sizeof (tree) + sizeof (struct tree_vec);
else
my_friendly_abort (42);
#define ROUND(x) ((x + obstack_alignment_mask (obstack)) \
& ~ obstack_alignment_mask (obstack))
if ((char *)t + ROUND (size) == obstack_next_free (obstack))
return 1;
#undef ROUND
return 0;
}
tree
vec_binfo_member (elem, vec)
tree elem, vec;
{
int i;
if (vec)
for (i = 0; i < TREE_VEC_LENGTH (vec); ++i)
if (same_type_p (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i))))
return TREE_VEC_ELT (vec, i);
return NULL_TREE;
}
tree
hack_decl_function_context (decl)
tree decl;
{
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FUNCTION_MEMBER_P (decl))
return decl_function_context (TYPE_MAIN_DECL (DECL_CLASS_CONTEXT (decl)));
return decl_function_context (decl);
}
tree
decl_namespace_context (decl)
tree decl;
{
while (1)
{
if (TREE_CODE (decl) == NAMESPACE_DECL)
return decl;
else if (TYPE_P (decl))
decl = CP_DECL_CONTEXT (TYPE_MAIN_DECL (decl));
else
decl = CP_DECL_CONTEXT (decl);
}
}
int
cp_tree_equal (t1, t2)
tree t1, t2;
{
register enum tree_code code1, code2;
int cmp;
if (t1 == t2)
return 1;
if (t1 == 0 || t2 == 0)
return 0;
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
{
if (code2 == NOP_EXPR || code2 == CONVERT_EXPR || code2 == NON_LVALUE_EXPR)
return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
else
return cp_tree_equal (TREE_OPERAND (t1, 0), t2);
}
else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
|| code2 == NON_LVALUE_EXPR)
return cp_tree_equal (t1, TREE_OPERAND (t2, 0));
if (code1 != code2)
return 0;
switch (code1)
{
case INTEGER_CST:
return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
case REAL_CST:
return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
case STRING_CST:
return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
&& !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
TREE_STRING_LENGTH (t1));
case CONSTRUCTOR:
if (!(same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
&& TREE_OPERAND (t1, 0) == TREE_OPERAND (t2, 0)))
return 0;
return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case TREE_LIST:
cmp = cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
if (cmp <= 0)
return cmp;
cmp = cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2));
if (cmp <= 0)
return cmp;
return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
case SAVE_EXPR:
return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
case CALL_EXPR:
cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case TARGET_EXPR:
if ((TREE_CODE (TREE_OPERAND (t1, 0)) == VAR_DECL
&& DECL_NAME (TREE_OPERAND (t1, 0)) == NULL_TREE
&& DECL_RTL (TREE_OPERAND (t1, 0)) == 0)
|| (TREE_CODE (TREE_OPERAND (t2, 0)) == VAR_DECL
&& DECL_NAME (TREE_OPERAND (t2, 0)) == NULL_TREE
&& DECL_RTL (TREE_OPERAND (t2, 0)) == 0))
cmp = 1;
else
cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case WITH_CLEANUP_EXPR:
cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t1, 2));
case COMPONENT_REF:
if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
return 0;
case VAR_DECL:
case PARM_DECL:
case CONST_DECL:
case FUNCTION_DECL:
return 0;
case TEMPLATE_PARM_INDEX:
return TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
&& TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2);
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
return 0;
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t1, 0))) == 't')
return same_type_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
break;
case PTRMEM_CST:
return (PTRMEM_CST_MEMBER (t1) == PTRMEM_CST_MEMBER (t2)
&& same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2)));
default:
break;
}
switch (TREE_CODE_CLASS (code1))
{
int i;
case '1':
case '2':
case '<':
case 'e':
case 'r':
case 's':
cmp = 1;
for (i=0; i<tree_code_length[(int) code1]; ++i)
{
cmp = cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
if (cmp <= 0)
return cmp;
}
return cmp;
}
return -1;
}
tree
make_temp_vec (len)
int len;
{
register tree node;
push_expression_obstack ();
node = make_tree_vec (len);
pop_obstacks ();
return node;
}
tree
build_ptr_wrapper (ptr)
void *ptr;
{
tree t = make_node (WRAPPER);
WRAPPER_PTR (t) = ptr;
return t;
}
tree
build_expr_ptr_wrapper (ptr)
void *ptr;
{
tree t;
push_expression_obstack ();
t = build_ptr_wrapper (ptr);
pop_obstacks ();
return t;
}
tree
build_int_wrapper (i)
int i;
{
tree t = make_node (WRAPPER);
WRAPPER_INT (t) = i;
return t;
}
static tree
build_srcloc (file, line)
char *file;
int line;
{
tree t;
register struct obstack *ambient_obstack = current_obstack;
current_obstack = &permanent_obstack;
t = make_node (SRCLOC);
SRCLOC_FILE (t) = file;
SRCLOC_LINE (t) = line;
current_obstack = ambient_obstack;
return t;
}
tree
build_srcloc_here ()
{
return build_srcloc (input_filename, lineno);
}
void
push_expression_obstack ()
{
push_obstacks_nochange ();
current_obstack = expression_obstack;
}
tree
lvalue_type (arg)
tree arg;
{
tree type = TREE_TYPE (arg);
if (TREE_CODE (arg) == OVERLOAD)
type = unknown_type_node;
return type;
}
tree
error_type (arg)
tree arg;
{
tree type = TREE_TYPE (arg);
if (TREE_CODE (type) == ARRAY_TYPE)
;
else if (real_lvalue_p (arg))
type = build_reference_type (lvalue_type (arg));
else if (IS_AGGR_TYPE (type))
type = lvalue_type (arg);
return type;
}
int
varargs_function_p (function)
tree function;
{
tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
for (; parm; parm = TREE_CHAIN (parm))
if (TREE_VALUE (parm) == void_type_node)
return 0;
return 1;
}
int
member_p (decl)
tree decl;
{
tree ctx = DECL_CONTEXT (decl);
return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
}
tree
build_dummy_object (type)
tree type;
{
tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node);
return build_indirect_ref (decl, NULL_PTR);
}
tree
maybe_dummy_object (type, binfop)
tree type;
tree *binfop;
{
tree decl, context;
if (current_class_type
&& get_base_distance (type, current_class_type, 0, binfop) != -1)
context = current_class_type;
else
{
context = type;
if (binfop)
*binfop = TYPE_BINFO (type);
}
if (current_class_ref && context == current_class_type)
decl = current_class_ref;
else
decl = build_dummy_object (context);
return decl;
}
int
is_dummy_object (ob)
tree ob;
{
if (TREE_CODE (ob) == INDIRECT_REF)
ob = TREE_OPERAND (ob, 0);
return (TREE_CODE (ob) == NOP_EXPR
&& TREE_OPERAND (ob, 0) == void_zero_node);
}
int
pod_type_p (t)
tree t;
{
tree f;
while (TREE_CODE (t) == ARRAY_TYPE)
t = TREE_TYPE (t);
if (! IS_AGGR_TYPE (t))
return 1;
if (CLASSTYPE_NON_AGGREGATE (t)
|| TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|| TYPE_HAS_DESTRUCTOR (t))
return 0;
for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f))
{
if (TREE_CODE (f) != FIELD_DECL)
continue;
if (TREE_CODE (TREE_TYPE (f)) == REFERENCE_TYPE
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (f))
|| TYPE_PTRMEM_P (TREE_TYPE (f)))
return 0;
}
return 1;
}
int
cp_valid_lang_attribute (attr_name, attr_args, decl, type)
tree attr_name;
tree attr_args ATTRIBUTE_UNUSED;
tree decl ATTRIBUTE_UNUSED;
tree type ATTRIBUTE_UNUSED;
{
if (is_attribute_p ("com_interface", attr_name))
{
if (! flag_vtable_thunks)
{
error ("`com_interface' only supported with -fvtable-thunks");
return 0;
}
if (attr_args != NULL_TREE
|| decl != NULL_TREE
|| ! CLASS_TYPE_P (type)
|| type != TYPE_MAIN_VARIANT (type))
{
warning ("`com_interface' attribute can only be applied to class definitions");
return 0;
}
CLASSTYPE_COM_INTERFACE (type) = 1;
return 1;
}
else if (is_attribute_p ("init_priority", attr_name))
{
tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
int pri;
if (initp_expr)
STRIP_NOPS (initp_expr);
if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
{
error ("requested init_priority is not an integer constant");
return 0;
}
pri = TREE_INT_CST_LOW (initp_expr);
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (decl == NULL_TREE
|| TREE_CODE (decl) != VAR_DECL
|| ! TREE_STATIC (decl)
|| DECL_EXTERNAL (decl)
|| (TREE_CODE (type) != RECORD_TYPE
&& TREE_CODE (type) != UNION_TYPE)
|| current_function_decl)
{
error ("can only use init_priority attribute on file-scope definitions of objects of class type");
return 0;
}
if (pri > MAX_INIT_PRIORITY || pri <= 0)
{
error ("requested init_priority is out of range");
return 0;
}
if (pri <= MAX_RESERVED_INIT_PRIORITY)
{
warning
("requested init_priority is reserved for internal use");
}
DECL_INIT_PRIORITY (decl) = pri;
return 1;
}
return 0;
}
tree
make_ptrmem_cst (type, member)
tree type;
tree member;
{
tree ptrmem_cst = make_node (PTRMEM_CST);
TREE_CONSTANT (ptrmem_cst) = 1;
TREE_TYPE (ptrmem_cst) = type;
PTRMEM_CST_MEMBER (ptrmem_cst) = member;
return ptrmem_cst;
}