/* Build expressions with type checking for C compiler.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
#include "tree.h"
#include "c-tree.h"
#include "tm_p.h"
#include "flags.h"
#include "output.h"
-#include "rtl.h"
#include "expr.h"
#include "toplev.h"
#include "intl.h"
static int undeclared_variable_notice;
static tree qualify_type PARAMS ((tree, tree));
-static int comp_target_types PARAMS ((tree, tree));
+static int comp_target_types PARAMS ((tree, tree, int));
static int function_types_compatible_p PARAMS ((tree, tree));
static int type_lists_compatible_p PARAMS ((tree, tree));
static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
-static tree lookup_field PARAMS ((tree, tree, tree *));
+static tree default_function_array_conversion PARAMS ((tree));
+static tree lookup_field PARAMS ((tree, tree));
+static void undeclared_variable PARAMS ((tree));
static tree convert_arguments PARAMS ((tree, tree, tree, tree));
-static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
static tree pointer_diff PARAMS ((tree, tree));
-static tree unary_complex_lvalue PARAMS ((enum tree_code, tree));
+static tree unary_complex_lvalue PARAMS ((enum tree_code, tree, int));
static void pedantic_lvalue_warning PARAMS ((enum tree_code));
static tree internal_build_compound_expr PARAMS ((tree, int));
static tree convert_for_assignment PARAMS ((tree, tree, const char *,
static int spelling_length PARAMS ((void));
static char *print_spelling PARAMS ((char *));
static void warning_init PARAMS ((const char *));
-static tree digest_init PARAMS ((tree, tree, int, int));
+static tree digest_init PARAMS ((tree, tree, int));
static void output_init_element PARAMS ((tree, tree, tree, int));
static void output_pending_init_elements PARAMS ((int));
static int set_designator PARAMS ((int));
does not have an incomplete type. (That includes void types.) */
tree
-require_complete_type (value)
- tree value;
+require_complete_type (tree value)
{
tree type = TREE_TYPE (value);
- if (TREE_CODE (value) == ERROR_MARK)
+ if (value == error_mark_node || type == error_mark_node)
return error_mark_node;
/* First, detect a valid value with a complete type. */
if (COMPLETE_TYPE_P (type))
return value;
- incomplete_type_error (value, type);
+ c_incomplete_type_error (value, type);
return error_mark_node;
}
and TYPE is the type that was invalid. */
void
-incomplete_type_error (value, type)
- tree value;
- tree type;
+c_incomplete_type_error (tree value, tree type)
{
const char *type_code_string;
case ARRAY_TYPE:
if (TYPE_DOMAIN (type))
{
+ if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL)
+ {
+ error ("invalid use of flexible array member");
+ return;
+ }
type = TREE_TYPE (type);
goto retry;
}
}
}
+/* Given a type, apply default promotions wrt unnamed function
+ arguments and return the new type. */
+
+tree
+c_type_promotes_to (tree type)
+{
+ if (TYPE_MAIN_VARIANT (type) == float_type_node)
+ return double_type_node;
+
+ if (c_promoting_integer_type_p (type))
+ {
+ /* Preserve unsignedness if not really getting any wider. */
+ if (TREE_UNSIGNED (type)
+ && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+ return unsigned_type_node;
+ return integer_type_node;
+ }
+
+ return type;
+}
+
/* Return a variant of TYPE which has all the type qualifiers of LIKE
as well as those of TYPE. */
static tree
-qualify_type (type, like)
- tree type, like;
+qualify_type (tree type, tree like)
{
- return c_build_qualified_type (type,
+ return c_build_qualified_type (type,
TYPE_QUALS (type) | TYPE_QUALS (like));
}
\f
if the operands have the given two types. */
tree
-common_type (t1, t2)
- tree t1, t2;
+common_type (tree t1, tree t2)
{
enum tree_code code1;
enum tree_code code2;
/* Treat an enum type as the unsigned integer type of the same width. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = type_for_size (TYPE_PRECISION (t1), 1);
+ t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
- t2 = type_for_size (TYPE_PRECISION (t2), 1);
+ t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
tree pointed_to_2 = TREE_TYPE (t2);
tree target = common_type (TYPE_MAIN_VARIANT (pointed_to_1),
TYPE_MAIN_VARIANT (pointed_to_2));
- t1 = build_pointer_type (c_build_qualified_type
- (target,
- TYPE_QUALS (pointed_to_1) |
+ t1 = build_pointer_type (c_build_qualified_type
+ (target,
+ TYPE_QUALS (pointed_to_1) |
TYPE_QUALS (pointed_to_2)));
return build_type_attribute_variant (t1, attributes);
}
-#if 0
- t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
- return build_type_attribute_variant (t1, attributes);
-#endif
case ARRAY_TYPE:
{
TREE_VALUE (n) = TREE_VALUE (p1);
goto parm_done;
}
-
+
/* Given wait (union {union wait *u; int *i} *)
and wait (union wait *),
prefer union wait * as type of parm. */
but a warning may be needed if you use them together. */
int
-comptypes (type1, type2)
- tree type1, type2;
+comptypes (tree type1, tree type2)
{
tree t1 = type1;
tree t2 = type2;
&& TYPE_DOMAIN (t2) != 0)
t2 = TYPE_DOMAIN (t2);
- /* Treat an enum type as the integer type of the same width and
+ /* Treat an enum type as the integer type of the same width and
signedness. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
+ t1 = c_common_type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
if (TREE_CODE (t2) == ENUMERAL_TYPE)
- t2 = type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2));
+ t2 = c_common_type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2));
if (t1 == t2)
return 1;
}
case RECORD_TYPE:
- if (maybe_objc_comptypes (t1, t2, 0) == 1)
+ if (flag_objc && objc_comptypes (t1, t2, 0) == 1)
val = 1;
break;
+ case VECTOR_TYPE:
+ /* The target might allow certain vector types to be compatible. */
+ val = (*targetm.vector_opaque_p) (t1)
+ || (*targetm.vector_opaque_p) (t2);
+ break;
+
default:
break;
}
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. */
+ ignoring their qualifiers. REFLEXIVE is only used by ObjC - set it
+ to 1 or 0 depending if the check of the pointer types is meant to
+ be reflexive or not (typically, assignments are not reflexive,
+ while comparisons are reflexive).
+*/
static int
-comp_target_types (ttl, ttr)
- tree ttl, ttr;
+comp_target_types (tree ttl, tree ttr, int reflexive)
{
int val;
- /* Give maybe_objc_comptypes a crack at letting these types through. */
- if ((val = maybe_objc_comptypes (ttl, ttr, 1)) >= 0)
+ /* Give objc_comptypes a crack at letting these types through. */
+ if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
return val;
val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
/* Return 1 if two function types F1 and F2 are compatible.
If either type specifies no argument types,
the other must specify a fixed number of self-promoting arg types.
- Otherwise, if one type specifies only the number of arguments,
+ Otherwise, if one type specifies only the number of arguments,
the other must specify that number of self-promoting arg types.
Otherwise, the argument types must match. */
static int
-function_types_compatible_p (f1, f2)
- tree f1, f2;
+function_types_compatible_p (tree f1, tree f2)
{
tree args1, args2;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
int val1;
-
- if (!(TREE_TYPE (f1) == TREE_TYPE (f2)
- || (val = comptypes (TREE_TYPE (f1), TREE_TYPE (f2)))))
+ tree ret1, ret2;
+
+ ret1 = TREE_TYPE (f1);
+ ret2 = TREE_TYPE (f2);
+
+ /* 'volatile' qualifiers on a function's return type mean the function
+ is noreturn. */
+ if (pedantic && TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2))
+ pedwarn ("function return types not compatible due to `volatile'");
+ if (TYPE_VOLATILE (ret1))
+ ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1),
+ TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
+ if (TYPE_VOLATILE (ret2))
+ ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
+ TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
+ val = comptypes (ret1, ret2);
+ if (val == 0)
return 0;
args1 = TYPE_ARG_TYPES (f1);
or 2 for compatible with warning. */
static int
-type_lists_compatible_p (args1, args2)
- tree args1, args2;
+type_lists_compatible_p (tree args1, tree args2)
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
So match anything that self-promotes. */
if (TREE_VALUE (args1) == 0)
{
- if (simple_type_promotes_to (TREE_VALUE (args2)) != NULL_TREE)
+ if (c_type_promotes_to (TREE_VALUE (args2)) != TREE_VALUE (args2))
return 0;
}
else if (TREE_VALUE (args2) == 0)
{
- if (simple_type_promotes_to (TREE_VALUE (args1)) != NULL_TREE)
+ if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
return 0;
}
- else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
+ else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
{
/* Allow wait (union {union wait *u; int *i} *)
}
}
\f
-/* Compute the value of the `sizeof' operator. */
-
-tree
-c_sizeof (type)
- tree type;
-{
- enum tree_code code = TREE_CODE (type);
- tree size;
-
- if (code == FUNCTION_TYPE)
- {
- if (pedantic || warn_pointer_arith)
- pedwarn ("sizeof applied to a function type");
- size = size_one_node;
- }
- else if (code == VOID_TYPE)
- {
- if (pedantic || warn_pointer_arith)
- pedwarn ("sizeof applied to a void type");
- size = size_one_node;
- }
- else if (code == ERROR_MARK)
- size = size_one_node;
- else if (!COMPLETE_TYPE_P (type))
- {
- error ("sizeof applied to an incomplete type");
- size = size_zero_node;
- }
- else
- /* Convert in case a char is more than one unit. */
- size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
- size_int (TYPE_PRECISION (char_type_node)
- / BITS_PER_UNIT));
-
- /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
- TYPE_IS_SIZETYPE means that certain things (like overflow) will
- never happen. However, this node should really have type
- `size_t', which is just a typedef for an ordinary integer type. */
- return fold (build1 (NOP_EXPR, c_size_type_node, size));
-}
-
-tree
-c_sizeof_nowarn (type)
- tree type;
-{
- enum tree_code code = TREE_CODE (type);
- tree size;
-
- if (code == FUNCTION_TYPE || code == VOID_TYPE || code == ERROR_MARK)
- size = size_one_node;
- else if (!COMPLETE_TYPE_P (type))
- size = size_zero_node;
- else
- /* Convert in case a char is more than one unit. */
- size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
- size_int (TYPE_PRECISION (char_type_node)
- / BITS_PER_UNIT));
-
- /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
- TYPE_IS_SIZETYPE means that certain things (like overflow) will
- never happen. However, this node should really have type
- `size_t', which is just a typedef for an ordinary integer type. */
- return fold (build1 (NOP_EXPR, c_size_type_node, size));
-}
-
/* Compute the size to increment a pointer by. */
tree
-c_size_in_bytes (type)
- tree type;
+c_size_in_bytes (tree type)
{
enum tree_code code = TREE_CODE (type);
/* Return either DECL or its known constant value (if it has one). */
tree
-decl_constant_value (decl)
- tree decl;
+decl_constant_value (tree decl)
{
if (/* Don't change a variable array bound or initial value to a constant
in a place where a variable is invalid. */
right test for avoiding misoptimizations either. */
static tree
-decl_constant_value_for_broken_optimization (decl)
- tree decl;
+decl_constant_value_for_broken_optimization (tree decl)
{
if (pedantic || DECL_MODE (decl) == BLKmode)
return decl;
return decl_constant_value (decl);
}
-/* Perform default promotions for C data used in expressions.
- Arrays and functions are converted to pointers;
- enumeral types or short or char, to int.
- In addition, manifest constants symbols are replaced by their values. */
-tree
-default_conversion (exp)
- tree exp;
+/* Perform the default conversion of arrays and functions to pointers.
+ Return the result of converting EXP. For any other expression, just
+ return EXP. */
+
+static tree
+default_function_array_conversion (tree exp)
{
+ tree orig_exp;
tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (type);
-
- /* Constants can be used directly unless they're not loadable. */
- if (TREE_CODE (exp) == CONST_DECL)
- exp = DECL_INITIAL (exp);
-
- /* Replace a nonvolatile const static variable with its value unless
- it is an array, in which case we must be sure that taking the
- address of the array produces consistent results. */
- else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
- {
- exp = decl_constant_value_for_broken_optimization (exp);
- type = TREE_TYPE (exp);
- }
+ int not_lvalue = 0;
/* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
- an lvalue.
+ an lvalue.
Do not use STRIP_NOPS here! It will remove conversions from pointer
to integer and cause infinite recursion. */
+ orig_exp = exp;
while (TREE_CODE (exp) == NON_LVALUE_EXPR
|| (TREE_CODE (exp) == NOP_EXPR
&& TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
- exp = TREE_OPERAND (exp, 0);
-
- /* Normally convert enums to int,
- but convert wide enums to something wider. */
- if (code == ENUMERAL_TYPE)
- {
- type = type_for_size (MAX (TYPE_PRECISION (type),
- TYPE_PRECISION (integer_type_node)),
- ((flag_traditional
- || (TYPE_PRECISION (type)
- >= TYPE_PRECISION (integer_type_node)))
- && TREE_UNSIGNED (type)));
-
- return convert (type, exp);
- }
-
- if (TREE_CODE (exp) == COMPONENT_REF
- && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
- /* If it's thinner than an int, promote it like a
- c_promoting_integer_type_p, otherwise leave it alone. */
- && 0 > compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
- TYPE_PRECISION (integer_type_node)))
- return convert (flag_traditional && TREE_UNSIGNED (type)
- ? unsigned_type_node : integer_type_node,
- exp);
-
- if (c_promoting_integer_type_p (type))
{
- /* Traditionally, unsignedness is preserved in default promotions.
- Also preserve unsignedness if not really getting any wider. */
- if (TREE_UNSIGNED (type)
- && (flag_traditional
- || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
- return convert (unsigned_type_node, exp);
-
- return convert (integer_type_node, exp);
+ if (TREE_CODE (exp) == NON_LVALUE_EXPR)
+ not_lvalue = 1;
+ exp = TREE_OPERAND (exp, 0);
}
- if (flag_traditional && !flag_allow_single_precision
- && TYPE_MAIN_VARIANT (type) == float_type_node)
- return convert (double_type_node, exp);
+ /* Preserve the original expression code. */
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
+ C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
- if (code == VOID_TYPE)
- {
- error ("void value not ignored as it ought to be");
- return error_mark_node;
- }
if (code == FUNCTION_TYPE)
{
return build_unary_op (ADDR_EXPR, exp, 0);
tree ptrtype;
int constp = 0;
int volatilep = 0;
+ int lvalue_array_p;
if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
{
}
if (TYPE_QUALS (type) || constp || volatilep)
- restype
+ restype
= c_build_qualified_type (restype,
- TYPE_QUALS (type)
+ TYPE_QUALS (type)
| (constp * TYPE_QUAL_CONST)
| (volatilep * TYPE_QUAL_VOLATILE));
TREE_OPERAND (exp, 0), op1);
}
- if (! lvalue_p (exp)
- && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
+ lvalue_array_p = !not_lvalue && lvalue_p (exp);
+ if (!flag_isoc99 && !lvalue_array_p)
{
- error ("invalid use of non-lvalue array");
- return error_mark_node;
+ /* Before C99, non-lvalue arrays do not decay to pointers.
+ Normally, using such an array would be invalid; but it can
+ be used correctly inside sizeof or as a statement expression.
+ Thus, do not give an error here; an error will result later. */
+ return exp;
}
ptrtype = build_pointer_type (restype);
is not the target type of the type of the ADDR_EXPR itself.
Question is, can this lossage be avoided? */
adr = build1 (ADDR_EXPR, ptrtype, exp);
- if (mark_addressable (exp) == 0)
+ if (!c_mark_addressable (exp))
return error_mark_node;
TREE_CONSTANT (adr) = staticp (exp);
TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
}
return exp;
}
+
+/* Perform default promotions for C data used in expressions.
+ Arrays and functions are converted to pointers;
+ enumeral types or short or char, to int.
+ In addition, manifest constants symbols are replaced by their values. */
+
+tree
+default_conversion (tree exp)
+{
+ tree orig_exp;
+ tree type = TREE_TYPE (exp);
+ enum tree_code code = TREE_CODE (type);
+
+ if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
+ return default_function_array_conversion (exp);
+
+ /* Constants can be used directly unless they're not loadable. */
+ if (TREE_CODE (exp) == CONST_DECL)
+ exp = DECL_INITIAL (exp);
+
+ /* Replace a nonvolatile const static variable with its value unless
+ it is an array, in which case we must be sure that taking the
+ address of the array produces consistent results. */
+ else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
+ {
+ exp = decl_constant_value_for_broken_optimization (exp);
+ type = TREE_TYPE (exp);
+ }
+
+ /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
+ an lvalue.
+
+ Do not use STRIP_NOPS here! It will remove conversions from pointer
+ to integer and cause infinite recursion. */
+ orig_exp = exp;
+ while (TREE_CODE (exp) == NON_LVALUE_EXPR
+ || (TREE_CODE (exp) == NOP_EXPR
+ && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
+ exp = TREE_OPERAND (exp, 0);
+
+ /* Preserve the original expression code. */
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
+ C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
+
+ /* Normally convert enums to int,
+ but convert wide enums to something wider. */
+ if (code == ENUMERAL_TYPE)
+ {
+ type = c_common_type_for_size (MAX (TYPE_PRECISION (type),
+ TYPE_PRECISION (integer_type_node)),
+ ((TYPE_PRECISION (type)
+ >= TYPE_PRECISION (integer_type_node))
+ && TREE_UNSIGNED (type)));
+
+ return convert (type, exp);
+ }
+
+ if (TREE_CODE (exp) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
+ /* If it's thinner than an int, promote it like a
+ c_promoting_integer_type_p, otherwise leave it alone. */
+ && 0 > compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
+ TYPE_PRECISION (integer_type_node)))
+ return convert (integer_type_node, exp);
+
+ if (c_promoting_integer_type_p (type))
+ {
+ /* Preserve unsignedness if not really getting any wider. */
+ if (TREE_UNSIGNED (type)
+ && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ return convert (unsigned_type_node, exp);
+
+ return convert (integer_type_node, exp);
+ }
+
+ if (code == VOID_TYPE)
+ {
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+ return exp;
+}
\f
-/* Look up component name in the structure type definition.
+/* Look up COMPONENT in a structure or union DECL.
+
+ If the component name is not found, returns NULL_TREE. Otherwise,
+ the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
+ stepping down the chain to the component, which is in the last
+ TREE_VALUE of the list. Normally the list is of length one, but if
+ the component is embedded within (nested) anonymous structures or
+ unions, the list steps down the chain to the component. */
- If this component name is found indirectly within an anonymous union,
- store in *INDIRECT the component which directly contains
- that anonymous union. Otherwise, set *INDIRECT to 0. */
-
static tree
-lookup_field (type, component, indirect)
- tree type, component;
- tree *indirect;
+lookup_field (tree decl, tree component)
{
+ tree type = TREE_TYPE (decl);
tree field;
/* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
/* Step through all anon unions in linear fashion. */
while (DECL_NAME (field_array[bot]) == NULL_TREE)
{
- tree anon = 0, junk;
-
field = field_array[bot++];
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
- anon = lookup_field (TREE_TYPE (field), component, &junk);
-
- if (anon != NULL_TREE)
{
- *indirect = field;
- return anon;
+ tree anon = lookup_field (field, component);
+
+ if (anon)
+ return tree_cons (NULL_TREE, field, anon);
}
}
if (DECL_NAME (field_array[bot]) == component)
field = field_array[bot];
else if (DECL_NAME (field) != component)
- field = 0;
+ return NULL_TREE;
}
else
{
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
- if (DECL_NAME (field) == NULL_TREE)
+ if (DECL_NAME (field) == NULL_TREE
+ && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
{
- tree junk;
- tree anon = 0;
+ tree anon = lookup_field (field, component);
- if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
- anon = lookup_field (TREE_TYPE (field), component, &junk);
-
- if (anon != NULL_TREE)
- {
- *indirect = field;
- return anon;
- }
+ if (anon)
+ return tree_cons (NULL_TREE, field, anon);
}
if (DECL_NAME (field) == component)
break;
}
+
+ if (field == NULL_TREE)
+ return NULL_TREE;
}
- *indirect = NULL_TREE;
- return field;
+ return tree_cons (NULL_TREE, field, NULL_TREE);
}
/* Make an expression to refer to the COMPONENT field of
structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. */
tree
-build_component_ref (datum, component)
- tree datum, component;
+build_component_ref (tree datum, tree component)
{
tree type = TREE_TYPE (datum);
enum tree_code code = TREE_CODE (type);
tree field = NULL;
tree ref;
- /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
- unless we are not to support things not strictly ANSI. */
+ /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
+ If pedantic ensure that the arguments are not lvalues; otherwise,
+ if the component is an array, it would wrongly decay to a pointer in
+ C89 mode.
+ We cannot do this with a COND_EXPR, because in a conditional expression
+ the default promotions are applied to both sides, and this would yield
+ the wrong type of the result; for example, if the components have
+ type "char". */
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
{
tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
return build (COMPOUND_EXPR, TREE_TYPE (value),
- TREE_OPERAND (datum, 0), value);
+ TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
}
- case COND_EXPR:
- return build_conditional_expr
- (TREE_OPERAND (datum, 0),
- build_component_ref (TREE_OPERAND (datum, 1), component),
- build_component_ref (TREE_OPERAND (datum, 2), component));
-
default:
break;
}
if (code == RECORD_TYPE || code == UNION_TYPE)
{
- tree indirect = 0;
-
if (!COMPLETE_TYPE_P (type))
{
- incomplete_type_error (NULL_TREE, type);
+ c_incomplete_type_error (NULL_TREE, type);
return error_mark_node;
}
- field = lookup_field (type, component, &indirect);
+ field = lookup_field (datum, component);
if (!field)
{
IDENTIFIER_POINTER (component));
return error_mark_node;
}
- if (TREE_TYPE (field) == error_mark_node)
- return error_mark_node;
- /* If FIELD was found buried within an anonymous union,
- make one COMPONENT_REF to get that anonymous union,
- then fall thru to make a second COMPONENT_REF to get FIELD. */
- if (indirect != 0)
+ /* Chain the COMPONENT_REFs if necessary down to the FIELD.
+ This might be better solved in future the way the C++ front
+ end does it - by giving the anonymous entities each a
+ separate name and type, and then have build_component_ref
+ recursively call itself. We can't do that here. */
+ do
{
- ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect);
- if (TREE_READONLY (datum) || TREE_READONLY (indirect))
+ tree subdatum = TREE_VALUE (field);
+
+ if (TREE_TYPE (subdatum) == error_mark_node)
+ return error_mark_node;
+
+ ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum);
+ if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect))
+ if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
TREE_THIS_VOLATILE (ref) = 1;
- datum = ref;
- }
- ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
+ if (TREE_DEPRECATED (subdatum))
+ warn_deprecated_use (subdatum);
- if (TREE_READONLY (datum) || TREE_READONLY (field))
- TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
- TREE_THIS_VOLATILE (ref) = 1;
+ datum = ref;
+
+ field = TREE_CHAIN (field);
+ }
+ while (field);
return ref;
}
ERRORSTRING is the name of the operator to appear in error messages. */
tree
-build_indirect_ref (ptr, errorstring)
- tree ptr;
- const char *errorstring;
+build_indirect_ref (tree ptr, const char *errorstring)
{
tree pointer = default_conversion (ptr);
tree type = TREE_TYPE (pointer);
if (TREE_CODE (type) == POINTER_TYPE)
{
if (TREE_CODE (pointer) == ADDR_EXPR
- && !flag_volatile
&& (TREE_TYPE (TREE_OPERAND (pointer, 0))
== TREE_TYPE (type)))
return TREE_OPERAND (pointer, 0);
to change it via some other pointer. */
TREE_READONLY (ref) = TYPE_READONLY (t);
TREE_SIDE_EFFECTS (ref)
- = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
+ = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
return ref;
}
by functions). */
tree
-build_array_ref (array, index)
- tree array, index;
+build_array_ref (tree array, tree index)
{
if (index == 0)
{
|| (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array)))
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))
{
- if (mark_addressable (array) == 0)
+ if (!c_mark_addressable (array))
return error_mark_node;
}
/* An array that is indexed by a constant value which is not within
&& TYPE_VALUES (TREE_TYPE (array))
&& ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array))))
{
- if (mark_addressable (array) == 0)
+ if (!c_mark_addressable (array))
return error_mark_node;
}
if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
pedwarn ("ISO C forbids subscripting `register' array");
else if (! flag_isoc99 && ! lvalue_p (foo))
- pedwarn ("ISO C89 forbids subscripting non-lvalue array");
+ pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
TREE_THIS_VOLATILE (rval)
|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
/* This was added by rms on 16 Nov 91.
- It fixes vol struct foo *a; a->elts[1]
+ It fixes vol struct foo *a; a->elts[1]
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
}
}
\f
+/* Issue an error message for a reference to an undeclared variable ID,
+ including a reference to a builtin outside of function-call context.
+ Arrange to suppress further errors for the same identifier. */
+static void
+undeclared_variable (tree id)
+{
+ if (current_function_decl == 0)
+ {
+ error ("`%s' undeclared here (not in a function)",
+ IDENTIFIER_POINTER (id));
+ IDENTIFIER_SYMBOL_VALUE (id) = error_mark_node;
+ }
+ else
+ {
+ error ("`%s' undeclared (first use in this function)",
+ IDENTIFIER_POINTER (id));
+
+ if (! undeclared_variable_notice)
+ {
+ error ("(Each undeclared identifier is reported only once");
+ error ("for each function it appears in.)");
+ undeclared_variable_notice = 1;
+ }
+
+ /* Set IDENTIFIER_SYMBOL_VALUE (id) to error_mark_node
+ at function scope. This suppresses further warnings
+ about this undeclared identifier in this function. */
+ pushdecl_function_level (error_mark_node, id);
+ }
+}
+
/* Build an external reference to identifier ID. FUN indicates
whether this will be used for a function call. */
tree
-build_external_ref (id, fun)
- tree id;
- int fun;
+build_external_ref (tree id, int fun)
{
tree ref;
tree decl = lookup_name (id);
tree objc_ivar = lookup_objc_ivar (id);
- if (!decl || decl == error_mark_node || C_DECL_ANTICIPATED (decl))
- {
- if (objc_ivar)
- ref = objc_ivar;
- else if (fun)
- {
- if (!decl || decl == error_mark_node)
- /* Ordinary implicit function declaration. */
- ref = implicitly_declare (id);
- else
- {
- /* Implicit declaration of built-in function. Don't
- change the built-in declaration, but don't let this
- go by silently, either. */
- implicit_decl_warning (id);
-
- /* only issue this warning once */
- C_DECL_ANTICIPATED (decl) = 0;
- ref = decl;
- }
- }
- else
- {
- /* Reference to undeclared variable, including reference to
- builtin outside of function-call context. */
- if (current_function_decl == 0)
- error ("`%s' undeclared here (not in a function)",
- IDENTIFIER_POINTER (id));
- else
- {
- if (IDENTIFIER_GLOBAL_VALUE (id) != error_mark_node
- || IDENTIFIER_ERROR_LOCUS (id) != current_function_decl)
- {
- error ("`%s' undeclared (first use in this function)",
- IDENTIFIER_POINTER (id));
-
- if (! undeclared_variable_notice)
- {
- error ("(Each undeclared identifier is reported only once");
- error ("for each function it appears in.)");
- undeclared_variable_notice = 1;
- }
- }
- IDENTIFIER_GLOBAL_VALUE (id) = error_mark_node;
- IDENTIFIER_ERROR_LOCUS (id) = current_function_decl;
- }
- return error_mark_node;
- }
- }
- else
+ if (decl && decl != error_mark_node)
{
/* Properly declared variable or function reference. */
if (!objc_ivar)
ref = decl;
- else if (decl != objc_ivar && IDENTIFIER_LOCAL_VALUE (id))
+ else if (decl != objc_ivar && DECL_CONTEXT (decl) != 0)
{
warning ("local declaration of `%s' hides instance variable",
IDENTIFIER_POINTER (id));
else
ref = objc_ivar;
}
+ else if (objc_ivar)
+ ref = objc_ivar;
+ else if (fun)
+ /* Implicit function declaration. */
+ ref = implicitly_declare (id);
+ else if (decl == error_mark_node)
+ /* Don't complain about something that's already been
+ complained about. */
+ return error_mark_node;
+ else
+ {
+ undeclared_variable (id);
+ return error_mark_node;
+ }
if (TREE_TYPE (ref) == error_mark_node)
return error_mark_node;
- assemble_external (ref);
+ if (TREE_DEPRECATED (ref))
+ warn_deprecated_use (ref);
+
+ if (!skip_evaluation)
+ assemble_external (ref);
TREE_USED (ref) = 1;
if (TREE_CODE (ref) == CONST_DECL)
ref = DECL_INITIAL (ref);
TREE_CONSTANT (ref) = 1;
}
+ else if (current_function_decl != 0
+ && DECL_CONTEXT (current_function_decl) != 0
+ && (TREE_CODE (ref) == VAR_DECL
+ || TREE_CODE (ref) == PARM_DECL
+ || TREE_CODE (ref) == FUNCTION_DECL))
+ {
+ tree context = decl_function_context (ref);
+
+ if (context != 0 && context != current_function_decl)
+ DECL_NONLOCAL (ref) = 1;
+ }
return ref;
}
FUNCTION's data type may be a function type or a pointer-to-function. */
tree
-build_function_call (function, params)
- tree function, params;
+build_function_call (tree function, tree params)
{
tree fntype, fundecl = 0;
tree coerced_params;
- tree name = NULL_TREE, assembler_name = NULL_TREE, result;
+ tree name = NULL_TREE, result;
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
if (TREE_CODE (function) == FUNCTION_DECL)
{
name = DECL_NAME (function);
- assembler_name = DECL_ASSEMBLER_NAME (function);
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
return error_mark_node;
}
+ if (fundecl && TREE_THIS_VOLATILE (fundecl))
+ current_function_returns_abnormally = 1;
+
/* fntype now gets the type of function pointed to. */
fntype = TREE_TYPE (fntype);
coerced_params
= convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
- /* Check for errors in format strings. */
+ /* Check that the arguments to the function are valid. */
- if (warn_format)
- check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
+ check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
with the elements of the list in the TREE_VALUE slots of those nodes. */
static tree
-convert_arguments (typelist, values, name, fundecl)
- tree typelist, values, name, fundecl;
+convert_arguments (tree typelist, tree values, tree name, tree fundecl)
{
tree typetail, valtail;
tree result = NULL;
if (TREE_CODE (val) == NON_LVALUE_EXPR)
val = TREE_OPERAND (val, 0);
- if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)
- val = default_conversion (val);
+ val = default_function_array_conversion (val);
val = require_complete_type (val);
&& TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST
&& int_fits_type_p (TREE_OPERAND (val, 0), type))
;
-#if 0 /* We never get such tree structure here. */
- else if (TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE
- && int_fits_type_p (TYPE_MIN_VALUE (TREE_TYPE (val)), type)
- && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (val)), type))
- /* Change in signedness doesn't matter
- if an enum value is unaffected. */
- ;
-#endif
/* If the value is extended from a narrower
unsigned type, it doesn't matter whether we
pass it as signed or unsigned; the value
}
}
- parmval = convert_for_assignment (type, val,
+ parmval = convert_for_assignment (type, val,
(char *) 0, /* arg passing */
fundecl, name, parmnum + 1);
-
+
if (PROMOTE_PROTOTYPES
&& INTEGRAL_TYPE_P (type)
&& (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
in a way that is likely to confuse the user. */
tree
-parser_build_binary_op (code, arg1, arg2)
- enum tree_code code;
- tree arg1, arg2;
+parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
{
tree result = build_binary_op (code, arg1, arg2, 1);
enum tree_code code1 = ERROR_MARK;
enum tree_code code2 = ERROR_MARK;
+ if (TREE_CODE (result) == ERROR_MARK)
+ return error_mark_node;
+
if (IS_EXPR_CODE_CLASS (class1))
code1 = C_EXP_ORIGINAL_CODE (arg1);
if (IS_EXPR_CODE_CLASS (class2))
the arithmetic is to be done. */
tree
-build_binary_op (code, orig_op0, orig_op1, convert_p)
- enum tree_code code;
- tree orig_op0, orig_op1;
- int convert_p;
+build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, int convert_p)
{
tree type0, type1;
enum tree_code code0, code1;
/* Subtraction of two similar pointers.
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
- && comp_target_types (type0, type1))
+ && comp_target_types (type0, type1, 1))
return pointer_diff (op0, op1);
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
warning ("division by zero");
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE)
+ || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE))
+ || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
case BIT_XOR_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
shorten = -1;
- /* If one operand is a constant, and the other is a short type
- that has been converted to an int,
- really do the work in the short type and then convert the
- result to int. If we are lucky, the constant will be 0 or 1
- in the short type, making the entire operation go away. */
- if (TREE_CODE (op0) == INTEGER_CST
- && TREE_CODE (op1) == NOP_EXPR
- && TYPE_PRECISION (type1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
- {
- final_type = result_type;
- op1 = TREE_OPERAND (op1, 0);
- result_type = TREE_TYPE (op1);
- }
- if (TREE_CODE (op1) == INTEGER_CST
- && TREE_CODE (op0) == NOP_EXPR
- && TYPE_PRECISION (type0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
- {
- final_type = result_type;
- op0 = TREE_OPERAND (op0, 0);
- result_type = TREE_TYPE (op0);
- }
+ else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ common = 1;
break;
case TRUNC_MOD_EXPR:
but that does not mean the operands should be
converted to ints! */
result_type = integer_type_node;
- op0 = truthvalue_conversion (op0);
- op1 = truthvalue_conversion (op1);
+ op0 = c_common_truthvalue_conversion (op0);
+ op1 = c_common_truthvalue_conversion (op1);
converted = 1;
}
break;
}
}
- /* Use the type of the value to be shifted.
- This is what most traditional C compilers do. */
+ /* Use the type of the value to be shifted. */
result_type = type0;
- /* Unless traditional, convert the shift-count to an integer,
- regardless of size of value being shifted. */
- if (! flag_traditional)
- {
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
- /* Avoid converting op1 to result_type later. */
- converted = 1;
- }
+ /* Convert the shift-count to an integer, regardless of size
+ of value being shifted. */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ /* Avoid converting op1 to result_type later. */
+ converted = 1;
}
break;
warning ("left shift count >= width of type");
}
- /* Use the type of the value to be shifted.
- This is what most traditional C compilers do. */
+ /* Use the type of the value to be shifted. */
result_type = type0;
- /* Unless traditional, convert the shift-count to an integer,
- regardless of size of value being shifted. */
- if (! flag_traditional)
- {
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
- /* Avoid converting op1 to result_type later. */
- converted = 1;
- }
+ /* Convert the shift-count to an integer, regardless of size
+ of value being shifted. */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ /* Avoid converting op1 to result_type later. */
+ converted = 1;
}
break;
warning ("shift count >= width of type");
}
- /* Use the type of the value to be shifted.
- This is what most traditional C compilers do. */
+ /* Use the type of the value to be shifted. */
result_type = type0;
- /* Unless traditional, convert the shift-count to an integer,
- regardless of size of value being shifted. */
- if (! flag_traditional)
- {
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
- /* Avoid converting op1 to result_type later. */
- converted = 1;
- }
+ /* Convert the shift-count to an integer, regardless of size
+ of value being shifted. */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ /* Avoid converting op1 to result_type later. */
+ converted = 1;
}
break;
but don't convert the args to int! */
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE)
+ || code0 == COMPLEX_TYPE
+ || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE))
+ || code1 == COMPLEX_TYPE
+ || code1 == VECTOR_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
result_type = common_type (type0, type1);
else if (VOID_TYPE_P (tt0))
{
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- if (! flag_traditional)
- pedwarn ("comparison between pointer and integer");
+ pedwarn ("comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- if (! flag_traditional)
- pedwarn ("comparison between pointer and integer");
+ pedwarn ("comparison between pointer and integer");
}
break;
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
{
result_type = common_type (type0, type1);
- if (pedantic
+ if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
}
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1))
+ if (comp_target_types (type0, type1, 1))
{
result_type = common_type (type0, type1);
if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
!= !COMPLETE_TYPE_P (TREE_TYPE (type1)))
pedwarn ("comparison of complete and incomplete pointers");
- else if (pedantic
+ else if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- if (! flag_traditional)
- pedwarn ("comparison between pointer and integer");
+ pedwarn ("comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- if (! flag_traditional)
- pedwarn ("comparison between pointer and integer");
+ pedwarn ("comparison between pointer and integer");
}
break;
break;
}
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
+ || code0 == VECTOR_TYPE)
&&
- (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+ (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+ || code1 == VECTOR_TYPE))
{
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
&& unsigned0 == unsigned1
&& (unsigned0 || !uns))
result_type
- = signed_or_unsigned_type (unsigned0,
- common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ = c_common_signed_or_unsigned_type
+ (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
< TYPE_PRECISION (result_type))
- && (type = signed_or_unsigned_type (unsigned1,
- TREE_TYPE (arg1)),
+ && (type
+ = c_common_signed_or_unsigned_type (unsigned1,
+ TREE_TYPE (arg1)),
int_fits_type_p (arg0, type)))
result_type = type;
else if (TREE_CODE (arg1) == INTEGER_CST
&& (unsigned0 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg0))
< TYPE_PRECISION (result_type))
- && (type = signed_or_unsigned_type (unsigned0,
- TREE_TYPE (arg0)),
+ && (type
+ = c_common_signed_or_unsigned_type (unsigned0,
+ TREE_TYPE (arg0)),
int_fits_type_p (arg1, type)))
result_type = type;
}
{
/* Do an unsigned shift if the operand was zero-extended. */
result_type
- = signed_or_unsigned_type (unsigned_arg, TREE_TYPE (arg0));
+ = c_common_signed_or_unsigned_type (unsigned_arg,
+ TREE_TYPE (arg0));
/* Convert value-to-be-shifted to that type. */
if (TREE_TYPE (op0) != result_type)
op0 = convert (result_type, op0);
pass the copies by reference, then copy them back afterward. */
tree xop0 = op0, xop1 = op1, xresult_type = result_type;
enum tree_code xresultcode = resultcode;
- tree val
+ tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
converted = 1;
resultcode = xresultcode;
- if ((warn_sign_compare < 0 ? extra_warnings : warn_sign_compare != 0)
- && skip_evaluation == 0)
+ if (warn_sign_compare && skip_evaluation == 0)
{
int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
STRIP_TYPE_NOPS (xop1);
/* Give warnings for comparisons between signed and unsigned
- quantities that may fail.
+ quantities that may fail.
Do the checking based on the original operand trees, so that
casts will be considered, but default promotions won't be.
constant expression involving such literals or a
conditional expression involving such literals)
and it is non-negative. */
- if (tree_expr_nonnegative_p (sop))
+ if (c_tree_expr_nonnegative_p (sop))
/* OK */;
/* Do not warn if the comparison is an equality operation,
the unsigned quantity is an integral constant, and it
would fit in the result if the result were signed. */
else if (TREE_CODE (uop) == INTEGER_CST
&& (resultcode == EQ_EXPR || resultcode == NE_EXPR)
- && int_fits_type_p (uop, signed_type (result_type)))
+ && int_fits_type_p
+ (uop, c_common_signed_type (result_type)))
/* OK */;
/* Do not warn if the unsigned quantity is an enumeration
constant and its maximum value would fit in the result
if the result were signed. */
else if (TREE_CODE (uop) == INTEGER_CST
&& TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
- && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE(uop)),
- signed_type (result_type)))
+ && int_fits_type_p
+ (TYPE_MAX_VALUE (TREE_TYPE(uop)),
+ c_common_signed_type (result_type)))
/* OK */;
else
warning ("comparison between signed and unsigned");
else
primop1 = get_narrower (TREE_OPERAND (primop1, 0),
&unsignedp1);
-
+
if (host_integerp (primop0, 0) || host_integerp (primop1, 0))
{
tree primop;
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = convert (result_type, op1);
}
if (build_type == NULL_TREE)
}
}
\f
-/* Return a tree for the sum or difference (RESULTCODE says which)
- of pointer PTROP and integer INTOP. */
-
-static tree
-pointer_int_sum (resultcode, ptrop, intop)
- enum tree_code resultcode;
- tree ptrop, intop;
-{
- tree size_exp;
-
- tree result;
- tree folded;
- /* The result is a pointer of the same type that is being added. */
+/* Return true if `t' is known to be non-negative. */
- tree result_type = TREE_TYPE (ptrop);
-
- if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
- {
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer of type `void *' used in arithmetic");
- size_exp = integer_one_node;
- }
- else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
+int
+c_tree_expr_nonnegative_p (tree t)
+{
+ if (TREE_CODE (t) == STMT_EXPR)
{
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer to a function used in arithmetic");
- size_exp = integer_one_node;
- }
- else
- size_exp = c_size_in_bytes (TREE_TYPE (result_type));
-
- /* If what we are about to multiply by the size of the elements
- contains a constant term, apply distributive law
- and multiply that constant term separately.
- This helps produce common subexpressions. */
-
- if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
- && ! TREE_CONSTANT (intop)
- && TREE_CONSTANT (TREE_OPERAND (intop, 1))
- && TREE_CONSTANT (size_exp)
- /* If the constant comes from pointer subtraction,
- skip this optimization--it would cause an error. */
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
- /* If the constant is unsigned, and smaller than the pointer size,
- then we must skip this optimization. This is because it could cause
- an overflow error if the constant is negative but INTOP is not. */
- && (! TREE_UNSIGNED (TREE_TYPE (intop))
- || (TYPE_PRECISION (TREE_TYPE (intop))
- == TYPE_PRECISION (TREE_TYPE (ptrop)))))
- {
- enum tree_code subcode = resultcode;
- tree int_type = TREE_TYPE (intop);
- if (TREE_CODE (intop) == MINUS_EXPR)
- subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
- /* Convert both subexpression types to the type of intop,
- because weird cases involving pointer arithmetic
- can result in a sum or difference with different type args. */
- ptrop = build_binary_op (subcode, ptrop,
- convert (int_type, TREE_OPERAND (intop, 1)), 1);
- intop = convert (int_type, TREE_OPERAND (intop, 0));
- }
-
- /* Convert the integer argument to a type the same size as sizetype
- so the multiply won't overflow spuriously. */
-
- if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
- || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
- intop = convert (type_for_size (TYPE_PRECISION (sizetype),
- TREE_UNSIGNED (sizetype)), intop);
-
- /* Replace the integer argument with a suitable product by the object size.
- Do this multiplication as signed, then convert to the appropriate
- pointer type (actually unsigned integral). */
-
- intop = convert (result_type,
- build_binary_op (MULT_EXPR, intop,
- convert (TREE_TYPE (intop), size_exp), 1));
-
- /* Create the sum or difference. */
-
- result = build (resultcode, result_type, ptrop, intop);
+ t = COMPOUND_BODY (STMT_EXPR_STMT (t));
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
- return folded;
+ /* Find the last statement in the chain, ignoring the final
+ * scope statement */
+ while (TREE_CHAIN (t) != NULL_TREE
+ && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
+ t = TREE_CHAIN (t);
+ return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ }
+ return tree_expr_nonnegative_p (t);
}
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
static tree
-pointer_diff (op0, op1)
- tree op0, op1;
+pointer_diff (tree op0, tree op1)
{
tree result, folded;
tree restype = ptrdiff_type_node;
\f
/* Construct and perhaps optimize a tree representation
for a unary operation. CODE, a tree_code, specifies the operation
- and XARG is the operand. NOCONVERT nonzero suppresses
- the default promotions (such as from short to int). */
+ and XARG is the operand.
+ For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
+ the default promotions (such as from short to int).
+ For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
+ allows non-lvalues; this is only used to handle conversion of non-lvalue
+ arrays to pointers in C99. */
tree
-build_unary_op (code, xarg, noconvert)
- enum tree_code code;
- tree xarg;
- int noconvert;
+build_unary_op (enum tree_code code, tree xarg, int flag)
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg;
tree argtype = 0;
enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
tree val;
+ int noconvert = flag;
if (typecode == ERROR_MARK)
return error_mark_node;
}
else if (!noconvert)
arg = default_conversion (arg);
+ arg = non_lvalue (arg);
break;
case NEGATE_EXPR:
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
- || typecode == COMPLEX_TYPE))
+ || typecode == COMPLEX_TYPE
+ || typecode == VECTOR_TYPE))
{
error ("wrong type argument to unary minus");
return error_mark_node;
break;
case BIT_NOT_EXPR:
- if (typecode == COMPLEX_TYPE)
+ if (typecode == INTEGER_TYPE || typecode == VECTOR_TYPE)
+ {
+ if (!noconvert)
+ arg = default_conversion (arg);
+ }
+ else if (typecode == COMPLEX_TYPE)
{
code = CONJ_EXPR;
if (pedantic)
if (!noconvert)
arg = default_conversion (arg);
}
- else if (typecode != INTEGER_TYPE)
+ else
{
error ("wrong type argument to bit-complement");
return error_mark_node;
}
- else if (!noconvert)
- arg = default_conversion (arg);
break;
case ABS_EXPR:
error ("wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = truthvalue_conversion (arg);
+ arg = c_common_truthvalue_conversion (arg);
return invert_truthvalue (arg);
case NOP_EXPR:
return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
else
return convert (TREE_TYPE (arg), integer_zero_node);
-
+
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
- val = unary_complex_lvalue (code, arg);
+ val = unary_complex_lvalue (code, arg, 0);
if (val != 0)
return val;
if (typecode != POINTER_TYPE
&& typecode != INTEGER_TYPE && typecode != REAL_TYPE)
{
- error ("wrong type argument to %s",
- code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
- ? "increment" : "decrement");
+ if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+ error ("wrong type argument to increment");
+ else
+ error ("wrong type argument to decrement");
+
return error_mark_node;
}
/* If pointer target is an undefined struct,
we just cannot know how to do the arithmetic. */
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (result_type)))
- error ("%s of pointer to unknown structure",
- code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
- ? "increment" : "decrement");
+ {
+ if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+ error ("increment of pointer to unknown structure");
+ else
+ error ("decrement of pointer to unknown structure");
+ }
else if ((pedantic || warn_pointer_arith)
&& (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
- pedwarn ("wrong type argument to %s",
- code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
- ? "increment" : "decrement");
+ {
+ if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+ pedwarn ("wrong type argument to increment");
+ else
+ pedwarn ("wrong type argument to decrement");
+ }
+
inc = c_size_in_bytes (TREE_TYPE (result_type));
}
else
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
- readonly_warning (arg,
+ readonly_warning (arg,
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"));
}
case ADDR_EXPR:
- /* Note that this operation never does default_conversion
- regardless of NOCONVERT. */
+ /* Note that this operation never does default_conversion. */
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
/* For &x[y], return x+y */
if (TREE_CODE (arg) == ARRAY_REF)
{
- if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
+ if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
return error_mark_node;
return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1), 1);
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
- val = unary_complex_lvalue (code, arg);
+ val = unary_complex_lvalue (code, arg, flag);
if (val != 0)
return val;
-#if 0 /* Turned off because inconsistent;
- float f; *&(int)f = 3.4 stores in int format
- whereas (int)f = 3.4 stores in float format. */
- /* Address of a cast is just a cast of the address
- of the operand of the cast. */
- switch (TREE_CODE (arg))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
- if (pedantic)
- pedwarn ("ISO C forbids the address of a cast expression");
- return convert (build_pointer_type (TREE_TYPE (arg)),
- build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0),
- 0));
- }
-#endif
-
- /* Allow the address of a constructor if all the elements
- are constant. */
- if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
- ;
/* Anything not already handled and not a true memory reference
- is an error. */
- else if (typecode != FUNCTION_TYPE
+ or a non-lvalue array is an error. */
+ else if (typecode != FUNCTION_TYPE && !flag
&& !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
return error_mark_node;
argtype = build_pointer_type (argtype);
- if (mark_addressable (arg) == 0)
+ if (!c_mark_addressable (arg))
return error_mark_node;
{
{
tree field = TREE_OPERAND (arg, 1);
- addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+ addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
if (DECL_C_BIT_FIELD (field))
{
return fold (build1 (code, argtype, arg));
}
-#if 0
-/* If CONVERSIONS is a conversion expression or a nested sequence of such,
- convert ARG with the same conversions in the same order
- and return the result. */
-
-static tree
-convert_sequence (conversions, arg)
- tree conversions;
- tree arg;
-{
- switch (TREE_CODE (conversions))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
- return convert (TREE_TYPE (conversions),
- convert_sequence (TREE_OPERAND (conversions, 0),
- arg));
-
- default:
- return arg;
- }
-}
-#endif /* 0 */
-
/* Return nonzero if REF is an lvalue valid for this language.
Lvalues can be assigned, unless their type has TYPE_READONLY.
Lvalues can have their address taken, unless they have DECL_REGISTER. */
int
-lvalue_p (ref)
- tree ref;
+lvalue_p (tree ref)
{
enum tree_code code = TREE_CODE (ref);
case COMPONENT_REF:
return lvalue_p (TREE_OPERAND (ref, 0));
+ case COMPOUND_LITERAL_EXPR:
case STRING_CST:
return 1;
otherwise, print an error message and return zero. */
int
-lvalue_or_else (ref, msgid)
- tree ref;
- const char *msgid;
+lvalue_or_else (tree ref, const char *msgid)
{
int win = lvalue_p (ref);
/* Apply unary lvalue-demanding operator CODE to the expression ARG
for certain kinds of expressions which are not really lvalues
- but which we can accept as lvalues.
+ but which we can accept as lvalues. If FLAG is nonzero, then
+ non-lvalues are OK since we may be converting a non-lvalue array to
+ a pointer in C99.
If ARG is not a kind of expression we can handle, return zero. */
-
+
static tree
-unary_complex_lvalue (code, arg)
- enum tree_code code;
- tree arg;
+unary_complex_lvalue (enum tree_code code, tree arg, int flag)
{
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
/* If this returns a function type, it isn't really being used as
an lvalue, so don't issue a warning about it. */
- if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+ if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR);
return build (COMPOUND_EXPR, TREE_TYPE (real_result),
/* Handle (a ? b : c) used as an "lvalue". */
if (TREE_CODE (arg) == COND_EXPR)
{
- pedantic_lvalue_warning (COND_EXPR);
- if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+ if (!flag)
+ pedantic_lvalue_warning (COND_EXPR);
+ if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR);
return (build_conditional_expr
(TREE_OPERAND (arg, 0),
- build_unary_op (code, TREE_OPERAND (arg, 1), 0),
- build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
+ build_unary_op (code, TREE_OPERAND (arg, 1), flag),
+ build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
}
return 0;
COMPOUND_EXPR, or CONVERT_EXPR (for casts). */
static void
-pedantic_lvalue_warning (code)
- enum tree_code code;
+pedantic_lvalue_warning (enum tree_code code)
{
if (pedantic)
switch (code)
/* Warn about storing in something that is `const'. */
void
-readonly_warning (arg, msgid)
- tree arg;
- const char *msgid;
+readonly_warning (tree arg, const char *msgid)
{
if (TREE_CODE (arg) == COMPONENT_REF)
{
\f
/* Mark EXP saying that we need to be able to take the
address of it; it should not be allocated in a register.
- Value is 1 if successful. */
+ Returns true if successful. */
-int
-mark_addressable (exp)
- tree exp;
+bool
+c_mark_addressable (tree exp)
{
tree x = exp;
+
while (1)
switch (TREE_CODE (x))
{
case COMPONENT_REF:
if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
{
- error ("cannot take address of bitfield `%s'",
+ error ("cannot take address of bit-field `%s'",
IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
- return 0;
+ return false;
}
/* ... fall through ... */
x = TREE_OPERAND (x, 0);
break;
+ case COMPOUND_LITERAL_EXPR:
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
- return 1;
+ return true;
case VAR_DECL:
case CONST_DECL:
{
error ("global register variable `%s' used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
- return 0;
+ return false;
}
pedwarn ("register variable `%s' used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
{
error ("address of global register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
- return 0;
+ return false;
}
/* If we are making this addressable due to its having
else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
{
error ("cannot put object with volatile field into register");
- return 0;
+ return false;
}
pedwarn ("address of register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
- put_var_into_stack (x);
+ put_var_into_stack (x, /*rescan=*/true);
/* drops in */
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
-#if 0 /* poplevel deals with this now. */
- if (DECL_CONTEXT (x) == 0)
- TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
-#endif
-
default:
- return 1;
+ return true;
}
}
\f
/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
tree
-build_conditional_expr (ifexp, op1, op2)
- tree ifexp, op1, op2;
+build_conditional_expr (tree ifexp, tree op1, tree op2)
{
tree type1;
tree type2;
tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
- ifexp = truthvalue_conversion (default_conversion (ifexp));
-
-#if 0 /* Produces wrong result if within sizeof. */
- /* Don't promote the operands separately if they promote
- the same way. Return the unpromoted type and let the combined
- value get promoted if necessary. */
-
- if (TREE_TYPE (op1) == TREE_TYPE (op2)
- && TREE_CODE (TREE_TYPE (op1)) != ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (op1)) != ENUMERAL_TYPE
- && TREE_CODE (TREE_TYPE (op1)) != FUNCTION_TYPE)
- {
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
-
- return fold (build (COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2));
- }
-#endif
+ ifexp = c_common_truthvalue_conversion (default_conversion (ifexp));
/* Promote both alternatives. */
code1 = TREE_CODE (type1);
type2 = TREE_TYPE (op2);
code2 = TREE_CODE (type2);
-
+
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
and later code won't know it used to be different.
Do this check on the original types, so that explicit casts
will be considered, but default promotions won't. */
- if ((warn_sign_compare < 0 ? extra_warnings : warn_sign_compare)
- && !skip_evaluation)
+ if (warn_sign_compare && !skip_evaluation)
{
int unsigned_op1 = TREE_UNSIGNED (TREE_TYPE (orig_op1));
int unsigned_op2 = TREE_UNSIGNED (TREE_TYPE (orig_op2));
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
involving such literals) and it is non-negative. */
- else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
- || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
+ else if ((unsigned_op2 && c_tree_expr_nonnegative_p (op1))
+ || (unsigned_op1 && c_tree_expr_nonnegative_p (op2)))
/* OK */;
else
warning ("signed and unsigned type in conditional expression");
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
- if (comp_target_types (type1, type2))
+ if (comp_target_types (type1, type2, 1))
result_type = common_type (type1, type2);
else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
&& TREE_CODE (orig_op1) != NOP_EXPR)
op1 = convert_and_check (result_type, op1);
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
-
+
if (TREE_CODE (ifexp) == INTEGER_CST)
return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
that performs them all and returns the value of the last of them. */
tree
-build_compound_expr (list)
- tree list;
+build_compound_expr (tree list)
{
return internal_build_compound_expr (list, TRUE);
}
static tree
-internal_build_compound_expr (list, first_p)
- tree list;
- int first_p;
+internal_build_compound_expr (tree list, int first_p)
{
tree rest;
if (TREE_CHAIN (list) == 0)
{
- /* Convert arrays to pointers when there really is a comma operator. */
- if (!first_p && TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
- TREE_VALUE (list) = default_conversion (TREE_VALUE (list));
-
-#if 0 /* If something inside inhibited lvalueness, we should not override. */
- /* Consider (x, y+0), which is not an lvalue since y+0 is not. */
-
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- if (TREE_CODE (list) == NON_LVALUE_EXPR)
- list = TREE_OPERAND (list, 0);
-#endif
+ /* Convert arrays and functions to pointers when there
+ really is a comma operator. */
+ if (!first_p)
+ TREE_VALUE (list)
+ = default_function_array_conversion (TREE_VALUE (list));
/* Don't let (0, 0) be null pointer constant. */
if (!first_p && integer_zerop (TREE_VALUE (list)))
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
/* The left-hand operand of a comma expression is like an expression
- statement: with -W or -Wunused, we should warn if it doesn't have
+ statement: with -Wextra or -Wunused, we should warn if it doesn't have
any side-effects, unless it was explicitly cast to (void). */
- if ((extra_warnings || warn_unused_value)
+ if (warn_unused_value
&& ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
warning ("left-hand operand of comma expression has no effect");
/* Build an expression representing a cast to type TYPE of expression EXPR. */
tree
-build_c_cast (type, expr)
- tree type;
- tree expr;
+build_c_cast (tree type, tree expr)
{
tree value = expr;
-
+
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
- type = TYPE_MAIN_VARIANT (type);
-#if 0
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- if (TREE_CODE (value) == NON_LVALUE_EXPR)
- value = TREE_OPERAND (value, 0);
-#endif
+ /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing
+ only in <protocol> qualifications. But when constructing cast expressions,
+ the protocols do matter and must be kept around. */
+ if (!flag_objc || !objc_is_id (type))
+ type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
{
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
- if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
- value = default_conversion (value);
+ value = default_function_array_conversion (value);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
if (field)
{
- const char *name;
tree t;
if (pedantic)
pedwarn ("ISO C forbids casts to union type");
- if (TYPE_NAME (type) != 0)
- {
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- name = IDENTIFIER_POINTER (TYPE_NAME (type));
- else
- name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- }
- else
- name = "";
- t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE,
- build_tree_list (field, value)),
- 0, 0);
+ t = digest_init (type,
+ build_constructor (type,
+ build_tree_list (field, value)),
+ 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
return t;
}
/* Convert functions and arrays to pointers,
but don't convert any other types. */
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE)
- value = default_conversion (value);
+ value = default_function_array_conversion (value);
otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */
{
tree in_type = type;
tree in_otype = otype;
- int warn = 0;
+ int added = 0;
+ int discarded = 0;
/* Check that the qualifiers on IN_TYPE are a superset of
the qualifiers of IN_OTYPE. The outermost level of
{
in_otype = TREE_TYPE (in_otype);
in_type = TREE_TYPE (in_type);
- warn |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+
+ /* GNU C allows cv-qualified function types. 'const'
+ means the function is very pure, 'volatile' means it
+ can't return. We need to warn when such qualifiers
+ are added, not when they're taken away. */
+ if (TREE_CODE (in_otype) == FUNCTION_TYPE
+ && TREE_CODE (in_type) == FUNCTION_TYPE)
+ added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+ else
+ discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
}
while (TREE_CODE (in_type) == POINTER_TYPE
&& TREE_CODE (in_otype) == POINTER_TYPE);
- if (warn)
+ if (added)
+ warning ("cast adds new qualifiers to function type");
+
+ if (discarded)
/* There are qualifiers present in IN_OTYPE that are not
present in IN_TYPE. */
warning ("cast discards qualifiers from pointer target type");
&& !TREE_CONSTANT (value))
warning ("cast to pointer from integer of different size");
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && TREE_CODE (expr) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (expr, 0))
+ && flag_strict_aliasing && warn_strict_aliasing
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ /* Casting the address of a decl to non void pointer. Warn
+ if the cast breaks type based aliasing. */
+ if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
+ warning ("type-punning to incomplete type might break strict-aliasing rules");
+ else if (!alias_sets_conflict_p
+ (get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))),
+ get_alias_set (TREE_TYPE (type))))
+ warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+ }
+
ovalue = value;
+ /* Replace a nonvolatile const static variable with its value. */
+ if (optimize && TREE_CODE (value) == VAR_DECL)
+ value = decl_constant_value (value);
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
/* Interpret a cast of expression EXPR to type TYPE. */
tree
-c_cast_expr (type, expr)
- tree type, expr;
+c_cast_expr (tree type, tree expr)
{
int saved_wsp = warn_strict_prototypes;
Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. */
tree
-build_modify_expr (lhs, modifycode, rhs)
- tree lhs, rhs;
- enum tree_code modifycode;
+build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
{
tree result;
tree newrhs;
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
-
+
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
pedantic_lvalue_warning (COND_EXPR);
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
- if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE)
- newrhs = default_conversion (newrhs);
+ newrhs = default_function_array_conversion (newrhs);
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
pedantic_lvalue_warning (CONVERT_EXPR);
return convert (TREE_TYPE (lhs), result);
}
-
+
default:
break;
}
PARMNUM is the number of the argument, for printing in error messages. */
static tree
-convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
- tree type, rhs;
- const char *errtype;
- tree fundecl, funname;
- int parmnum;
+convert_for_assignment (tree type, tree rhs, const char *errtype, tree fundecl, tree funname, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
tree rhstype;
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
overflow_warning (rhs);
- /* Check for Objective-C protocols. This will issue a warning if
- there are protocol violations. No need to use the return value. */
- maybe_objc_comptypes (type, rhstype, 0);
+ /* Check for Objective-C protocols. This will automatically
+ issue a warning if there are protocol violations. No need to
+ use the return value. */
+ if (flag_objc)
+ objc_comptypes (type, rhstype, 0);
return rhs;
}
error ("void value not ignored as it ought to be");
return error_mark_node;
}
- /* A type converts to a reference to it.
+ /* A type converts to a reference to it.
This code doesn't fully support references, it's just for the
special case of va_start and va_copy. */
if (codel == REFERENCE_TYPE
&& comptypes (TREE_TYPE (type), TREE_TYPE (rhs)) == 1)
{
- if (mark_addressable (rhs) == 0)
+ if (!lvalue_p (rhs))
+ {
+ error ("cannot pass rvalue to reference parameter");
+ return error_mark_node;
+ }
+ if (!c_mark_addressable (rhs))
return error_mark_node;
rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs);
rhs = build1 (NOP_EXPR, type, rhs);
return rhs;
}
+ /* Some types can interconvert without explicit casts. */
+ else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
+ && ((*targetm.vector_opaque_p) (type)
+ || (*targetm.vector_opaque_p) (rhstype)))
+ return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */
- else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
+ else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
|| codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
|| codel == BOOLEAN_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE
|| coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
|| coder == BOOLEAN_TYPE))
return convert_and_check (type, rhs);
Meanwhile, the lhs target must have all the qualifiers of
the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (memb_type, rhstype))
+ || comp_target_types (memb_type, rhstype, 0))
{
/* If this type won't generate any warnings, use it. */
if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
errtype, funname,
parmnum);
}
-
+
if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
pedwarn ("ISO C prohibits argument conversion to union type");
/* Conversions among pointers */
else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
- && (coder == POINTER_TYPE || coder == REFERENCE_TYPE))
+ && (coder == codel))
{
tree ttl = TREE_TYPE (type);
tree ttr = TREE_TYPE (rhstype);
+ bool is_opaque_pointer;
+
+ /* Opaque pointers are treated like void pointers. */
+ is_opaque_pointer = ((*targetm.vector_opaque_p) (type)
+ || (*targetm.vector_opaque_p) (rhstype))
+ && TREE_CODE (ttl) == VECTOR_TYPE
+ && TREE_CODE (ttr) == VECTOR_TYPE;
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (type, rhstype)
- || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
- == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+ || comp_target_types (type, rhstype, 0)
+ || is_opaque_pointer
+ || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
+ == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
{
if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (type, rhstype))
+ || comp_target_types (type, rhstype, 0))
;
/* If there is a mismatch, do warn. */
else if (pedantic)
if (!errtype)
{
if (funname)
- {
- tree selector = maybe_building_objc_message_expr ();
-
- if (selector && parmnum > 2)
- error ("incompatible type for argument %d of `%s'",
+ {
+ tree selector = objc_message_selector ();
+
+ if (selector && parmnum > 2)
+ error ("incompatible type for argument %d of `%s'",
parmnum - 2, IDENTIFIER_POINTER (selector));
- else
+ else
error ("incompatible type for argument %d of `%s'",
parmnum, IDENTIFIER_POINTER (funname));
}
return error_mark_node;
}
+/* Convert VALUE for assignment into inlined parameter PARM. */
+
+tree
+c_convert_parm_for_inlining (tree parm, tree value, tree fn)
+{
+ tree ret, type;
+
+ /* If FN was prototyped, the value has been converted already
+ in convert_arguments. */
+ if (! value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
+ return value;
+
+ type = TREE_TYPE (parm);
+ ret = convert_for_assignment (type, value,
+ (char *) 0 /* arg passing */, fn,
+ DECL_NAME (fn), 0);
+ if (PROMOTE_PROTOTYPES
+ && INTEGRAL_TYPE_P (type)
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ ret = default_conversion (ret);
+ return ret;
+}
+
/* Print a warning using MSGID.
It gets OPNAME as its one parameter.
- If OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
+ if OPNAME is null and ARGNUM is 0, it is replaced by "passing arg of `FUNCTION'".
+ Otherwise if OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
FUNCTION and ARGNUM are handled specially if we are building an
Objective-C selector. */
static void
-warn_for_assignment (msgid, opname, function, argnum)
- const char *msgid;
- const char *opname;
- tree function;
- int argnum;
+warn_for_assignment (const char *msgid, const char *opname, tree function, int argnum)
{
if (opname == 0)
{
- tree selector = maybe_building_objc_message_expr ();
+ tree selector = objc_message_selector ();
char * new_opname;
-
+
if (selector && argnum > 2)
{
function = selector;
argnum -= 2;
}
- if (function)
+ if (argnum == 0)
+ {
+ if (function)
+ {
+ /* Function name is known; supply it. */
+ const char *const argstring = _("passing arg of `%s'");
+ new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
+ + strlen (argstring) + 1
+ + 1);
+ sprintf (new_opname, argstring,
+ IDENTIFIER_POINTER (function));
+ }
+ else
+ {
+ /* Function name unknown (call through ptr). */
+ const char *const argnofun = _("passing arg of pointer to function");
+ new_opname = (char *) alloca (strlen (argnofun) + 1 + 1);
+ sprintf (new_opname, argnofun);
+ }
+ }
+ else if (function)
{
/* Function name is known; supply it. */
const char *const argstring = _("passing arg %d of `%s'");
}
else
{
- /* Function name unknown (call through ptr); just give arg number.*/
+ /* Function name unknown (call through ptr); just give arg number. */
const char *const argnofun = _("passing arg %d of pointer to function");
new_opname = (char *) alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1);
sprintf (new_opname, argnofun, argnum);
which is allowed with a warning when -pedantic is specified. */
static tree
-valid_compound_expr_initializer (value, endtype)
- tree value;
- tree endtype;
+valid_compound_expr_initializer (tree value, tree endtype)
{
if (TREE_CODE (value) == COMPOUND_EXPR)
{
If the init is invalid, store an ERROR_MARK. */
void
-store_init_value (decl, init)
- tree decl, init;
+store_init_value (tree decl, tree init)
{
tree value, type;
/* Digest the specified initializer into an expression. */
- value = digest_init (type, init, TREE_STATIC (decl),
- TREE_STATIC (decl) || (pedantic && !flag_isoc99));
+ value = digest_init (type, init, TREE_STATIC (decl));
/* Store the expression if valid; else report error. */
-#if 0
- /* Note that this is the only place we can detect the error
- in a case such as struct foo bar = (struct foo) { x, y };
- where there is one initial value which is a constructor expression. */
- if (value == error_mark_node)
- ;
- else if (TREE_STATIC (decl) && ! TREE_CONSTANT (value))
- {
- error ("initializer for static variable is not constant");
- value = error_mark_node;
- }
- else if (TREE_STATIC (decl)
- && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
- {
- error ("initializer for static variable uses complicated arithmetic");
- value = error_mark_node;
- }
- else
- {
- if (pedantic && TREE_CODE (value) == CONSTRUCTOR)
- {
- if (! TREE_CONSTANT (value))
- pedwarn ("aggregate initializer is not constant");
- else if (! TREE_STATIC (value))
- pedwarn ("aggregate initializer uses complicated arithmetic");
- }
- }
-#endif
-
if (warn_traditional && !in_system_header
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)) && ! TREE_STATIC (decl))
warning ("traditional C rejects automatic aggregate initialization");
/* ANSI wants warnings about out-of-range constant initializers. */
STRIP_TYPE_NOPS (value);
constant_expression_warning (value);
+
+ /* Check if we need to set array size from compound literal size. */
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == 0
+ && value != error_mark_node)
+ {
+ tree inside_init = init;
+
+ if (TREE_CODE (init) == NON_LVALUE_EXPR)
+ inside_init = TREE_OPERAND (init, 0);
+ inside_init = fold (inside_init);
+
+ if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+ {
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+
+ if (TYPE_DOMAIN (TREE_TYPE (decl)))
+ {
+ /* For int foo[] = (int [3]){1}; we need to set array size
+ now since later on array initializer will be just the
+ brace enclosed list of the compound literal. */
+ TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (decl));
+ layout_type (type);
+ layout_decl (decl, 0);
+ }
+ }
+ }
}
\f
/* Methods for storing and printing names for error messages. */
#define SPELLING_DEPTH() (spelling - spelling_base)
#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH))
-/* Save and restore the spelling stack around arbitrary C code. */
-
-#define SAVE_SPELLING_DEPTH(code) \
-{ \
- int __depth = SPELLING_DEPTH (); \
- code; \
- RESTORE_SPELLING_DEPTH (__depth); \
-}
-
/* Push an element on the spelling stack with type KIND and assign VALUE
to MEMBER. */
/* Push STRING on the stack. Printed literally. */
static void
-push_string (string)
- const char *string;
+push_string (const char *string)
{
PUSH_SPELLING (SPELLING_STRING, string, u.s);
}
/* Push a member name on the stack. Printed as '.' STRING. */
static void
-push_member_name (decl)
- tree decl;
-
+push_member_name (tree decl)
{
const char *const string
= DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
/* Push an array bounds on the stack. Printed as [BOUNDS]. */
static void
-push_array_bounds (bounds)
- int bounds;
+push_array_bounds (int bounds)
{
PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i);
}
/* Compute the maximum size in bytes of the printed spelling. */
static int
-spelling_length ()
+spelling_length (void)
{
int size = 0;
struct spelling *p;
/* Print the spelling to BUFFER and return it. */
static char *
-print_spelling (buffer)
- char *buffer;
+print_spelling (char *buffer)
{
char *d = buffer;
struct spelling *p;
The component name is taken from the spelling stack. */
void
-error_init (msgid)
- const char *msgid;
+error_init (const char *msgid)
{
char *ofwhat;
- error ("%s", msgid);
+ error ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
error ("(near initialization for `%s')", ofwhat);
The component name is taken from the spelling stack. */
void
-pedwarn_init (msgid)
- const char *msgid;
+pedwarn_init (const char *msgid)
{
char *ofwhat;
- pedwarn ("%s", msgid);
+ pedwarn ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
pedwarn ("(near initialization for `%s')", ofwhat);
The component name is taken from the spelling stack. */
static void
-warning_init (msgid)
- const char *msgid;
+warning_init (const char *msgid)
{
char *ofwhat;
- warning ("%s", msgid);
+ warning ("%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
warning ("(near initialization for `%s')", ofwhat);
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
- The arguments REQUIRE_CONSTANT and CONSTRUCTOR_CONSTANT request errors
- if non-constant initializers or elements are seen. CONSTRUCTOR_CONSTANT
- applies only to elements of constructors. */
+ REQUIRE_CONSTANT requests an error if non-constant initializers or
+ elements are seen. */
static tree
-digest_init (type, init, require_constant, constructor_constant)
- tree type, init;
- int require_constant, constructor_constant;
+digest_init (tree type, tree init, int require_constant)
{
enum tree_code code = TREE_CODE (type);
tree inside_init = init;
if (type == error_mark_node
|| init == error_mark_node
- || TREE_TYPE (init) == error_mark_node)
+ || TREE_TYPE (init) == error_mark_node)
return error_mark_node;
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
}
}
+ /* Build a VECTOR_CST from a *constant* vector constructor. If the
+ vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
+ below and handle as a constructor. */
+ if (code == VECTOR_TYPE
+ && comptypes (TREE_TYPE (inside_init), type)
+ && TREE_CONSTANT (inside_init))
+ {
+ if (TREE_CODE (inside_init) == VECTOR_CST
+ && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+ TYPE_MAIN_VARIANT (type)))
+ return inside_init;
+ else
+ return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+ }
+
/* Any type can be initialized
from an expression of the same type, optionally with braces. */
TYPE_MAIN_VARIANT (type))
|| (code == ARRAY_TYPE
&& comptypes (TREE_TYPE (inside_init), type))
+ || (code == VECTOR_TYPE
+ && comptypes (TREE_TYPE (inside_init), type))
|| (code == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
TREE_TYPE (type)))))
{
- if (code == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
- inside_init = default_conversion (inside_init);
- else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
- && TREE_CODE (inside_init) != CONSTRUCTOR)
+ if (code == POINTER_TYPE)
+ inside_init = default_function_array_conversion (inside_init);
+
+ if (require_constant && !flag_isoc99
+ && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+ {
+ /* As an extension, allow initializing objects with static storage
+ duration with compound literals (which are then treated just as
+ the brace enclosed list they contain). */
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+ inside_init = DECL_INITIAL (decl);
+ }
+
+ if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
+ && TREE_CODE (inside_init) != CONSTRUCTOR)
{
error_init ("array initialized from non-constant array expression");
return error_mark_node;
if (flag_pedantic_errors)
inside_init = error_mark_node;
}
- else if (require_constant
+ else if (require_constant
&& (!TREE_CONSTANT (inside_init)
/* This test catches things like `7 / 0' which
result in an expression for which TREE_CONSTANT
return error_mark_node;
}
- /* Traditionally, you can write struct foo x = 0;
- and it initializes the first element of x to 0. */
- if (flag_traditional)
- {
- tree top = 0, prev = 0, otype = type;
- while (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == ARRAY_TYPE
- || TREE_CODE (type) == QUAL_UNION_TYPE
- || TREE_CODE (type) == UNION_TYPE)
- {
- tree temp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
- if (prev == 0)
- top = temp;
- else
- TREE_OPERAND (prev, 1) = build_tree_list (NULL_TREE, temp);
- prev = temp;
- if (TREE_CODE (type) == ARRAY_TYPE)
- type = TREE_TYPE (type);
- else if (TYPE_FIELDS (type))
- type = TREE_TYPE (TYPE_FIELDS (type));
- else
- {
- error_init ("invalid initializer");
- return error_mark_node;
- }
- }
-
- if (otype != type)
- {
- TREE_OPERAND (prev, 1)
- = build_tree_list (NULL_TREE,
- digest_init (type, init, require_constant,
- constructor_constant));
- return top;
- }
- else
- return error_mark_node;
- }
error_init ("invalid initializer");
return error_mark_node;
}
/* 1 if this constructor is erroneous so far. */
static int constructor_erroneous;
-/* 1 if have called defer_addressed_constants. */
-static int constructor_subconstants_deferred;
-
/* Structure for managing pending initializer elements, organized as an
AVL tree. */
char top_level;
char require_constant_value;
char require_constant_elements;
- char deferred;
};
struct initializer_stack *initializer_stack;
/* Prepare to parse and output the initializer for variable DECL. */
void
-start_init (decl, asmspec_tree, top_level)
- tree decl;
- tree asmspec_tree;
- int top_level;
+start_init (tree decl, tree asmspec_tree, int top_level)
{
const char *locus;
struct initializer_stack *p
p->spelling = spelling;
p->spelling_base = spelling_base;
p->spelling_size = spelling_size;
- p->deferred = constructor_subconstants_deferred;
p->top_level = constructor_top_level;
p->next = initializer_stack;
initializer_stack = p;
constructor_decl = decl;
constructor_asmspec = asmspec;
- constructor_subconstants_deferred = 0;
constructor_designated = 0;
constructor_top_level = top_level;
}
void
-finish_init ()
+finish_init (void)
{
struct initializer_stack *p = initializer_stack;
- /* Output subconstants (string constants, usually)
- that were referenced within this initializer and saved up.
- Must do this if and only if we called defer_addressed_constants. */
- if (constructor_subconstants_deferred)
- output_deferred_addressed_constants ();
-
/* Free the whole constructor stack of this initializer. */
while (constructor_stack)
{
spelling = p->spelling;
spelling_base = p->spelling_base;
spelling_size = p->spelling_size;
- constructor_subconstants_deferred = p->deferred;
constructor_top_level = p->top_level;
initializer_stack = p->next;
free (p);
For an initializer for a decl, TYPE is zero. */
void
-really_start_incremental_init (type)
- tree type;
+really_start_incremental_init (tree type)
{
struct constructor_stack *p
= (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
if (type == 0)
type = TREE_TYPE (constructor_decl);
+ if ((*targetm.vector_opaque_p) (type))
+ error ("opaque vector types cannot be initialized");
+
p->type = constructor_type;
p->fields = constructor_fields;
p->index = constructor_index;
&& TYPE_SIZE (constructor_type))
constructor_max_index = build_int_2 (-1, -1);
+ /* constructor_max_index needs to be an INTEGER_CST. Attempts
+ to initialize VLAs will cause a proper error; avoid tree
+ checking errors as well by setting a safe value. */
+ if (constructor_max_index
+ && TREE_CODE (constructor_max_index) != INTEGER_CST)
+ constructor_max_index = build_int_2 (-1, -1);
+
constructor_index
= convert (bitsizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
constructor_unfilled_index = constructor_index;
}
+ else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+ {
+ /* Vectors are like simple fixed-size arrays. */
+ constructor_max_index =
+ build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ constructor_index = convert (bitsizetype, bitsize_zero_node);
+ constructor_unfilled_index = constructor_index;
+ }
else
{
/* Handle the case of int x = {5}; */
IMPLICIT is 1 (or 2 if the push is because of designator list). */
void
-push_init_level (implicit)
- int implicit;
+push_init_level (int implicit)
{
struct constructor_stack *p;
tree value = NULL_TREE;
&& constructor_fields == 0)
process_init_element (pop_init_level (1));
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+ && constructor_max_index
&& tree_int_cst_lt (constructor_max_index, constructor_index))
process_init_element (pop_init_level (1));
else
{
constructor_constant = TREE_CONSTANT (value);
constructor_simple = TREE_STATIC (value);
- constructor_elements = TREE_OPERAND (value, 1);
+ constructor_elements = CONSTRUCTOR_ELTS (value);
if (constructor_elements
&& (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == ARRAY_TYPE))
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = bitsize_zero_node;
}
+ else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+ {
+ /* Vectors are like simple fixed-size arrays. */
+ constructor_max_index =
+ build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ constructor_index = convert (bitsizetype, integer_zero_node);
+ constructor_unfilled_index = constructor_index;
+ }
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
if (TYPE_DOMAIN (constructor_type))
&& TYPE_SIZE (constructor_type))
constructor_max_index = build_int_2 (-1, -1);
+ /* constructor_max_index needs to be an INTEGER_CST. Attempts
+ to initialize VLAs will cause a proper error; avoid tree
+ checking errors as well by setting a safe value. */
+ if (constructor_max_index
+ && TREE_CODE (constructor_max_index) != INTEGER_CST)
+ constructor_max_index = build_int_2 (-1, -1);
+
constructor_index
- = convert (bitsizetype,
+ = convert (bitsizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
}
else
}
}
-/* At the end of an implicit or explicit brace level,
+/* At the end of an implicit or explicit brace level,
finish up that level of constructor.
If we were outputting the elements as they are read, return 0
from inner levels (process_init_element ignores that),
Otherwise, return a CONSTRUCTOR expression. */
tree
-pop_init_level (implicit)
- int implicit;
+pop_init_level (int implicit)
{
struct constructor_stack *p;
- HOST_WIDE_INT size = 0;
tree constructor = 0;
if (implicit == 0)
p = constructor_stack;
- if (constructor_type != 0)
- size = int_size_in_bytes (constructor_type);
-
/* Error for initializing a flexible array member, or a zero-length
array member in an inappropriate context. */
if (constructor_type && constructor_fields
else
/* Zero-length arrays are no longer special, so we should no longer
get here. */
- abort();
+ abort ();
}
/* Warn when some struct elements are implicitly initialized to zero. */
;
else if (TREE_CODE (constructor_type) != RECORD_TYPE
&& TREE_CODE (constructor_type) != UNION_TYPE
- && TREE_CODE (constructor_type) != ARRAY_TYPE)
+ && TREE_CODE (constructor_type) != ARRAY_TYPE
+ && TREE_CODE (constructor_type) != VECTOR_TYPE)
{
/* A nonincremental scalar initializer--just return
the element, after verifying there is just one. */
constructor = error_mark_node;
else
{
- constructor = build (CONSTRUCTOR, constructor_type, NULL_TREE,
- nreverse (constructor_elements));
+ constructor = build_constructor (constructor_type,
+ nreverse (constructor_elements));
if (constructor_constant)
TREE_CONSTANT (constructor) = 1;
if (constructor_constant && constructor_simple)
}
/* Common handling for both array range and field name designators.
- ARRAY argument is non-zero for array ranges. Returns zero for success. */
+ ARRAY argument is nonzero for array ranges. Returns zero for success. */
static int
-set_designator (array)
- int array;
+set_designator (int array)
{
tree subtype;
enum tree_code subcode;
NULL_TREE if there is no range designator at this level. */
static void
-push_range_stack (range_end)
- tree range_end;
+push_range_stack (tree range_end)
{
struct constructor_range_stack *p;
of indices, running from FIRST through LAST. */
void
-set_init_index (first, last)
- tree first, last;
+set_init_index (tree first, tree last)
{
if (set_designator (1))
return;
/* Within a struct initializer, specify the next field to be initialized. */
void
-set_init_label (fieldname)
- tree fieldname;
+set_init_label (tree fieldname)
{
tree tail;
error_init ("field name not in record or union initializer");
return;
}
-
+
for (tail = TYPE_FIELDS (constructor_type); tail;
tail = TREE_CHAIN (tail))
{
}
\f
/* Add a new initializer to the tree of pending initializers. PURPOSE
- identifies the initializer, either array index or field in a structure.
+ identifies the initializer, either array index or field in a structure.
VALUE is the value of that index or field. */
static void
-add_pending_init (purpose, value)
- tree purpose, value;
+add_pending_init (tree purpose, tree value)
{
struct init_node *p, **q, *r;
/* Build AVL tree from a sorted chain. */
static void
-set_nonincremental_init ()
+set_nonincremental_init (void)
{
tree chain;
&& DECL_C_BIT_FIELD (constructor_unfilled_fields)
&& DECL_NAME (constructor_unfilled_fields) == 0)
constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
-
+
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
/* Build AVL tree from a string constant. */
static void
-set_nonincremental_init_from_string (str)
- tree str;
+set_nonincremental_init_from_string (tree str)
{
tree value, purpose, type;
HOST_WIDE_INT val[2];
not initialized yet. */
static tree
-find_init_member (field)
- tree field;
+find_init_member (tree field)
{
struct init_node *p;
it is 0 while outputting pending elements, to avoid recursion.) */
static void
-output_init_element (value, type, field, pending)
- tree value, type, field;
- int pending;
+output_init_element (tree value, tree type, tree field, int pending)
{
+ if (type == error_mark_node)
+ {
+ constructor_erroneous = 1;
+ return;
+ }
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
|| (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
&& !(TREE_CODE (value) == STRING_CST
TYPE_MAIN_VARIANT (type))))
value = default_conversion (value);
+ if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
+ && require_constant_value && !flag_isoc99 && pending)
+ {
+ /* As an extension, allow initializing objects with static storage
+ duration with compound literals (which are then treated just as
+ the brace enclosed list they contain). */
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (value);
+ value = DECL_INITIAL (decl);
+ }
+
if (value == error_mark_node)
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
|| TREE_CHAIN (field)))))
return;
+ value = digest_init (type, value, require_constant_value);
if (value == error_mark_node)
{
constructor_erroneous = 1;
&& tree_int_cst_lt (field, constructor_unfilled_index))
set_nonincremental_init ();
- add_pending_init (field,
- digest_init (type, value, require_constant_value,
- require_constant_elements));
+ add_pending_init (field, value);
return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
}
}
- add_pending_init (field,
- digest_init (type, value, require_constant_value,
- require_constant_elements));
+ add_pending_init (field, value);
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
if (field && TREE_CODE (field) == INTEGER_CST)
field = copy_node (field);
constructor_elements
- = tree_cons (field, digest_init (type, value,
- require_constant_value,
- require_constant_elements),
- constructor_elements);
+ = tree_cons (field, value, constructor_elements);
/* Advance the variable that indicates sequential elements output. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
we can output all the pending elements. */
static void
-output_pending_init_elements (all)
- int all;
+output_pending_init_elements (int all)
{
struct init_node *elt = constructor_pending_elts;
tree next;
If we find an element that should be output now,
output it. Otherwise, set NEXT to the element
that comes first among those still pending. */
-
+
next = 0;
while (elt)
{
it calls output_init_element. */
void
-process_init_element (value)
- tree value;
+process_init_element (tree value)
{
tree orig_value = value;
int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
/* In the case of [LO ... HI] = VALUE, only evaluate VALUE once. */
if (constructor_range_stack)
- value = save_expr (value);
+ {
+ /* If value is a compound literal and we'll be just using its
+ content, don't put it into a SAVE_EXPR. */
+ if (TREE_CODE (value) != COMPOUND_LITERAL_EXPR
+ || !require_constant_value
+ || flag_isoc99)
+ value = save_expr (value);
+ }
while (1)
{
fieldtype = TYPE_MAIN_VARIANT (fieldtype);
fieldcode = TREE_CODE (fieldtype);
+ /* Error for non-static initialization of a flexible array member. */
+ if (fieldcode == ARRAY_TYPE
+ && !require_constant_value
+ && TYPE_SIZE (fieldtype) == NULL_TREE
+ && TREE_CHAIN (constructor_fields) == NULL_TREE)
+ {
+ error_init ("non-static initialization of a flexible array member");
+ break;
+ }
+
/* Accept a string constant to initialize a subarray. */
if (value != 0
&& fieldcode == ARRAY_TYPE
bit_position (constructor_fields),
DECL_SIZE (constructor_fields));
- constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
- /* Skip any nameless bit fields. */
- while (constructor_unfilled_fields != 0
- && DECL_C_BIT_FIELD (constructor_unfilled_fields)
- && DECL_NAME (constructor_unfilled_fields) == 0)
- constructor_unfilled_fields =
- TREE_CHAIN (constructor_unfilled_fields);
+ /* If the current field was the first one not yet written out,
+ it isn't now, so update. */
+ if (constructor_unfilled_fields == constructor_fields)
+ {
+ constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+ /* Skip any nameless bit fields. */
+ while (constructor_unfilled_fields != 0
+ && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+ && DECL_NAME (constructor_unfilled_fields) == 0)
+ constructor_unfilled_fields =
+ TREE_CHAIN (constructor_unfilled_fields);
+ }
}
constructor_fields = TREE_CHAIN (constructor_fields);
constructor_unfilled_index. */
constructor_unfilled_index = constructor_index;
}
+ else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+ {
+ tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+
+ /* Do a basic check of initializer size. Note that vectors
+ always have a fixed size derived from their type. */
+ if (tree_int_cst_lt (constructor_max_index, constructor_index))
+ {
+ pedwarn_init ("excess elements in vector initializer");
+ break;
+ }
+
+ /* Now output the actual element. */
+ if (value)
+ output_init_element (value, elttype, constructor_index, 1);
+
+ constructor_index
+ = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
+
+ if (! value)
+ /* If we are doing the bookkeeping for an element that was
+ directly output as a constructor, we must update
+ constructor_unfilled_index. */
+ constructor_unfilled_index = constructor_index;
+ }
/* Handle the sole element allowed in a braced initializer
for a scalar variable. */
\f
/* Build a simple asm-statement, from one string literal. */
tree
-simple_asm_stmt (expr)
- tree expr;
+simple_asm_stmt (tree expr)
{
STRIP_NOPS (expr);
{
tree stmt;
- if (TREE_CHAIN (expr))
- expr = combine_strings (expr);
- stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr,
- NULL_TREE, NULL_TREE,
- NULL_TREE));
+ /* Simple asm statements are treated as volatile. */
+ stmt = add_stmt (build_stmt (ASM_STMT, ridpointers[(int) RID_VOLATILE],
+ expr, NULL_TREE, NULL_TREE, NULL_TREE));
ASM_INPUT_P (stmt) = 1;
return stmt;
}
STRING, some OUTPUTS, some INPUTS, and some CLOBBERS. */
tree
-build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
- tree cv_qualifier;
- tree string;
- tree outputs;
- tree inputs;
- tree clobbers;
+build_asm_stmt (tree cv_qualifier, tree string, tree outputs, tree inputs, tree clobbers)
{
tree tail;
- if (TREE_CHAIN (string))
- string = combine_strings (string);
if (TREE_CODE (string) != STRING_CST)
{
error ("asm template is not a string constant");
TREE_VALUE (tail) = output;
}
- /* Perform default conversions on array and function inputs.
+ /* Perform default conversions on array and function inputs.
Don't do this for other types as it would screw up operands
expected to be in memory. */
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
- TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
+ TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
outputs, inputs, clobbers));
Arguments are same as for expand_asm_operands. */
void
-c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
- tree string, outputs, inputs, clobbers;
- int vol;
- const char *filename;
- int line;
+c_expand_asm_operands (tree string, tree outputs, tree inputs,
+ tree clobbers, int vol, const char *filename,
+ int line)
{
int noutputs = list_length (outputs);
int i;
/* Record the contents of OUTPUTS before it is modified. */
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- o[i] = TREE_VALUE (tail);
+ {
+ o[i] = TREE_VALUE (tail);
+ if (o[i] == error_mark_node)
+ return;
+ }
/* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
OUTPUTS some trees for where the values were actually stored. */
or a null pointer for `return;' with no value. */
tree
-c_expand_return (retval)
- tree retval;
+c_expand_return (tree retval)
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
tree res = DECL_RESULT (current_function_decl);
tree inner;
+ current_function_returns_value = 1;
if (t == error_mark_node)
return NULL_TREE;
inner = TREE_OPERAND (inner, 0);
continue;
}
-
+
case ADDR_EXPR:
inner = TREE_OPERAND (inner, 0);
}
retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
- current_function_returns_value = 1;
}
return add_stmt (build_return_stmt (retval));
SWITCH_STMT. */
tree
-c_start_case (exp)
- tree exp;
+c_start_case (tree exp)
{
enum tree_code code;
- tree type;
+ tree type, orig_type = error_mark_node;
struct c_switch *cs;
if (exp != error_mark_node)
{
code = TREE_CODE (TREE_TYPE (exp));
- type = TREE_TYPE (exp);
+ orig_type = TREE_TYPE (exp);
- if (! INTEGRAL_TYPE_P (type)
+ if (! INTEGRAL_TYPE_P (orig_type)
&& code != ERROR_MARK)
{
error ("switch quantity not an integer");
}
else
{
- tree index;
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
if (warn_traditional && !in_system_header
exp = default_conversion (exp);
type = TREE_TYPE (exp);
- index = get_unwidened (exp, NULL_TREE);
- /* We can't strip a conversion from a signed type to an
- unsigned, because if we did, int_fits_type_p would do the
- wrong thing when checking case values for being in range,
- and it's too hard to do the right thing. */
- if (TREE_UNSIGNED (TREE_TYPE (exp))
- == TREE_UNSIGNED (TREE_TYPE (index)))
- exp = index;
}
}
/* Add this new SWITCH_STMT to the stack. */
cs = (struct c_switch *) xmalloc (sizeof (*cs));
- cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, NULL_TREE);
+ cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
cs->cases = splay_tree_new (case_compare, NULL, NULL);
cs->next = switch_stack;
switch_stack = cs;
/* Process a case label. */
tree
-do_case (low_value, high_value)
- tree low_value;
- tree high_value;
+do_case (tree low_value, tree high_value)
{
tree label = NULL_TREE;
if (switch_stack)
{
- label = c_add_case_label (switch_stack->cases,
- SWITCH_COND (switch_stack->switch_stmt),
+ bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
+
+ label = c_add_case_label (switch_stack->cases,
+ SWITCH_COND (switch_stack->switch_stmt),
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
+ else if (switch_was_empty_p)
+ {
+ /* Attach the first case label to the SWITCH_BODY. */
+ SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
+ TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
+ }
}
else if (low_value)
error ("case label not within a switch statement");
/* Finish the switch statement. */
void
-c_finish_case ()
+c_finish_case (void)
{
struct c_switch *cs = switch_stack;
- RECHAIN_STMTS (cs->switch_stmt, SWITCH_BODY (cs->switch_stmt));
+ /* Rechain the next statements to the SWITCH_STMT. */
+ last_tree = cs->switch_stmt;
/* Pop the stack. */
switch_stack = switch_stack->next;