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 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))
-/* Returns non-zero if REF is an lvalue. If
- TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type
- are considered lvalues. */
+/* 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. */
-static int
+static cp_lvalue_kind
lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
tree ref;
int treat_class_rvalues_as_lvalues;
{
+ 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:
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:
if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
- return 1;
+ 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 (lvalue_p_1 (TREE_OPERAND (ref, 0),
- treat_class_rvalues_as_lvalues)
- && lvalue_p_1 (TREE_OPERAND (ref, 1),
- treat_class_rvalues_as_lvalues));
+ 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 (lvalue_p_1 (TREE_OPERAND (ref, 1),
- treat_class_rvalues_as_lvalues)
- && lvalue_p_1 (TREE_OPERAND (ref, 2),
- treat_class_rvalues_as_lvalues));
+ 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 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));
+ treat_class_rvalues_as_lvalues);
case TARGET_EXPR:
- return treat_class_rvalues_as_lvalues;
+ return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
case CALL_EXPR:
- return (treat_class_rvalues_as_lvalues
- && IS_AGGR_TYPE (TREE_TYPE (ref)));
+ return ((treat_class_rvalues_as_lvalues
+ && IS_AGGR_TYPE (TREE_TYPE (ref)))
+ ? clk_class : clk_none);
case FUNCTION_DECL:
/* All functions (except non-static-member functions) are
lvalues. */
- return !DECL_NONSTATIC_MEMBER_FUNCTION_P (ref);
+ return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
+ ? clk_none : clk_ordinary);
default:
break;
}
- return 0;
+ /* 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;
+
+ /* 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;
}
-/* Return nonzero if REF is an lvalue valid for this language.
- 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. */
+/* 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. */
-int
+cp_lvalue_kind
real_lvalue_p (ref)
tree ref;
{
return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
}
-/* This differs from real_lvalue_p in that class rvalues are considered
- lvalues. */
+/* This differs from real_lvalue_p in that class rvalues are
+ considered lvalues. */
int
lvalue_p (ref)
tree ref;
{
- return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1);
+ return
+ (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
}
/* Return nonzero if REF is an lvalue valid for this language;
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 (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
|| uses_template_parms (elt_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;
}
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_qualified_type (type, type_quals)
+cp_build_qualified_type_real (type, type_quals, complain)
tree type;
int type_quals;
+ int complain;
{
+ tree result;
+
if (type == error_mark_node)
return 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))
{
- cp_error ("`%T' cannot be `restrict'-qualified", type);
+ if (complain)
+ cp_error ("`%T' cannot be `restrict'-qualified", type);
+ else
+ return error_mark_node;
+
type_quals &= ~TYPE_QUAL_RESTRICT;
}
- if (TREE_CODE (type) == ARRAY_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)
{
- tree real_main_variant = TYPE_MAIN_VARIANT (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);
- 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 (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_qualified_type (type, type_quals);
+
+ /* 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
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);
goto got_it;
}
FORMAT_VBASE_NAME (name, basetype);
- decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
- build_pointer_type (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;
while (virtuals)
{
- tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
+ tree fndecl = TREE_VALUE (virtuals);
fprintf (stderr, "%s [%ld =? %ld]\n",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
(long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
return ovl_cons (decl, chain);
}
-/* Returns true iff functions are equivalent. Equivalent functions are
- not identical only if one is a function-local extern function.
- This assumes that function-locals don't have TREE_PERMANENT. */
-
-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;
-}
-
/* True if fn is in ovl. */
int
if (ovl == NULL_TREE)
return 0;
if (TREE_CODE (ovl) != OVERLOAD)
- return equal_functions (ovl, fn);
+ return ovl == fn;
for (; ovl; ovl = OVL_CHAIN (ovl))
- if (equal_functions (OVL_FUNCTION (ovl), fn))
+ if (OVL_FUNCTION (ovl) == fn)
return 1;
return 0;
}
\f
#define PRINT_RING_SIZE 4
-char *
+const char *
lang_printable_name (decl, v)
tree decl;
int v;
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)
- /* There's a memory leak here; RAISES is not freed. */
- 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);
tree t2;
/* Make sure these end up on the permanent_obstack. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ push_permanent_obstack ();
t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
template = copy_node (template);
#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:
break;
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_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 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 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:
+ case THROW_EXPR:
+ case EXIT_EXPR:
+ case LOOP_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:
+ case PSEUDO_DTOR_EXPR:
break;
case COMPLEX_CST:
break;
case BIND_EXPR:
+ case STMT_EXPR:
break;
case REAL_TYPE:
TRY (TYPE_PTRMEMFUNC_FN_TYPE (t));
break;
- /* 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;
-
+ my_friendly_abort (19990803);
}
return NULL_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;
}
-/* 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. */
+/* Make copies of all the nodes below T. If FUNC is non-NULL, call it
+ for each node. */
tree
mapcar (t, func)
tree (*func) PROTO((tree));
{
tree tmp;
+ enum tree_code code;
if (t == NULL_TREE)
return t;
- if (tmp = func (t), tmp != NULL_TREE)
- return tmp;
+ 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))
{
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
- make_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 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;
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
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
pod_type_p (t)
tree t;
{
- tree f;
-
while (TREE_CODE (t) == ARRAY_TYPE)
t = TREE_TYPE (t);
- if (! IS_AGGR_TYPE (t))
+ if (INTEGRAL_TYPE_P (t))
+ return 1; /* integral, character or enumeral type */
+ if (FLOAT_TYPE_P (t))
return 1;
-
- if (CLASSTYPE_NON_AGGREGATE (t)
- || TYPE_HAS_COMPLEX_ASSIGN_REF (t)
- || TYPE_HAS_DESTRUCTOR (t))
+ 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;
-
- 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;
}
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;
+}
+