#include "target.h"
#include "tree-iterator.h"
#include "tree-gimple.h"
+#include "tree-flow.h"
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
/* The level of nesting inside "typeof". */
int in_typeof;
+struct c_label_context_se *label_context_stack_se;
+struct c_label_context_vm *label_context_stack_vm;
+
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
static void readonly_error (tree, enum lvalue_use);
+static int lvalue_or_else (tree, enum lvalue_use);
+static int lvalue_p (tree);
static void record_maybe_used_decl (tree);
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
if (value != 0 && (TREE_CODE (value) == VAR_DECL
|| TREE_CODE (value) == PARM_DECL))
- error ("%qs has an incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (value)));
+ error ("%qD has an incomplete type", value);
else
{
retry:
}
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- error ("invalid use of undefined type %<%s %s%>",
- type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type)));
+ error ("invalid use of undefined type %<%s %E%>",
+ type_code_string, TYPE_NAME (type));
else
/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
- error ("invalid use of incomplete typedef %qs",
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+ error ("invalid use of incomplete typedef %qD", TYPE_NAME (type));
}
}
case ARRAY_TYPE:
{
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
-
+ int quals;
+ tree unqual_elt;
+
/* We should not have any type quals on arrays at all. */
gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t2, attributes);
- /* Merge the element types, and have a size if either arg has one. */
- t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ /* Merge the element types, and have a size if either arg has
+ one. We may have qualifiers on the element types. To set
+ up TYPE_MAIN_VARIANT correctly, we need to form the
+ composite of the unqualified types and add the qualifiers
+ back at the end. */
+ quals = TYPE_QUALS (strip_array_types (elt));
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+ t1 = build_array_type (unqual_elt,
+ TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ t1 = c_build_qualified_type (t1, quals);
return build_type_attribute_variant (t1, attributes);
}
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
/* Tell global_bindings_p to return false so that variable_size
- doesn't abort on VLAs in parameter types. */
+ doesn't die on VLAs in parameter types. */
c_override_global_bindings_to_false = true;
len = list_length (p1);
&& TREE_VALUE (p1) != TREE_VALUE (p2))
{
tree memb;
+ tree mv2 = TREE_VALUE (p2);
+ if (mv2 && mv2 != error_mark_node
+ && TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (mv2);
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
- {
- TREE_VALUE (n) = TREE_VALUE (p2);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p2));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
&& TREE_VALUE (p2) != TREE_VALUE (p1))
{
tree memb;
+ tree mv1 = TREE_VALUE (p1);
+ if (mv1 && mv1 != error_mark_node
+ && TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (mv1);
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
- {
- TREE_VALUE (n) = TREE_VALUE (p1);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p1));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
parm_done: ;
common_pointer_type (tree t1, tree t2)
{
tree attributes;
- tree pointed_to_1;
- tree pointed_to_2;
+ tree pointed_to_1, mv1;
+ tree pointed_to_2, mv2;
tree target;
/* Save time if the two types are the same. */
attributes = targetm.merge_type_attributes (t1, t2);
/* Find the composite type of the target types, and combine the
- qualifiers of the two types' targets. */
- pointed_to_1 = TREE_TYPE (t1);
- pointed_to_2 = TREE_TYPE (t2);
- target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
- TYPE_MAIN_VARIANT (pointed_to_2));
+ qualifiers of the two types' targets. Do not lose qualifiers on
+ array element types by taking the TYPE_MAIN_VARIANT. */
+ mv1 = pointed_to_1 = TREE_TYPE (t1);
+ mv2 = pointed_to_2 = TREE_TYPE (t2);
+ if (TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (pointed_to_1);
+ if (TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
+ target = composite_type (mv1, mv2);
t1 = build_pointer_type (c_build_qualified_type
(target,
TYPE_QUALS (pointed_to_1) |
This is the type for the result of most arithmetic operations
if the operands have the given two types. */
-tree
-common_type (tree t1, tree t2)
+static tree
+c_common_type (tree t1, tree t2)
{
enum tree_code code1;
enum tree_code code2;
{
tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
- tree subtype = common_type (subtype1, subtype2);
+ tree subtype = c_common_type (subtype1, subtype2);
if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
return t1;
return t2;
}
\f
+/* Wrapper around c_common_type that is used by c-common.c. ENUMERAL_TYPEs
+ are allowed here and are converted to their compatible integer types. */
+tree
+common_type (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) == ENUMERAL_TYPE)
+ t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
+ if (TREE_CODE (t2) == ENUMERAL_TYPE)
+ t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
+ return c_common_type (t1, t2);
+}
+\f
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. */
definition. Note that we already checked for equality of the type
qualifiers (just above). */
- if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ if (TREE_CODE (t1) != ARRAY_TYPE
+ && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
comp_target_types (tree ttl, tree ttr, int reflexive)
{
int val;
+ tree mvl, mvr;
/* 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)),
- TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+ /* Do not lose qualifiers on element types of array types that are
+ pointer targets by taking their TYPE_MAIN_VARIANT. */
+ mvl = TREE_TYPE (ttl);
+ mvr = TREE_TYPE (ttr);
+ if (TREE_CODE (mvl) != ARRAY_TYPE)
+ mvl = TYPE_MAIN_VARIANT (mvl);
+ if (TREE_CODE (mvr) != ARRAY_TYPE)
+ mvr = TYPE_MAIN_VARIANT (mvr);
+ val = comptypes (mvl, mvr);
if (val == 2 && pedantic)
pedwarn ("types are not quite compatible");
return 0;
/* If one of these types comes from a non-prototype fn definition,
compare that with the other type's arglist.
- If they don't match, ask for a warning (but no error). */
+ If they don't match, ask for a warning (0, but no error). */
if (TYPE_ACTUAL_ARG_TYPES (f1)
&& 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
val = 2;
while (1)
{
+ tree a1, mv1, a2, mv2;
if (args1 == 0 && args2 == 0)
return val;
/* If one list is shorter than the other,
they fail to match. */
if (args1 == 0 || args2 == 0)
return 0;
+ mv1 = a1 = TREE_VALUE (args1);
+ mv2 = a2 = TREE_VALUE (args2);
+ if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (mv1);
+ if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (mv2);
/* A null pointer instead of a type
means there is supposed to be an argument
but nothing is specified about what type it has.
So match anything that self-promotes. */
- if (TREE_VALUE (args1) == 0)
+ if (a1 == 0)
{
- if (c_type_promotes_to (TREE_VALUE (args2)) != TREE_VALUE (args2))
+ if (c_type_promotes_to (a2) != a2)
return 0;
}
- else if (TREE_VALUE (args2) == 0)
+ else if (a2 == 0)
{
- if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
+ if (c_type_promotes_to (a1) != a1)
return 0;
}
/* If one of the lists has an error marker, ignore this arg. */
- else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
- || TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
+ else if (TREE_CODE (a1) == ERROR_MARK
+ || TREE_CODE (a2) == ERROR_MARK)
;
- else if (!(newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
- TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+ else if (!(newval = comptypes (mv1, mv2)))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
- if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
- && (TYPE_NAME (TREE_VALUE (args1)) == 0
- || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
- && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
- && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
- TYPE_SIZE (TREE_VALUE (args2))))
+ if (TREE_CODE (a1) == UNION_TYPE
+ && (TYPE_NAME (a1) == 0
+ || TYPE_TRANSPARENT_UNION (a1))
+ && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
+ && tree_int_cst_equal (TYPE_SIZE (a1),
+ TYPE_SIZE (a2)))
{
tree memb;
- for (memb = TYPE_FIELDS (TREE_VALUE (args1));
+ for (memb = TYPE_FIELDS (a1);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ break;
+ }
if (memb == 0)
return 0;
}
- else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
- && (TYPE_NAME (TREE_VALUE (args2)) == 0
- || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
- && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
- && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
- TYPE_SIZE (TREE_VALUE (args1))))
+ else if (TREE_CODE (a2) == UNION_TYPE
+ && (TYPE_NAME (a2) == 0
+ || TYPE_TRANSPARENT_UNION (a2))
+ && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
+ && tree_int_cst_equal (TYPE_SIZE (a2),
+ TYPE_SIZE (a1)))
{
tree memb;
- for (memb = TYPE_FIELDS (TREE_VALUE (args2));
+ for (memb = TYPE_FIELDS (a2);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ break;
+ }
if (memb == 0)
return 0;
}
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. */
+
+/* EXP is an expression of integer type. Apply the integer promotions
+ to it and return the promoted value. */
tree
-default_conversion (tree exp)
+perform_integral_promotions (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);
-
- if (TREE_NO_WARNING (orig_exp))
- TREE_NO_WARNING (exp) = 1;
+ gcc_assert (INTEGRAL_TYPE_P (type));
/* Normally convert enums to int,
but convert wide enums to something wider. */
return convert (type, exp);
}
+ /* ??? This should no longer be needed now bit-fields have their
+ proper types. */
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
return convert (integer_type_node, 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 no-op conversions. */
+ orig_exp = exp;
+ STRIP_TYPE_NOPS (exp);
+
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
+
+ if (INTEGRAL_TYPE_P (type))
+ return perform_integral_promotions (exp);
+
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
if (!field)
{
- error ("%qT has no member named %qs", type,
- IDENTIFIER_POINTER (component));
+ error ("%qT has no member named %qE", type, component);
return error_mark_node;
}
return ref;
}
else if (code != ERROR_MARK)
- error ("request for member %qs in something not a structure or union",
- IDENTIFIER_POINTER (component));
+ error ("request for member %qE in something not a structure or union",
+ component);
return error_mark_node;
}
else
{
tree t = TREE_TYPE (type);
- tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
+ tree mvt = t;
+ tree ref;
+
+ if (TREE_CODE (mvt) != ARRAY_TYPE)
+ mvt = TYPE_MAIN_VARIANT (mvt);
+ ref = build1 (INDIRECT_REF, mvt, pointer);
if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
{
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning ("dereferencing %<void *%> pointer");
+ warning (0, "dereferencing %<void *%> pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
char[array]. */
if (warn_char_subscripts && !swapped
&& TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("array subscript has type %<char%>");
+ warning (0, "array subscript has type %<char%>");
/* Apply default promotions *after* noticing character types. */
index = default_conversion (index);
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
- type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+ type = TREE_TYPE (TREE_TYPE (array));
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ type = TYPE_MAIN_VARIANT (type);
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is. */
}
\f
/* Build an external reference to identifier ID. FUN indicates
- whether this will be used for a function call. */
+ whether this will be used for a function call. LOC is the source
+ location of the identifier. */
tree
-build_external_ref (tree id, int fun)
+build_external_ref (tree id, int fun, location_t loc)
{
tree ref;
tree decl = lookup_name (id);
return error_mark_node;
else
{
- undeclared_variable (id);
+ undeclared_variable (id, loc);
return error_mark_node;
}
/* Convert anything with function type to a pointer-to-function. */
if (TREE_CODE (function) == FUNCTION_DECL)
{
+ /* Implement type-directed function overloading for builtins.
+ resolve_overloaded_builtin and targetm.resolve_overloaded_builtin
+ handle all the type checking. The result is a complete expression
+ that implements this function call. */
+ tem = resolve_overloaded_builtin (function, params);
+ if (tem)
+ return tem;
+
name = DECL_NAME (function);
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
executions of the program must execute the code. */
- warning ("function called through a non-compatible type");
+ warning (0, "function called through a non-compatible type");
/* We can, however, treat "undefined" any way we please.
Call abort to encourage the user to fix the program. */
tree val = TREE_VALUE (valtail);
tree rname = function;
int argnum = parmnum + 1;
+ const char *invalid_func_diag;
if (type == void_type_node)
{
argnum -= 2;
}
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here! We do not want an enumerator with value 0
- to convert automatically to a pointer. */
- if (TREE_CODE (val) == NON_LVALUE_EXPR)
- val = TREE_OPERAND (val, 0);
+ STRIP_TYPE_NOPS (val);
val = default_function_array_conversion (val);
/* Formal parm type is specified by a function prototype. */
tree parmval;
- if (!COMPLETE_TYPE_P (type))
+ if (type == error_mark_node || !COMPLETE_TYPE_P (type))
{
error ("type of formal parameter %d is incomplete", parmnum + 1);
parmval = val;
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than floating due to prototype",
argnum, rname);
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than complex due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than floating due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than complex due to prototype",
argnum, rname);
/* ??? At some point, messages should be written about
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
if (formal_prec == TYPE_PRECISION (float_type_node))
- warning ("passing argument %d of %qE as %<float%> "
+ warning (0, "passing argument %d of %qE as %<float%> "
"rather than %<double%> due to prototype",
argnum, rname);
}
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warning ("passing argument %d of %qE with different "
+ warning (0, "passing argument %d of %qE with different "
"width due to prototype", argnum, rname);
else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
;
/* Change in signedness doesn't matter
if a constant value is unaffected. */
;
- /* Likewise for a constant in a NOP_EXPR. */
- else if (TREE_CODE (val) == NOP_EXPR
- && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST
- && int_fits_type_p (TREE_OPERAND (val, 0), type))
- ;
/* If the value is extended from a narrower
unsigned type, it doesn't matter whether we
pass it as signed or unsigned; the value
&& TYPE_UNSIGNED (TREE_TYPE (val)))
;
else if (TYPE_UNSIGNED (type))
- warning ("passing argument %d of %qE as unsigned "
+ warning (0, "passing argument %d of %qE as unsigned "
"due to prototype", argnum, rname);
else
- warning ("passing argument %d of %qE as signed "
+ warning (0, "passing argument %d of %qE as signed "
"due to prototype", argnum, rname);
}
}
< TYPE_PRECISION (double_type_node)))
/* Convert `float' to `double'. */
result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+ else if ((invalid_func_diag =
+ targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+ {
+ error (invalid_func_diag);
+ return error_mark_node;
+ }
else
/* Convert `short' and `char' to full-size `int'. */
result = tree_cons (NULL_TREE, default_conversion (val), result);
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around + or - inside shift");
+ warning (0, "suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code1 == TRUTH_ANDIF_EXPR
|| code2 == TRUTH_ANDIF_EXPR)
- warning ("suggest parentheses around && within ||");
+ warning (0, "suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of |");
+ warning (0, "suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of |");
+ warning (0, "suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of ^");
+ warning (0, "suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of ^");
+ warning (0, "suggest parentheses around comparison in operand of ^");
}
if (code == BIT_AND_EXPR)
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around + or - in operand of &");
+ warning (0, "suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of &");
+ warning (0, "suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
if (TREE_CODE_CLASS (code) == tcc_comparison
&& (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison))
- warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
+ warning (0, "comparisons like X<=Y<=Z do not have their mathematical meaning");
}
break;
case TRUTH_NOT_EXPR:
+ /* ??? Why do most validation here but that for non-lvalue arrays
+ in c_objc_common_truthvalue_conversion? */
if (typecode != INTEGER_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
&& typecode != COMPLEX_TYPE
error ("wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = lang_hooks.truthvalue_conversion (arg);
+ arg = c_objc_common_truthvalue_conversion (arg);
return invert_truthvalue (arg);
case NOP_EXPR:
Lvalues can be assigned, unless their type has TYPE_READONLY.
Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
-int
+static int
lvalue_p (tree ref)
{
enum tree_code code = TREE_CODE (ref);
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
readonly_error (TREE_OPERAND (arg, 0), use);
else
- error (READONLY_MSG (N_("assignment of read-only member %qs"),
- N_("increment of read-only member %qs"),
- N_("decrement of read-only member %qs")),
- IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
+ error (READONLY_MSG (N_("assignment of read-only member %qD"),
+ N_("increment of read-only member %qD"),
+ N_("decrement of read-only member %qD")),
+ TREE_OPERAND (arg, 1));
}
else if (TREE_CODE (arg) == VAR_DECL)
- error (READONLY_MSG (N_("assignment of read-only variable %qs"),
- N_("increment of read-only variable %qs"),
- N_("decrement of read-only variable %qs")),
- IDENTIFIER_POINTER (DECL_NAME (arg)));
+ error (READONLY_MSG (N_("assignment of read-only variable %qD"),
+ N_("increment of read-only variable %qD"),
+ N_("decrement of read-only variable %qD")),
+ arg);
else
error (READONLY_MSG (N_("assignment of read-only location"),
N_("increment of read-only location"),
N_("decrement of read-only location")));
}
+
+
+/* Return nonzero if REF is an lvalue valid for this language;
+ otherwise, print an error message and return zero. USE says
+ how the lvalue is being used and so selects the error message. */
+
+static int
+lvalue_or_else (tree ref, enum lvalue_use use)
+{
+ int win = lvalue_p (ref);
+
+ if (!win)
+ lvalue_error (use);
+
+ return win;
+}
\f
/* Mark EXP saying that we need to be able to take the
address of it; it should not be allocated in a register.
tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
- ifexp = lang_hooks.truthvalue_conversion (default_conversion (ifexp));
-
/* Promote both alternatives. */
if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE
|| code2 == COMPLEX_TYPE))
{
- result_type = common_type (type1, type2);
+ result_type = c_common_type (type1, type2);
/* If -Wsign-compare, warn here if type1 and type2 have
different signedness. We'll promote the signed to unsigned
|| (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
- warning ("signed and unsigned type in conditional expression");
+ warning (0, "signed and unsigned type in conditional expression");
}
}
}
/* The left-hand operand of a comma expression is like an expression
statement: with -Wextra or -Wunused, we should warn if it doesn't have
any side-effects, unless it was explicitly cast to (void). */
- if (warn_unused_value
- && !(TREE_CODE (expr1) == CONVERT_EXPR
- && VOID_TYPE_P (TREE_TYPE (expr1))))
- warning ("left-hand operand of comma expression has no effect");
+ if (warn_unused_value)
+ {
+ if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == CONVERT_EXPR)
+ ; /* (void) a, b */
+ else if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR)
+ ; /* (void) a, (void) b, c */
+ else
+ warning (0, "left-hand operand of comma expression has no effect");
+ }
}
/* With -Wunused, we should also warn if the left-hand operand does have
&& TREE_CODE (in_otype) == POINTER_TYPE);
if (added)
- warning ("cast adds new qualifiers to function type");
+ warning (0, "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");
+ warning (0, "cast discards qualifiers from pointer target type");
}
/* Warn about possible alignment problems. */
|| TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
&& TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast increases required alignment of target type");
+ warning (0, "cast increases required alignment of target type");
- if (TREE_CODE (type) == INTEGER_TYPE
+ if (warn_pointer_to_int_cast
+ && TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
&& !TREE_CONSTANT (value))
- warning ("cast from pointer to integer of different size");
+ warning (0, "cast from pointer to integer of different size");
if (warn_bad_function_cast
&& TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning ("cast from function call of type %qT to non-matching "
+ warning (0, "cast from function call of type %qT to non-matching "
"type %qT", otype, type);
- if (TREE_CODE (type) == POINTER_TYPE
+ if (warn_int_to_pointer_cast
+ && TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
/* Don't warn about converting any constant. */
&& !TREE_CONSTANT (value))
- warning ("cast to pointer from integer of different size");
+ warning (0, "cast to pointer from integer of different size");
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_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");
+ warning (0, "type-punning to incomplete type might break strict-aliasing rules");
else
{
HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
if (!alias_sets_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+ warning (0, "dereferencing type-punned pointer will break strict-aliasing rules");
else if (warn_strict_aliasing > 1
&& !alias_sets_might_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+ warning (0, "dereferencing type-punned pointer might break strict-aliasing rules");
}
}
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ STRIP_TYPE_NOPS (rhs);
newrhs = rhs;
pedwarn (AR, parmnum, rname); \
break; \
case ic_argpass_nonproto: \
- warning (AR, parmnum, rname); \
+ warning (0, AR, parmnum, rname); \
break; \
case ic_assign: \
pedwarn (AS); \
} \
} while (0)
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ STRIP_TYPE_NOPS (rhs);
if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
{
tree ttl = TREE_TYPE (type);
tree ttr = TREE_TYPE (rhstype);
+ tree mvl = ttl;
+ tree mvr = ttr;
bool is_opaque_pointer;
int target_cmp = 0; /* Cache comp_target_types () result. */
+ if (TREE_CODE (mvl) != ARRAY_TYPE)
+ mvl = TYPE_MAIN_VARIANT (mvl);
+ if (TREE_CODE (mvr) != ARRAY_TYPE)
+ mvr = TYPE_MAIN_VARIANT (mvr);
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = (targetm.vector_opaque_p (type)
|| targetm.vector_opaque_p (rhstype))
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
|| (target_cmp = 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))))
+ || (c_common_unsigned_type (mvl)
+ == c_common_unsigned_type (mvr)))
{
if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
|| target_cmp)
;
/* If there is a mismatch, do warn. */
- else
+ else if (warn_pointer_sign)
WARN_FOR_ASSIGNMENT (N_("pointer targets in passing argument "
"%d of %qE differ in signedness"),
N_("pointer targets in assignment "
if (warn_traditional && !in_system_header
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
- warning ("traditional C rejects automatic aggregate initialization");
+ warning (0, "traditional C rejects automatic aggregate initialization");
DECL_INITIAL (decl) = value;
{
tree inside_init = init;
- if (TREE_CODE (init) == NON_LVALUE_EXPR)
- inside_init = TREE_OPERAND (init, 0);
+ STRIP_TYPE_NOPS (inside_init);
inside_init = fold (inside_init);
if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
char *ofwhat;
- warning ("%s", _(msgid));
+ warning (0, "%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning ("(near initialization for %qs)", ofwhat);
+ warning (0, "(near initialization for %qs)", ofwhat);
}
\f
/* If TYPE is an array type and EXPR is a parenthesized string
|| TREE_TYPE (init) == error_mark_node)
return error_mark_node;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (init) == NON_LVALUE_EXPR)
- inside_init = TREE_OPERAND (init, 0);
+ STRIP_TYPE_NOPS (inside_init);
inside_init = fold (inside_init);
/* 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
- && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
- && vector_types_convertible_p (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));
- }
+ if (code == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
+ && vector_types_convertible_p (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;
+
+ if (TREE_CODE (inside_init) == CONSTRUCTOR)
+ {
+ tree link;
+
+ /* Iterate through elements and check if all constructor
+ elements are *_CSTs. */
+ for (link = CONSTRUCTOR_ELTS (inside_init);
+ link;
+ link = TREE_CHAIN (link))
+ if (! CONSTANT_CLASS_P (TREE_VALUE (link)))
+ break;
+
+ if (link == NULL)
+ return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+ }
+ }
/* Any type can be initialized
from an expression of the same type, optionally with braces. */
char designated;
};
-struct constructor_stack *constructor_stack;
+static struct constructor_stack *constructor_stack;
/* This stack represents designators from some range designator up to
the last designator in the list. */
tree fields;
};
-struct constructor_range_stack *constructor_range_stack;
+static struct constructor_range_stack *constructor_range_stack;
/* This stack records separate initializers that are nested.
Nested initializers can't happen in ANSI C, but GNU C allows them
char require_constant_elements;
};
-struct initializer_stack *initializer_stack;
+static struct initializer_stack *initializer_stack;
\f
/* Prepare to parse and output the initializer for variable DECL. */
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
}
else
- constructor_index = bitsize_zero_node;
+ {
+ constructor_index = bitsize_zero_node;
+ constructor_max_index = NULL_TREE;
+ }
constructor_unfilled_index = constructor_index;
}
}
else
{
- warning_init ("braces around scalar initializer");
+ if (constructor_type != error_mark_node)
+ warning_init ("braces around scalar initializer");
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
}
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
- Discard the initializer so that we do not abort later. */
+ Discard the initializer so that we do not die later. */
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
return;
}
- while ((TREE_CODE (first) == NOP_EXPR
- || TREE_CODE (first) == CONVERT_EXPR
- || TREE_CODE (first) == NON_LVALUE_EXPR)
- && (TYPE_MODE (TREE_TYPE (first))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
- first = TREE_OPERAND (first, 0);
-
- if (last)
- while ((TREE_CODE (last) == NOP_EXPR
- || TREE_CODE (last) == CONVERT_EXPR
- || TREE_CODE (last) == NON_LVALUE_EXPR)
- && (TYPE_MODE (TREE_TYPE (last))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
- last = TREE_OPERAND (last, 0);
-
if (TREE_CODE (first) != INTEGER_CST)
error_init ("nonconstant array index in initializer");
else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
}
if (tail == 0)
- error ("unknown field %qs specified in initializer",
- IDENTIFIER_POINTER (fieldname));
+ error ("unknown field %qE specified in initializer", fieldname);
else
{
constructor_fields = tail;
if (warn_traditional && !in_system_header && !constructor_designated
&& !(value.value && (integer_zerop (value.value)
|| real_zerop (value.value))))
- warning ("traditional C rejects initialization of unions");
+ warning (0, "traditional C rejects initialization of unions");
/* Accept a string constant to initialize a subarray. */
if (value.value != 0
/* Handle the sole element allowed in a braced initializer
for a scalar variable. */
- else if (constructor_fields == 0)
+ else if (constructor_type != error_mark_node
+ && constructor_fields == 0)
{
pedwarn_init ("excess elements in scalar initializer");
break;
{
/* If the operand is going to end up in memory,
mark it addressable. */
- if (!allows_reg && allows_mem && !c_mark_addressable (input))
- input = error_mark_node;
+ if (!allows_reg && allows_mem)
+ {
+ /* Strip the nops as we allow this case. FIXME, this really
+ should be rejected or made deprecated. */
+ STRIP_NOPS (input);
+ if (!c_mark_addressable (input))
+ input = error_mark_node;
+ }
}
else
input = error_mark_node;
if (!decl)
return NULL_TREE;
+ if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
+ {
+ error ("jump into statement expression");
+ return NULL_TREE;
+ }
+
+ if (C_DECL_UNJUMPABLE_VM (decl))
+ {
+ error ("jump into scope of identifier with variably modified type");
+ return NULL_TREE;
+ }
+
+ if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
+ {
+ /* No jump from outside this statement expression context, so
+ record that there is a jump from within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack_se->labels_used;
+ nlist->label = decl;
+ label_context_stack_se->labels_used = nlist;
+ }
+
+ if (!C_DECL_UNDEFINABLE_VM (decl))
+ {
+ /* No jump from outside this context context of identifiers with
+ variably modified type, so record that there is a jump from
+ within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack_vm->labels_used;
+ nlist->label = decl;
+ label_context_stack_vm->labels_used = nlist;
+ }
+
TREE_USED (decl) = 1;
return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
}
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared %<noreturn%> has a %<return%> statement");
+ warning (0, "function declared %<noreturn%> has a %<return%> statement");
if (!retval)
{
&& !DECL_EXTERNAL (inner)
&& !TREE_STATIC (inner)
&& DECL_CONTEXT (inner) == current_function_decl)
- warning ("function returns address of local variable");
+ warning (0, "function returns address of local variable");
break;
default:
}
\f
struct c_switch {
- /* The SWITCH_STMT being built. */
- tree switch_stmt;
+ /* The SWITCH_EXPR being built. */
+ tree switch_expr;
/* The original type of the testing expression, i.e. before the
default conversion is applied. */
of the GNU case range extension. */
splay_tree cases;
+ /* Number of nested statement expressions within this switch
+ statement; if nonzero, case and default labels may not
+ appear. */
+ unsigned int blocked_stmt_expr;
+
+ /* Scope of outermost declarations of identifiers with variably
+ modified type within this switch statement; if nonzero, case and
+ default labels may not appear. */
+ unsigned int blocked_vm;
+
/* The next node on the stack. */
struct c_switch *next;
};
struct c_switch *c_switch_stack;
/* Start a C switch statement, testing expression EXP. Return the new
- SWITCH_STMT. */
+ SWITCH_EXPR. */
tree
c_start_case (tree exp)
if (warn_traditional && !in_system_header
&& (type == long_integer_type_node
|| type == long_unsigned_type_node))
- warning ("%<long%> switch expression not converted to "
+ warning (0, "%<long%> switch expression not converted to "
"%<int%> in ISO C");
exp = default_conversion (exp);
}
}
- /* Add this new SWITCH_STMT to the stack. */
+ /* Add this new SWITCH_EXPR to the stack. */
cs = XNEW (struct c_switch);
- cs->switch_stmt = build_stmt ((enum tree_code) SWITCH_STMT, exp, NULL_TREE,
- orig_type);
+ cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
+ cs->blocked_stmt_expr = 0;
+ cs->blocked_vm = 0;
cs->next = c_switch_stack;
c_switch_stack = cs;
- return add_stmt (cs->switch_stmt);
+ return add_stmt (cs->switch_expr);
}
/* Process a case label. */
{
tree label = NULL_TREE;
- if (c_switch_stack)
+ if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
+ && !c_switch_stack->blocked_vm)
{
label = c_add_case_label (c_switch_stack->cases,
- SWITCH_COND (c_switch_stack->switch_stmt),
+ SWITCH_COND (c_switch_stack->switch_expr),
c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
}
+ else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
+ {
+ if (low_value)
+ error ("case label in statement expression not containing "
+ "enclosing switch statement");
+ else
+ error ("%<default%> label in statement expression not containing "
+ "enclosing switch statement");
+ }
+ else if (c_switch_stack && c_switch_stack->blocked_vm)
+ {
+ if (low_value)
+ error ("case label in scope of identifier with variably modified "
+ "type not containing enclosing switch statement");
+ else
+ error ("%<default%> label in scope of identifier with variably "
+ "modified type not containing enclosing switch statement");
+ }
else if (low_value)
error ("case label not within a switch statement");
else
c_finish_case (tree body)
{
struct c_switch *cs = c_switch_stack;
+ location_t switch_location;
+
+ SWITCH_BODY (cs->switch_expr) = body;
- SWITCH_BODY (cs->switch_stmt) = body;
+ /* We must not be within a statement expression nested in the switch
+ at this point; we might, however, be within the scope of an
+ identifier with variably modified type nested in the switch. */
+ gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
- c_do_switch_warnings (cs->cases, cs->switch_stmt);
+ if (EXPR_HAS_LOCATION (cs->switch_expr))
+ switch_location = EXPR_LOCATION (cs->switch_expr);
+ else
+ switch_location = input_location;
+ c_do_switch_warnings (cs->cases, switch_location,
+ TREE_TYPE (cs->switch_expr),
+ SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
c_switch_stack = cs->next;
found:
if (COND_EXPR_ELSE (inner_if))
- warning ("%Hsuggest explicit braces to avoid ambiguous %<else%>",
+ warning (0, "%Hsuggest explicit braces to avoid ambiguous %<else%>",
&if_locus);
}
if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
{
if (!else_block)
- warning ("%Hempty body in an if-statement",
+ warning (0, "%Hempty body in an if-statement",
EXPR_LOCUS (then_block));
then_block = alloc_stmt_list ();
}
&& TREE_CODE (else_block) == NOP_EXPR
&& !TREE_TYPE (else_block))
{
- warning ("%Hempty body in an else-statement",
+ warning (0, "%Hempty body in an else-statement",
EXPR_LOCUS (else_block));
else_block = alloc_stmt_list ();
}
tree
c_finish_bc_stmt (tree *label_p, bool is_break)
{
+ bool skip;
tree label = *label_p;
+ /* In switch statements break is sometimes stylistically used after
+ a return statement. This can lead to spurious warnings about
+ control reaching the end of a non-void function when it is
+ inlined. Note that we are calling block_may_fallthru with
+ language specific tree nodes; this works because
+ block_may_fallthru returns true when given something it does not
+ understand. */
+ skip = !block_may_fallthru (cur_stmt_list);
+
if (!label)
- *label_p = label = create_artificial_label ();
+ {
+ if (!skip)
+ *label_p = label = create_artificial_label ();
+ }
else if (TREE_CODE (label) != LABEL_DECL)
{
if (is_break)
return NULL_TREE;
}
+ if (skip)
+ return NULL_TREE;
+
return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
}
else if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
- warning ("%Hstatement with no effect",
+ warning (0, "%Hstatement with no effect",
EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
}
else if (warn_unused_value)
c_begin_stmt_expr (void)
{
tree ret;
+ struct c_label_context_se *nstack;
+ struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
later, there is a way to turn off the entire subtree of blocks that
are contained in it. */
keep_next_level ();
ret = c_begin_compound_stmt (true);
+ if (c_switch_stack)
+ {
+ c_switch_stack->blocked_stmt_expr++;
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ }
+ for (glist = label_context_stack_se->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->next = label_context_stack_se;
+ label_context_stack_se = nstack;
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
{
tree last, type, tmp, val;
tree *last_p;
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
body = c_end_compound_stmt (body, true);
+ if (c_switch_stack)
+ {
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ c_switch_stack->blocked_stmt_expr--;
+ }
+ /* It is no longer possible to jump to labels defined within this
+ statement expression. */
+ for (dlist = label_context_stack_se->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this statement expression. */
+ for (glist = label_context_stack_se->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_se->labels_used;
+ else
+ label_context_stack_se->next->labels_used
+ = label_context_stack_se->labels_used;
+ label_context_stack_se = label_context_stack_se->next;
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
+
+/* Begin the scope of an identifier of variably modified type, scope
+ number SCOPE. Jumping from outside this scope to inside it is not
+ permitted. */
+
+void
+c_begin_vm_scope (unsigned int scope)
+{
+ struct c_label_context_vm *nstack;
+ struct c_label_list *glist;
+
+ gcc_assert (scope > 0);
+ if (c_switch_stack && !c_switch_stack->blocked_vm)
+ c_switch_stack->blocked_vm = scope;
+ for (glist = label_context_stack_vm->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->scope = scope;
+ nstack->next = label_context_stack_vm;
+ label_context_stack_vm = nstack;
+}
+
+/* End a scope which may contain identifiers of variably modified
+ type, scope number SCOPE. */
+
+void
+c_end_vm_scope (unsigned int scope)
+{
+ if (label_context_stack_vm == NULL)
+ return;
+ if (c_switch_stack && c_switch_stack->blocked_vm == scope)
+ c_switch_stack->blocked_vm = 0;
+ /* We may have a number of nested scopes of identifiers with
+ variably modified type, all at this depth. Pop each in turn. */
+ while (label_context_stack_vm->scope == scope)
+ {
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
+
+ /* It is no longer possible to jump to labels defined within this
+ scope. */
+ for (dlist = label_context_stack_vm->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this scope. */
+ for (glist = label_context_stack_vm->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_vm->labels_used;
+ else
+ label_context_stack_vm->next->labels_used
+ = label_context_stack_vm->labels_used;
+ label_context_stack_vm = label_context_stack_vm->next;
+ }
+}
\f
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */
/* Floating point division by zero is a legitimate way to obtain
infinities and NaNs. */
if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ warning (0, "division by zero");
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ warning (0, "division by zero");
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
but that does not mean the operands should be
converted to ints! */
result_type = integer_type_node;
- op0 = lang_hooks.truthvalue_conversion (op0);
- op1 = lang_hooks.truthvalue_conversion (op1);
+ op0 = c_common_truthvalue_conversion (op0);
+ op1 = c_common_truthvalue_conversion (op1);
converted = 1;
}
break;
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("right shift count is negative");
+ warning (0, "right shift count is negative");
else
{
if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("right shift count >= width of type");
+ warning (0, "right shift count >= width of type");
}
}
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("left shift count is negative");
+ warning (0, "left shift count is negative");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("left shift count >= width of type");
+ warning (0, "left shift count >= width of type");
}
/* Use the type of the value to be shifted. */
case EQ_EXPR:
case NE_EXPR:
if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
- warning ("comparing floating point with == or != is unsafe");
+ warning (0, "comparing floating point with == or != is unsafe");
/* Result of comparison is always int,
but don't convert the args to int! */
build_type = integer_type_node;
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
if (shorten || common || short_compare)
- result_type = common_type (type0, type1);
+ result_type = c_common_type (type0, type1);
/* For certain operations (which identify themselves by shorten != 0)
if both args were extended from the same smaller type,
&& (unsigned0 || !uns))
result_type
= c_common_signed_or_unsigned_type
- (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ (unsigned0, c_common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
c_common_signed_type (result_type)))
/* OK */;
else
- warning ("comparison between signed and unsigned");
+ warning (0, "comparison between signed and unsigned");
}
/* Warn if two unsigned values are being compared in a size
{
mask = (~(HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
- warning ("comparison of promoted ~unsigned with constant");
+ warning (0, "comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
< TYPE_PRECISION (result_type)))
- warning ("comparison of promoted ~unsigned with unsigned");
+ warning (0, "comparison of promoted ~unsigned with unsigned");
}
}
}
return result;
}
}
+
+
+/* Convert EXPR to be a truth-value, validating its type for this
+ purpose. Passes EXPR to default_function_array_conversion. */
+
+tree
+c_objc_common_truthvalue_conversion (tree expr)
+{
+ expr = default_function_array_conversion (expr);
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case ARRAY_TYPE:
+ error ("used array that cannot be converted to pointer where scalar is required");
+ return error_mark_node;
+
+ case RECORD_TYPE:
+ error ("used struct type value where scalar is required");
+ return error_mark_node;
+
+ case UNION_TYPE:
+ error ("used union type value where scalar is required");
+ return error_mark_node;
+
+ default:
+ break;
+ }
+
+ /* ??? Should we also give an error for void and vectors rather than
+ leaving those to give errors later? */
+ return c_common_truthvalue_conversion (expr);
+}