/* Language-dependent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#include "rtl.h"
#include "toplev.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-extern void compiler_error ();
-
-static tree get_identifier_list PROTO((tree));
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, int, int, int, tree, tree,
- tree));
+static tree list_hash_lookup PROTO((int, tree, tree, tree));
static void propagate_binfo_offsets PROTO((tree, tree));
-static void unshare_base_binfos PROTO((tree));
static int avoid_overlap PROTO((tree, tree));
+static cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
+static tree no_linkage_helper PROTO((tree));
+static tree build_srcloc PROTO((char *, int));
#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. */
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+ Otherwise, returns clk_none. If TREAT_CLASS_RVALUES_AS_LVALUES is
+ non-zero, rvalues of class type are considered lvalues. */
-int
-real_lvalue_p (ref)
+static cp_lvalue_kind
+lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
tree ref;
+ int treat_class_rvalues_as_lvalues;
{
- if (! language_lvalue_valid (ref))
- return 0;
-
+ cp_lvalue_kind op1_lvalue_kind = clk_none;
+ cp_lvalue_kind op2_lvalue_kind = clk_none;
+
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
- return 1;
+ return clk_ordinary;
if (ref == current_class_ptr && flag_this_is_variable <= 0)
- return 0;
+ return clk_none;
switch (TREE_CODE (ref))
{
what they refer to are valid lvals. */
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
- case COMPONENT_REF:
case SAVE_EXPR:
case UNSAVE_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
- return real_lvalue_p (TREE_OPERAND (ref, 0));
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case NOP_EXPR:
+ return lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues);
+
+ case COMPONENT_REF:
+ op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues);
+ if (op1_lvalue_kind
+ /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
+ situations. */
+ && TREE_CODE (TREE_OPERAND (ref, 1)) == FIELD_DECL
+ && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
+ {
+ /* Clear the ordinary bit. If this object was a class
+ rvalue we want to preserve that information. */
+ op1_lvalue_kind &= ~clk_ordinary;
+ /* The lvalue is for a btifield. */
+ op1_lvalue_kind |= clk_bitfield;
+ }
+ return op1_lvalue_kind;
case STRING_CST:
- return 1;
+ return clk_ordinary;
case VAR_DECL:
if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
&& DECL_LANG_SPECIFIC (ref)
&& DECL_IN_AGGR_P (ref))
- return 0;
+ return clk_none;
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;
+ if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
+ return clk_ordinary;
break;
/* A currently unresolved scope ref. */
my_friendly_abort (103);
case OFFSET_REF:
if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
- return 1;
- return real_lvalue_p (TREE_OPERAND (ref, 0))
- && real_lvalue_p (TREE_OPERAND (ref, 1));
+ return clk_ordinary;
+ /* Fall through. */
+ case MAX_EXPR:
+ case MIN_EXPR:
+ op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues);
+ op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+ treat_class_rvalues_as_lvalues);
break;
case COND_EXPR:
- return (real_lvalue_p (TREE_OPERAND (ref, 1))
- && real_lvalue_p (TREE_OPERAND (ref, 2)));
+ op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+ treat_class_rvalues_as_lvalues);
+ op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
+ treat_class_rvalues_as_lvalues);
+ break;
case MODIFY_EXPR:
- return 1;
+ return clk_ordinary;
case COMPOUND_EXPR:
- return real_lvalue_p (TREE_OPERAND (ref, 1));
-
- case MAX_EXPR:
- case MIN_EXPR:
- return (real_lvalue_p (TREE_OPERAND (ref, 0))
- && real_lvalue_p (TREE_OPERAND (ref, 1)));
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* This differs from real_lvalue_p in that class rvalues are considered
- lvalues. */
-int
-lvalue_p (ref)
- tree ref;
-{
- if (! language_lvalue_valid (ref))
- return 0;
-
- 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))
- {
- /* preincrements and predecrements are valid lvals, provided
- what they refer to are valid lvals. */
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case COMPONENT_REF:
- case SAVE_EXPR:
- case UNSAVE_EXPR:
- case TRY_CATCH_EXPR:
- case WITH_CLEANUP_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;
+ return lvalue_p_1 (TREE_OPERAND (ref, 1),
+ treat_class_rvalues_as_lvalues);
case TARGET_EXPR:
- return 1;
+ return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
case CALL_EXPR:
- if (IS_AGGR_TYPE (TREE_TYPE (ref)))
- return 1;
- break;
+ return ((treat_class_rvalues_as_lvalues
+ && IS_AGGR_TYPE (TREE_TYPE (ref)))
+ ? clk_class : clk_none);
- /* 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));
+ case FUNCTION_DECL:
+ /* All functions (except non-static-member functions) are
+ lvalues. */
+ return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
+ ? clk_none : clk_ordinary);
+
+ default:
break;
+ }
- case COND_EXPR:
- return (lvalue_p (TREE_OPERAND (ref, 1))
- && lvalue_p (TREE_OPERAND (ref, 2)));
+ /* If one operand is not an lvalue at all, then this expression is
+ not an lvalue. */
+ if (!op1_lvalue_kind || !op2_lvalue_kind)
+ return clk_none;
- case MODIFY_EXPR:
- return 1;
+ /* Otherwise, it's an lvalue, and it has all the odd properties
+ contributed by either operand. */
+ op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind;
+ /* It's not an ordinary lvalue if it involves either a bit-field or
+ a class rvalue. */
+ if ((op1_lvalue_kind & ~clk_ordinary) != clk_none)
+ op1_lvalue_kind &= ~clk_ordinary;
+ return op1_lvalue_kind;
+}
- case COMPOUND_EXPR:
- return lvalue_p (TREE_OPERAND (ref, 1));
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+ Otherwise, returns clk_none. Lvalues can be assigned, unless they
+ have TREE_READONLY, or unless they are FUNCTION_DECLs. Lvalues can
+ have their address taken, unless they have DECL_REGISTER. */
- case MAX_EXPR:
- case MIN_EXPR:
- return (lvalue_p (TREE_OPERAND (ref, 0))
- && lvalue_p (TREE_OPERAND (ref, 1)));
+cp_lvalue_kind
+real_lvalue_p (ref)
+ tree ref;
+{
+ return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
+}
- default:
- break;
- }
+/* This differs from real_lvalue_p in that class rvalues are
+ considered lvalues. */
- return 0;
+int
+lvalue_p (ref)
+ tree ref;
+{
+ return
+ (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
}
/* Return nonzero if REF is an lvalue valid for this language;
int
lvalue_or_else (ref, string)
tree ref;
- char *string;
+ const char *string;
{
int win = lvalue_p (ref);
if (! win)
tree type;
tree init;
{
+ tree fn;
tree slot;
tree rval;
+ /* Make sure that we're not trying to create an instance of an
+ abstract class. */
+ abstract_virtuals_error (NULL_TREE, type);
+
if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
- return init;
+ 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);
+
+ /* We split the CALL_EXPR into its function and its arguments here.
+ Then, in expand_expr, we put them back together. The reason for
+ this is that this expression might be a default argument
+ expression. In that case, we need a new temporary every time the
+ expression is used. That's what break_out_target_exprs does; it
+ replaces every AGGR_INIT_EXPR with a copy that uses a fresh
+ temporary slot. Then, expand_expr builds up a call-expression
+ using the new slot. */
+ fn = TREE_OPERAND (init, 0);
+ rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
TREE_SIDE_EFFECTS (rval) = 1;
+ AGGR_INIT_VIA_CTOR_P (rval)
+ = (TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+ && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (rval) = 1;
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_pointer_type (basetype);
/* The actual arglist for this function includes a "hidden" argument
- which is "this". Put it into the list of argument types. */
-
+ which is "this". Put it into the list of argument types. Make
+ sure that the new argument list is allocated on the same obstack
+ as the type. */
+ push_obstacks (TYPE_OBSTACK (t), TYPE_OBSTACK (t));
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
TREE_SIDE_EFFECTS (argtypes) = 1; /* Mark first argtype as "artificial". */
+ pop_obstacks ();
/* 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);
+ hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
+ type_hash_list (argtypes);
+
t = type_hash_canon (hashcode, t);
if (TYPE_SIZE (t) == 0)
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,
+ if (elt_type == error_mark_node || index_type == error_mark_node)
+ return error_mark_node;
+
+ push_obstacks_nochange ();
+
+ /* 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;
- }
+ end_temporary_allocation ();
- if (processing_template_decl
+ if (processing_template_decl
+ || uses_template_parms (elt_type)
|| uses_template_parms (index_type))
{
t = make_node (ARRAY_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;
+ TYPE_NEEDS_CONSTRUCTING (t)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
+ TYPE_NEEDS_DESTRUCTOR (t)
+ = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
+ pop_obstacks ();
return t;
}
tree index_type;
{
tree t;
- int constp = TYPE_READONLY (elt_type);
- int volatilep = TYPE_VOLATILE (elt_type);
+ 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 (constp || volatilep)
- t = cp_build_type_variant (t, constp, volatilep);
+ if (type_quals != TYPE_UNQUALIFIED)
+ t = cp_build_qualified_type (t, type_quals);
return t;
}
\f
-/* Make a variant type in the proper way for C/C++, propagating qualifiers
- down to the element type of an array. */
+/* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles
+ arrays correctly. In particular, if TYPE is an array of T's, and
+ TYPE_QUALS is non-empty, returns an array of qualified T's. If
+ at attempt is made to qualify a type illegally, and COMPLAIN is
+ non-zero, an error is issued. If COMPLAIN is zero, error_mark_node
+ is returned. */
tree
-cp_build_type_variant (type, constp, volatilep)
+cp_build_qualified_type_real (type, type_quals, complain)
tree type;
- int constp, volatilep;
+ int type_quals;
+ int complain;
{
+ tree result;
+
if (type == error_mark_node)
return type;
-
- if (TREE_CODE (type) == ARRAY_TYPE)
+
+ if (type_quals == TYPE_QUALS (type))
+ return type;
+
+ /* A restrict-qualified pointer type must be a pointer (or reference)
+ to object or incomplete type. */
+ if ((type_quals & TYPE_QUAL_RESTRICT)
+ && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+ && (!POINTER_TYPE_P (type)
+ || TYPE_PTRMEM_P (type)
+ || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
{
- tree real_main_variant = TYPE_MAIN_VARIANT (type);
+ if (complain)
+ cp_error ("`%T' cannot be `restrict'-qualified", type);
+ else
+ return error_mark_node;
+
+ type_quals &= ~TYPE_QUAL_RESTRICT;
+ }
- push_obstacks (TYPE_OBSTACK (real_main_variant),
- TYPE_OBSTACK (real_main_variant));
- type = build_cplus_array_type_1 (cp_build_type_variant
- (TREE_TYPE (type), constp, volatilep),
- TYPE_DOMAIN (type));
+ if (type_quals != TYPE_UNQUALIFIED
+ && TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ if (complain)
+ cp_error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
+ else
+ return error_mark_node;
+ type_quals = TYPE_UNQUALIFIED;
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ /* In C++, the qualification really applies to the array element
+ type. Obtain the appropriately qualified element type. */
+ tree t;
+ tree element_type
+ = cp_build_qualified_type_real (TREE_TYPE (type),
+ type_quals,
+ complain);
+
+ if (element_type == error_mark_node)
+ return error_mark_node;
- /* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not,
- make a copy. (TYPE might have come from the hash table and
- REAL_MAIN_VARIANT might be in some function's obstack.) */
+ /* See if we already have an identically qualified type. */
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ if (CP_TYPE_QUALS (t) == type_quals)
+ break;
- if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+ /* If we didn't already have it, create it now. */
+ if (!t)
{
- type = copy_node (type);
- TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+ /* Make a new array type, just like the old one, but with the
+ appropriately qualified element type. */
+ t = build_type_copy (type);
+ TREE_TYPE (t) = element_type;
}
- TYPE_MAIN_VARIANT (type) = real_main_variant;
- pop_obstacks ();
- return type;
+ /* Even if we already had this variant, we update
+ TYPE_NEEDS_CONSTRUCTING and TYPE_NEEDS_DESTRUCTOR in case
+ they changed since the variant was originally created.
+
+ This seems hokey; if there is some way to use a previous
+ variant *without* coming through here,
+ TYPE_NEEDS_CONSTRUCTING will never be updated. */
+ TYPE_NEEDS_CONSTRUCTING (t)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
+ TYPE_NEEDS_DESTRUCTOR (t)
+ = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
+ return t;
+ }
+ else if (TYPE_PTRMEMFUNC_P (type))
+ {
+ /* For a pointer-to-member type, we can't just return a
+ cv-qualified version of the RECORD_TYPE. If we do, we
+ haven't change the field that contains the actual pointer to
+ a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong. */
+ tree t;
+
+ t = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ t = cp_build_qualified_type_real (t, type_quals, complain);
+ return build_ptrmemfunc_type (t);
}
- return build_type_variant (type, constp, volatilep);
+
+ /* Retrieve (or create) the appropriately qualified variant. */
+ result = build_qualified_type (type, type_quals);
+
+ /* If this was a pointer-to-method type, and we just made a copy,
+ then we need to clear the cached associated
+ pointer-to-member-function type; it is not valid for the new
+ type. */
+ if (result != type
+ && TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ TYPE_SET_PTRMEMFUNC_TYPE (result, NULL_TREE);
+
+ return result;
+}
+
+/* Returns the canonical version of TYPE. In other words, if TYPE is
+ a typedef, returns the underlying type. The cv-qualification of
+ the type returned matches the type input; they will always be
+ compatible types. */
+
+tree
+canonical_type_variant (t)
+ tree t;
+{
+ return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), CP_TYPE_QUALS (t));
}
\f
/* Add OFFSET to all base types of T.
BINFO_OFFSET (base_binfo) = offset;
#endif
- unshare_base_binfos (base_binfo);
+ propagate_binfo_offsets (base_binfo, offset);
/* Go to our next class that counts for offset propagation. */
i = j;
}
}
-/* Makes new binfos for the indirect bases under BASE_BINFO, and updates
+/* Makes new binfos for the indirect bases under BINFO, and updates
BINFO_OFFSET for them and their bases. */
-static void
-unshare_base_binfos (base_binfo)
- tree base_binfo;
+void
+unshare_base_binfos (binfo)
+ tree binfo;
{
- if (BINFO_BASETYPES (base_binfo))
- {
- tree base_binfos = BINFO_BASETYPES (base_binfo);
- tree chain = NULL_TREE;
- int j;
+ tree binfos = BINFO_BASETYPES (binfo);
+ tree new_binfo;
+ int j;
- /* Now unshare the structure beneath BASE_BINFO. */
- for (j = TREE_VEC_LENGTH (base_binfos)-1;
- j >= 0; j--)
- {
- tree base_base_binfo = TREE_VEC_ELT (base_binfos, j);
- if (! TREE_VIA_VIRTUAL (base_base_binfo))
- TREE_VEC_ELT (base_binfos, j)
- = make_binfo (BINFO_OFFSET (base_base_binfo),
- base_base_binfo,
- BINFO_VTABLE (base_base_binfo),
- BINFO_VIRTUALS (base_base_binfo),
- chain);
- chain = TREE_VEC_ELT (base_binfos, j);
- TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
- TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
- BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
- }
+ if (binfos == NULL_TREE)
+ return;
- /* Completely unshare potentially shared data, and
- update what is ours. */
- propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
+ /* Now unshare the structure beneath BINFO. */
+ 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);
}
}
tree binfos = TYPE_BINFO_BASETYPES (rec);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- /* 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);
+ tree vbase_types;
unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
unsigned int desired_align;
record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
#endif
- CLASSTYPE_VBASECLASSES (rec) = vbase_types;
+ /* Get all the virtual base types that this type uses. The
+ TREE_VALUE slot holds the virtual baseclass type. Note that
+ get_vbase_types makes copies of the virtual base BINFOs, so that
+ the vbase_types are unshared. */
+ 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));
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));
- unshare_base_binfos (base_binfo);
+ propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
TYPE_FIELDS (rec) = TREE_CHAIN (field);
}
{
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;
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
- decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, basetype);
+ decl = build_lang_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);
base_align = MAX (base_align, DECL_ALIGN (decl));
DECL_SIZE (decl)
= size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
- base_align));
+ (int) base_align));
}
else if (DECL_SIZE (decl) == integer_zero_node)
saw_empty = 1;
if (TREE_VIA_VIRTUAL (base_binfo))
{
int j;
- char *name = (char *)alloca (TYPE_NAME_LENGTH (basetype)
- + sizeof (VBASE_NAME) + 1);
+ const char *name;
/* The offset for a virtual base class is only used in computing
virtual function tables and for initializing virtual base
))
goto got_it;
}
- sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype));
- decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
- build_pointer_type (basetype));
+ FORMAT_VBASE_NAME (name, 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_FIELD_CONTEXT (decl) = rec;
DECL_CLASS_CONTEXT (decl) = rec;
DECL_FCONTEXT (decl) = basetype;
- DECL_SAVED_INSNS (decl) = NULL_RTX;
+ DECL_SAVED_INSNS (decl) = 0;
DECL_FIELD_SIZE (decl) = 0;
DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node);
TREE_CHAIN (decl) = vbase_decls;
If one is found, return it. Otherwise return 0. */
static tree
-list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
- purpose, value, chain)
- int hashcode, via_public, via_virtual, via_protected;
+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_VIA_VIRTUAL (h->list) == via_virtual
- && TREE_VIA_PUBLIC (h->list) == via_public
- && TREE_VIA_PROTECTED (h->list) == via_protected
&& TREE_PURPOSE (h->list) == purpose
&& TREE_VALUE (h->list) == value
&& TREE_CHAIN (h->list) == chain)
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. */
+/* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical
+ object for an identical list if one already exists. Otherwise, build a
+ new one, and record it as the canonical object. */
/* Set to 1 to debug without canonicalization. Never set by program. */
static int debug_no_list_hash = 0;
tree
-hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
- int via_public, via_virtual, via_protected;
+hash_tree_cons (purpose, value, chain)
tree purpose, value, chain;
{
struct obstack *ambient_obstack = current_obstack;
if (! debug_no_list_hash)
{
hashcode = list_hash (purpose, value, chain);
- t = list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
- 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);
- TREE_VIA_PUBLIC (t) = via_public;
- TREE_VIA_PROTECTED (t) = via_protected;
- TREE_VIA_VIRTUAL (t) = via_virtual;
/* If this is a new list, record it for later reuse. */
if (! debug_no_list_hash)
hash_tree_chain (value, chain)
tree value, chain;
{
- return hash_tree_cons (0, 0, 0, NULL_TREE, value, chain);
+ return hash_tree_cons (NULL_TREE, value, chain);
}
/* Similar, but used for concatenating two lists. */
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
- {
- if (! CLASSTYPE_ID_AS_LIST (type))
- CLASSTYPE_ID_AS_LIST (type)
- = perm_tree_cons (NULL_TREE, TYPE_IDENTIFIER (type), 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)
- && value == TYPE_MAIN_VARIANT (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);
-}
\f
/* Build an association between TYPE and some parameters:
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. */
+ VIRTUALS are the virtual functions sitting in VTABLE. */
tree
-make_binfo (offset, binfo, vtable, virtuals, chain)
+make_binfo (offset, binfo, vtable, virtuals)
tree offset, binfo;
tree vtable, virtuals;
- tree chain;
{
- tree new_binfo = make_tree_vec (6);
+ tree new_binfo = make_tree_vec (7);
tree type;
if (TREE_CODE (binfo) == TREE_VEC)
else
{
type = binfo;
- binfo = TYPE_BINFO (binfo);
+ binfo = CLASS_TYPE_P (type) ? TYPE_BINFO (binfo) : NULL_TREE;
}
- 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;
return get_binfo (elem, type, 0);
}
+/* Return a reversed copy of the BINFO-chain given by PATH. (If the
+ BINFO_INHERITANCE_CHAIN points from base classes to derived
+ classes, it will instead point from derived classes to base
+ classes.) Returns the first node in the reversed chain. */
+
tree
reverse_path (path)
tree path;
{
- register tree prev = 0, tmp, next;
- for (tmp = path; tmp; tmp = next)
+ register tree prev = NULL_TREE, cur;
+ push_expression_obstack ();
+ for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
{
- next = BINFO_INHERITANCE_CHAIN (tmp);
- BINFO_INHERITANCE_CHAIN (tmp) = prev;
- prev = tmp;
+ tree r = copy_node (cur);
+ BINFO_INHERITANCE_CHAIN (r) = prev;
+ prev = r;
}
+ pop_obstacks ();
return prev;
}
unsigned HOST_WIDE_INT n;
tree virtuals;
- fprintf (stderr, "type \"%s\"; offset = %d\n",
+ fprintf (stderr, "type \"%s\"; offset = %ld\n",
TYPE_NAME_STRING (BINFO_TYPE (elem)),
- TREE_INT_CST_LOW (BINFO_OFFSET (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, "virtuals:\n");
virtuals = BINFO_VIRTUALS (elem);
- n = skip_rtti_stuff (&virtuals);
+ 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 [%d =? %d]\n",
+ tree fndecl = TREE_VALUE (virtuals);
+ fprintf (stderr, "%s [%ld =? %ld]\n",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
- n, TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
+ (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
++n;
virtuals = TREE_CHAIN (virtuals);
}
is_overloaded_fn (x)
tree x;
{
- /* XXX A baselink is also considered an overloaded function.
- As is a placeholder from push_class_decls. */
- if (TREE_CODE (x) == TREE_LIST)
- {
- my_friendly_assert (TREE_CODE (TREE_PURPOSE (x)) == TREE_VEC
- || TREE_CODE (TREE_PURPOSE (x)) == IDENTIFIER_NODE,
- 388);
- x = TREE_VALUE (x);
- }
+ /* A baselink is also considered an overloaded function. */
+ 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)
really_overloaded_fn (x)
tree x;
{
- /* A baselink is also considered an overloaded function.
- This might also be an ambiguous class member. */
- while (TREE_CODE (x) == TREE_LIST)
+ /* A baselink is also considered an overloaded function. */
+ 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
{
my_friendly_assert (is_overloaded_fn (from), 9);
/* A baselink is also considered an overloaded function. */
- if (TREE_CODE (from) == TREE_LIST)
+ if (BASELINK_P (from))
from = TREE_VALUE (from);
return OVL_CURRENT (from);
}
+/* Returns nonzero if T is a ->* or .* expression that refers to a
+ member function. */
+
+int
+bound_pmf_p (t)
+ tree t;
+{
+ return (TREE_CODE (t) == OFFSET_REF
+ && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (t, 1))));
+}
+
/* Return a new OVL node, concatenating it with the old one. */
tree
tree decl;
tree chain;
{
- if (!chain)
+ if (! chain && TREE_CODE (decl) != TEMPLATE_DECL)
return decl;
- if (TREE_CODE (chain) != OVERLOAD)
+ if (chain && TREE_CODE (chain) != OVERLOAD)
chain = ovl_cons (chain, NULL_TREE);
return ovl_cons (decl, chain);
}
tree fn;
tree ovl;
{
- if (fn == ovl)
- return 1;
- if (!ovl || TREE_CODE (ovl) != OVERLOAD)
+ if (ovl == NULL_TREE)
return 0;
+ if (TREE_CODE (ovl) != OVERLOAD)
+ return ovl == fn;
for (; ovl; ovl = OVL_CHAIN (ovl))
if (OVL_FUNCTION (ovl) == fn)
return 1;
\f
#define PRINT_RING_SIZE 4
-char *
+const char *
lang_printable_name (decl, v)
tree decl;
int v;
tree raises;
{
tree v = TYPE_MAIN_VARIANT (type);
- int constp = TYPE_READONLY (type);
- int volatilep = TYPE_VOLATILE (type);
+ int type_quals = TYPE_QUALS (type);
for (; v; v = TYPE_NEXT_VARIANT (v))
- {
- if (TYPE_READONLY (v) != constp
- || TYPE_VOLATILE (v) != volatilep)
- continue;
-
- /* @@ This should do set equality, not exact match. */
- if (simple_cst_list_equal (TYPE_RAISES_EXCEPTIONS (v), raises))
- /* List of exceptions raised matches previously found list.
-
- @@ Nice to free up storage used in consing up the
- @@ list of exceptions raised. */
- return v;
- }
+ if (TYPE_QUALS (v) == type_quals
+ && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1))
+ return v;
/* Need to build a new variant. */
v = build_type_copy (type);
if (raises && ! TREE_PERMANENT (raises))
- {
- push_obstacks_nochange ();
- end_temporary_allocation ();
- raises = copy_list (raises);
- pop_obstacks ();
- }
+ raises = copy_to_permanent (raises);
TYPE_RAISES_EXCEPTIONS (v) = raises;
return v;
tree t;
{
tree template = TYPE_NAME (t);
- tree t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+ tree t2;
+
+ /* Make sure these end up on the permanent_obstack. */
+ push_permanent_obstack ();
+
+ 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;
/* No need to copy these */
TYPE_FIELDS (t2) = TYPE_FIELDS (t);
- CLASSTYPE_TEMPLATE_INFO (t2) = CLASSTYPE_TEMPLATE_INFO (t);
+ TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)
+ = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
return t2;
}
-/* 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. */
+/* Walk through the tree structure T, applying func. If func ever returns
+ non-null, return that value. */
tree
-mapcar (t, func)
+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;
+ enum tree_code code;
if (t == NULL_TREE)
return t;
-
- if (tmp = func (t), tmp != NULL_TREE)
+
+ tmp = func (t);
+ if (tmp)
return tmp;
- switch (TREE_CODE (t))
+ /* Handle some common cases up front. */
+ code = TREE_CODE (t);
+ if (TREE_CODE_CLASS (code) == '1')
+ {
+ TRY (TREE_OPERAND (t, 0));
+ return NULL_TREE;
+ }
+ else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+ {
+ TRY (TREE_OPERAND (t, 0));
+ TRY (TREE_OPERAND (t, 1));
+ return NULL_TREE;
+ }
+
+ switch (code)
{
case ERROR_MARK:
- return error_mark_node;
+ break;
+
+ case IDENTIFIER_NODE:
+ break;
case VAR_DECL:
case FUNCTION_DECL:
case CONST_DECL:
- /* Rather than aborting, return error_mark_node. This allows us
- to report a sensible error message on code like this:
+ case TEMPLATE_DECL:
+ case NAMESPACE_DECL:
+ break;
- void g() { int i; f<i>(7); }
+ case TYPE_DECL:
+ TRY (TREE_TYPE (t));
+ break;
- In a case like:
+ case PARM_DECL:
+ TRY (TREE_TYPE (t));
+ TRY (TREE_CHAIN (t));
+ break;
- void g() { const int i = 7; f<i>(7); }
+ case TREE_LIST:
+ TRY (TREE_PURPOSE (t));
+ TRY (TREE_VALUE (t));
+ TRY (TREE_CHAIN (t));
+ break;
- however, we must actually return the constant initializer. */
- tmp = decl_constant_value (t);
- if (tmp != t)
- return mapcar (tmp, func);
- else
- return error_mark_node;
+ case OVERLOAD:
+ TRY (OVL_FUNCTION (t));
+ TRY (OVL_CHAIN (t));
+ break;
- case PARM_DECL:
+ case TREE_VEC:
{
- tree chain = TREE_CHAIN (t);
+ 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 TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_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:
+ case COMPOUND_EXPR:
+ case MODIFY_EXPR:
+ case INIT_EXPR:
+ TRY (TREE_OPERAND (t, 0));
+ TRY (TREE_OPERAND (t, 1));
+ break;
+
+ case SAVE_EXPR:
+ case ADDR_EXPR:
+ case INDIRECT_REF:
+ case TRUTH_NOT_EXPR:
+ case COMPONENT_REF:
+ case CLEANUP_POINT_EXPR:
+ case LOOKUP_EXPR:
+ case THROW_EXPR:
+ case EXIT_EXPR:
+ case LOOP_EXPR:
+ TRY (TREE_OPERAND (t, 0));
+ break;
+
+ case MODOP_EXPR:
+ case ARROW_EXPR:
+ case DOTSTAR_EXPR:
+ case TYPEID_EXPR:
+ case PSEUDO_DTOR_EXPR:
+ 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:
+ case STMT_EXPR:
+ break;
+
+ 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:
+ my_friendly_abort (19990803);
+ }
+
+ return NULL_TREE;
+
+#undef TRY
+}
+
+/* Passed to search_tree. Checks for the use of types with no linkage. */
+
+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;
+}
+
+/* Check if the type T depends on a type with no linkage and if so, return
+ it. */
+
+tree
+no_linkage_check (t)
+ tree t;
+{
+ /* There's no point in checking linkage on template functions; we
+ can't know their complete types. */
+ if (processing_template_decl)
+ return NULL_TREE;
+
+ t = search_tree (t, no_linkage_helper);
+ if (t != error_mark_node)
+ return t;
+ return NULL_TREE;
+}
+
+
+/* Make copies of all the nodes below T. If FUNC is non-NULL, call it
+ for each node. */
+
+tree
+mapcar (t, func)
+ tree t;
+ tree (*func) PROTO((tree));
+{
+ tree tmp;
+ enum tree_code code;
+
+ if (t == NULL_TREE)
+ return t;
+
+ if (func)
+ {
+ tmp = func (t);
+ if (tmp)
+ return tmp;
+ }
+
+ /* Handle some common cases up front. */
+ code = TREE_CODE (t);
+ if (TREE_CODE_CLASS (code) == '1')
+ {
+ t = copy_node (t);
+ TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+ TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+ return t;
+ }
+ else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+ {
+ 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);
+ return t;
+ }
+
+ switch (TREE_CODE (t))
+ {
+ case ERROR_MARK:
+ return error_mark_node;
+
+ case VAR_DECL:
+ case FUNCTION_DECL:
+ case CONST_DECL:
+ /* Rather than aborting, return error_mark_node. This allows us
+ to report a sensible error message on code like this:
+
+ void g() { int i; f<i>(7); }
+
+ In a case like:
+
+ void g() { const int i = 7; f<i>(7); }
+
+ however, we must actually return the constant initializer. */
+ 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);
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:
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_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_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 SCOPE_REF:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
+ case COMPOUND_EXPR:
+ case MODIFY_EXPR:
+ case 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_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);
-
- /* tree.def says that operand two is RTL, but
- build_call_declarator puts trees in there. */
- 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;
+ TREE_OPERAND (t, 2) = NULL_TREE;
return t;
- case CONVERT_EXPR:
+ case SAVE_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 THROW_EXPR:
+ case STMT_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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case REFERENCE_TYPE:
tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
- return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ 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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ 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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ 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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ 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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ 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_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ return cp_build_qualified_type (tmp, TYPE_QUALS (t));
case COMPLEX_CST:
t = copy_node (t);
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 LOOKUP_EXPR:
+ case EXIT_EXPR:
+ case LOOP_EXPR:
+ t = copy_node (t);
+ TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+ return t;
+
+ case RTL_EXPR:
+ t = copy_node (t);
+ TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+ return t;
+
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
return build_ptrmemfunc_type
(mapcar (TYPE_PTRMEMFUNC_FN_TYPE (t), func));
/* else fall through */
-
- /* This list is incomplete, but should suffice for now.
- It is very important that `sorry' not call
- `report_error_function'. That could cause an infinite loop. */
- default:
- sorry ("initializer contains unrecognized tree code");
- return error_mark_node;
+ default:
+ my_friendly_abort (19990815);
}
my_friendly_abort (107);
/* NOTREACHED */
return NULL_TREE;
}
+/* Returns T if T is allocated on the permanent obstack, NULL_TREE
+ otherwise. */
+
+tree
+permanent_p (t)
+ tree t;
+{
+ return TREE_PERMANENT (t) ? t : NULL_TREE;
+}
+
static tree
perm_manip (t)
tree t;
if (t == NULL_TREE || TREE_PERMANENT (t))
return t;
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ push_permanent_obstack ();
t = mapcar (t, perm_manip);
-
pop_obstacks ();
return t;
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);
tree
build_min_nt VPROTO((enum tree_code code, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum tree_code code;
#endif
register struct obstack *ambient_obstack = expression_obstack;
VA_START (p, code);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum tree_code);
#endif
tree
build_min VPROTO((enum tree_code code, tree tt, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum tree_code code;
tree tt;
#endif
VA_START (p, tt);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum tree_code);
tt = va_arg (p, tree);
#endif
t = make_node (code);
length = tree_code_length[(int) code];
- TREE_TYPE (t) = tt;
+ TREE_TYPE (t) = copy_to_permanent (tt);
TREE_COMPLEXITY (t) = lineno;
for (i = 0; i < length; i++)
if (vec)
for (i = 0; i < TREE_VEC_LENGTH (vec); ++i)
- if (comptypes (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i)), 1))
+ if (same_type_p (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i))))
return TREE_VEC_ELT (vec, i);
return NULL_TREE;
return decl_function_context (decl);
}
+/* Returns the namespace that contains DECL, whether directly or
+ indirectly. */
+
+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);
+ }
+}
+
/* Return truthvalue of whether T1 is the same tree structure as T2.
Return 1 if they are the same.
Return 0 if they are understandably different.
/* We need to do this when determining whether or not two
non-type pointer to member function template arguments
are the same. */
- if (!(comptypes (TREE_TYPE (t1), TREE_TYPE (t2), 1)
+ if (!(same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
/* The first operand is RTL. */
&& TREE_OPERAND (t1, 0) == TREE_OPERAND (t2, 0)))
return 0;
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 comptypes (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), 1);
+ return same_type_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
break;
+ case PTRMEM_CST:
+ /* Two pointer-to-members are the same if they point to the same
+ field or function in the same class. */
+ return (PTRMEM_CST_MEMBER (t1) == PTRMEM_CST_MEMBER (t2)
+ && same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2)));
+
default:
break;
}
return -1;
}
-/* Similar to make_tree_vec, but build on a temporary obstack. */
+/* Similar to make_tree_vec, but build on the momentary_obstack.
+ Thus, these vectors are really and truly temporary. */
tree
make_temp_vec (len)
int len;
{
register tree node;
- register struct obstack *ambient_obstack = current_obstack;
- current_obstack = expression_obstack;
+ push_expression_obstack ();
node = make_tree_vec (len);
- current_obstack = ambient_obstack;
+ pop_obstacks ();
return node;
}
return t;
}
-tree
+static tree
build_srcloc (file, line)
char *file;
int line;
{
- tree t = make_node (SRCLOC);
+ tree t;
+
+ /* Make sure that we put these on the permanent obstack; up in
+ add_pending_template, we pass this return value into perm_tree_cons,
+ which also puts it on the permanent_obstack. However, this wasn't
+ explicitly doing the same. */
+ 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;
}
current_obstack = expression_obstack;
}
+/* Begin allocating on the permanent obstack. When you're done
+ allocating there, call pop_obstacks to return to the previous set
+ of obstacks. */
+
+void
+push_permanent_obstack ()
+{
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+}
+
/* The type of ARG when used as an lvalue. */
tree
tree type = TREE_TYPE (arg);
if (TREE_CODE (arg) == OVERLOAD)
type = unknown_type_node;
- return cp_build_type_variant
- (type, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+ return type;
}
/* The type of ARG for printing error messages; denote lvalues with
tree ctx = DECL_CONTEXT (decl);
return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
}
+
+/* Create a placeholder for member access where we don't actually have an
+ object that the access is against. */
+
+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);
+}
+
+/* We've gotten a reference to a member of TYPE. Return *this if appropriate,
+ or a dummy object otherwise. If BINFOP is non-0, it is filled with the
+ binfo path from current_class_type to TYPE, or 0. */
+
+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
+ {
+ /* Reference from a nested class member function. */
+ 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;
+}
+
+/* Returns 1 if OB is a placeholder object, or a pointer to one. */
+
+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);
+}
+
+/* Returns 1 iff type T is a POD type, as defined in [basic.types]. */
+
+int
+pod_type_p (t)
+ tree t;
+{
+ while (TREE_CODE (t) == ARRAY_TYPE)
+ t = TREE_TYPE (t);
+
+ if (INTEGRAL_TYPE_P (t))
+ return 1; /* integral, character or enumeral type */
+ if (FLOAT_TYPE_P (t))
+ return 1;
+ if (TYPE_PTR_P (t))
+ return 1; /* pointer to non-member */
+ if (TYPE_PTRMEM_P (t))
+ return 1; /* pointer to member object */
+ if (TYPE_PTRMEMFUNC_P (t))
+ return 1; /* pointer to member function */
+
+ if (! CLASS_TYPE_P (t))
+ return 0; /* other non-class type (reference or function) */
+ if (CLASSTYPE_NON_POD_P (t))
+ return 0;
+ return 1;
+}
+
+/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific
+ attribute for either declaration DECL or type TYPE and 0 otherwise.
+ Plugged into valid_lang_attribute. */
+
+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)
+ /* Static objects in functions are initialized the
+ first time control passes through that
+ function. This is not precise enough to pin down an
+ init_priority value, so don't allow it. */
+ || 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;
+ }
+
+ /* Check for init_priorities that are reserved for
+ language and runtime support implementations.*/
+ if (pri <= MAX_RESERVED_INIT_PRIORITY)
+ {
+ warning
+ ("requested init_priority is reserved for internal use");
+ }
+
+ DECL_INIT_PRIORITY (decl) = pri;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the
+ thing pointed to by the constant. */
+
+tree
+make_ptrmem_cst (type, member)
+ tree type;
+ tree member;
+{
+ tree ptrmem_cst = make_node (PTRMEM_CST);
+ /* If would seem a great convenience if make_node would set
+ TREE_CONSTANT for things of class `c', but it does not. */
+ TREE_CONSTANT (ptrmem_cst) = 1;
+ TREE_TYPE (ptrmem_cst) = type;
+ PTRMEM_CST_MEMBER (ptrmem_cst) = member;
+ return ptrmem_cst;
+}
+
+/* Initialize unsave for C++. */
+void
+init_cplus_unsave ()
+{
+ lang_unsave_expr_now = cplus_unsave_expr_now;
+}
+
+/* The C++ version of unsave_expr_now.
+ See gcc/tree.c:unsave_expr_now for comments. */
+
+void
+cplus_unsave_expr_now (expr)
+ tree expr;
+{
+ if (expr == NULL)
+ return;
+
+ else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
+ {
+ unsave_expr_now (TREE_OPERAND (expr,0));
+ if (TREE_OPERAND (expr, 1)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+ {
+ tree exp = TREE_OPERAND (expr, 1);
+ while (exp)
+ {
+ unsave_expr_now (TREE_VALUE (exp));
+ exp = TREE_CHAIN (exp);
+ }
+ }
+ unsave_expr_now (TREE_OPERAND (expr,2));
+ return;
+ }
+
+ else
+ return;
+}
+