#include "tree-iterator.h"
#include "tree-gimple.h"
+/* Possible cases of implicit bad conversions. Used to select
+ diagnostic messages in convert_for_assignment. */
+enum impl_conv {
+ ic_argpass,
+ ic_argpass_nonproto,
+ ic_assign,
+ ic_init,
+ ic_return
+};
+
+/* The level of nesting inside "__alignof__". */
+int in_alignof;
+
+/* The level of nesting inside "sizeof". */
+int in_sizeof;
+
+/* The level of nesting inside "typeof". */
+int in_typeof;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
-static tree internal_build_compound_expr (tree, int);
-static tree convert_for_assignment (tree, tree, const char *, tree, tree,
+static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
int);
-static void warn_for_assignment (const char *, const char *, tree, int);
static tree valid_compound_expr_initializer (tree, tree);
static void push_string (const char *);
static void push_member_name (tree);
static int spelling_length (void);
static char *print_spelling (char *);
static void warning_init (const char *);
-static tree digest_init (tree, tree, int);
-static void output_init_element (tree, tree, tree, int);
+static tree digest_init (tree, tree, bool, int);
+static void output_init_element (tree, bool, tree, tree, int);
static void output_pending_init_elements (int);
static int set_designator (int);
static void push_range_stack (tree);
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
-static int lvalue_or_else (tree, const char *);
+static void readonly_error (tree, enum lvalue_use);
+static void record_maybe_used_decl (tree);
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
if (value != 0 && (TREE_CODE (value) == VAR_DECL
|| TREE_CODE (value) == PARM_DECL))
- error ("`%s' has an incomplete type",
+ error ("%qs has an incomplete type",
IDENTIFIER_POINTER (DECL_NAME (value)));
else
{
return;
default:
- abort ();
+ gcc_unreachable ();
}
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- error ("invalid use of undefined type `%s %s'",
+ error ("invalid use of undefined type %<%s %s%>",
type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type)));
else
/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
- error ("invalid use of incomplete typedef `%s'",
+ error ("invalid use of incomplete typedef %qs",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
}
}
if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE)
return t2;
- if (code1 != code2)
- abort ();
+ gcc_assert (code1 == code2);
switch (code1)
{
tree pointed_to_2 = TREE_TYPE (t2);
tree target = composite_type (pointed_to_1, pointed_to_2);
t1 = build_pointer_type (target);
- return build_type_attribute_variant (t1, attributes);
+ t1 = build_type_attribute_variant (t1, attributes);
+ return qualify_type (t1, t2);
}
case ARRAY_TYPE:
{
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+
+ /* We should not have any type quals on arrays at all. */
+ gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
+
/* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
return build_type_attribute_variant (t2, attributes);
+
+ if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
+ return build_type_attribute_variant (t1, attributes);
+ 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));
return build_type_attribute_variant (t1, attributes);
int i;
/* Save space: see if the result is identical to one of the args. */
- if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2))
+ if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2))
return build_type_attribute_variant (t1, attributes);
- if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1))
+ if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1))
return build_type_attribute_variant (t2, attributes);
/* Simple way if one arg fails to specify argument types. */
if (TYPE_ARG_TYPES (t1) == 0)
{
- t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
- return build_type_attribute_variant (t1, attributes);
+ t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
+ t1 = build_type_attribute_variant (t1, attributes);
+ return qualify_type (t1, t2);
}
if (TYPE_ARG_TYPES (t2) == 0)
{
t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
- return build_type_attribute_variant (t1, attributes);
+ t1 = build_type_attribute_variant (t1, attributes);
+ return qualify_type (t1, t2);
}
/* If both args specify argument types, we must merge the two
c_override_global_bindings_to_false = false;
t1 = build_function_type (valtype, newargs);
+ t1 = qualify_type (t1, t2);
/* ... falls through ... */
}
if (t2 == error_mark_node)
return t1;
- if (TREE_CODE (t1) != POINTER_TYPE || TREE_CODE (t2) != POINTER_TYPE)
- abort ();
+ gcc_assert (TREE_CODE (t1) == POINTER_TYPE
+ && TREE_CODE (t2) == POINTER_TYPE);
/* Merge the attributes. */
attributes = targetm.merge_type_attributes (t1, t2);
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
- if (code1 != VECTOR_TYPE && code1 != COMPLEX_TYPE
- && code1 != REAL_TYPE && code1 != INTEGER_TYPE)
- abort ();
-
- if (code2 != VECTOR_TYPE && code2 != COMPLEX_TYPE
- && code2 != REAL_TYPE && code2 != INTEGER_TYPE)
- abort ();
+ gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
+ || code1 == REAL_TYPE || code1 == INTEGER_TYPE);
+ gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
+ || code2 == REAL_TYPE || code2 == INTEGER_TYPE);
/* If one type is a vector type, return that type. (How the usual
arithmetic conversions apply to the vector types extension is not
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- if (! (attrval = targetm.comp_type_attributes (t1, t2)))
+ if (!(attrval = targetm.comp_type_attributes (t1, t2)))
return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
protocol qualifiers may be involved. */
if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0)
break;
+ /* Do not remove mode or aliasing information. */
+ if (TYPE_MODE (t1) != TYPE_MODE (t2)
+ || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
+ break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
break;
if (d1 == 0 || d2 == 0 || d1 == d2)
break;
- d1_zero = ! TYPE_MAX_VALUE (d1);
- d2_zero = ! TYPE_MAX_VALUE (d2);
+ d1_zero = !TYPE_MAX_VALUE (d1);
+ d2_zero = !TYPE_MAX_VALUE (d2);
- d1_variable = (! d1_zero
+ d1_variable = (!d1_zero
&& (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
- d2_variable = (! d2_zero
+ d2_variable = (!d2_zero
&& (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
if (d1_zero && d2_zero)
break;
if (d1_zero || d2_zero
- || ! tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
- || ! tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
+ || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
+ || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
val = 0;
break;
while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t1)))
{
- case 'd': t1 = DECL_CONTEXT (t1); break;
- case 't': t1 = TYPE_CONTEXT (t1); break;
- case 'x': t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */
- default: abort ();
+ case tcc_declaration:
+ t1 = DECL_CONTEXT (t1); break;
+ case tcc_type:
+ t1 = TYPE_CONTEXT (t1); break;
+ case tcc_exceptional:
+ t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */
+ default: gcc_unreachable ();
}
while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t2)))
{
- case 'd': t2 = DECL_CONTEXT (t2); break;
- case 't': t2 = TYPE_CONTEXT (t2); break;
- case 'x': t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */
- default: abort ();
+ case tcc_declaration:
+ t2 = DECL_CONTEXT (t2); break;
+ case tcc_type:
+ t2 = TYPE_CONTEXT (t2); break;
+ case tcc_exceptional:
+ t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */
+ default: gcc_unreachable ();
}
return t1 == t2;
break;
}
tagged_tu_seen_base = tts.next;
- if (! ok)
+ if (!ok)
return 0;
}
return needs_warning ? 2 : 1;
}
default:
- abort ();
+ gcc_unreachable ();
}
}
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'");
+ /* 'volatile' qualifiers on a function's return type used to mean
+ the function is noreturn. */
+ if (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);
else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
|| TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
;
- else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
- TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+ else if (!(newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
+ TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
\f
/* Compute the size to increment a pointer by. */
-tree
+static tree
c_size_in_bytes (tree type)
{
enum tree_code code = TREE_CODE (type);
isn't valid for a PARM_DECL. */
current_function_decl != 0
&& TREE_CODE (decl) != PARM_DECL
- && ! TREE_THIS_VOLATILE (decl)
+ && !TREE_THIS_VOLATILE (decl)
&& TREE_READONLY (decl)
&& DECL_INITIAL (decl) != 0
&& TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
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));
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
if (code == FUNCTION_TYPE)
{
int volatilep = 0;
int lvalue_array_p;
- if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
+ if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
{
constp = TREE_READONLY (exp);
volatilep = TREE_THIS_VOLATILE (exp);
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
tree op1 = default_conversion (TREE_OPERAND (exp, 1));
- return build (COMPOUND_EXPR, TREE_TYPE (op1),
- TREE_OPERAND (exp, 0), op1);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
+ TREE_OPERAND (exp, 0), op1);
}
lvalue_array_p = !not_lvalue && lvalue_p (exp);
&& 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));
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
/* Normally convert enums to int,
but convert wide enums to something wider. */
if (!objc_is_public (datum, component))
return error_mark_node;
- /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
- 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), non_lvalue (value));
- }
- default:
- break;
- }
-
/* See if there is a field or component with name COMPONENT. */
if (code == RECORD_TYPE || code == UNION_TYPE)
if (!field)
{
- error ("%s has no member named `%s'",
- code == RECORD_TYPE ? "structure" : "union",
+ error ("%qT has no member named %qs", type,
IDENTIFIER_POINTER (component));
return error_mark_node;
}
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
- ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
- NULL_TREE);
+ ref = build3 (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+ NULL_TREE);
if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
TREE_READONLY (ref) = 1;
if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
return ref;
}
else if (code != ERROR_MARK)
- error ("request for member `%s' in something not a structure or union",
+ error ("request for member %qs in something not a structure or union",
IDENTIFIER_POINTER (component));
return error_mark_node;
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning ("dereferencing `void *' pointer");
+ warning ("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
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error ("invalid type argument of `%s'", errorstring);
+ error ("invalid type argument of %qs", errorstring);
return error_mark_node;
}
tree
build_array_ref (tree array, tree index)
{
- if (index == 0)
- {
- error ("subscript missing in array reference");
- return error_mark_node;
- }
-
+ bool swapped = false;
if (TREE_TYPE (array) == error_mark_node
|| TREE_TYPE (index) == error_mark_node)
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+ if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE)
{
- tree rval, type;
-
- /* Subscripting with type char is likely to lose
- on a machine where chars are signed.
- So warn on any machine, but optionally.
- Don't warn for unsigned char since that type is safe.
- Don't warn for signed char because anyone who uses that
- must have done so deliberately. */
- if (warn_char_subscripts
- && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("array subscript has type `char'");
-
- /* Apply default promotions *after* noticing character types. */
- index = default_conversion (index);
-
- /* Require integer *after* promotion, for sake of enums. */
- if (TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE)
+ tree temp;
+ if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
{
- error ("array subscript is not an integer");
+ error ("subscripted value is neither array nor pointer");
return error_mark_node;
}
+ temp = array;
+ array = index;
+ index = temp;
+ swapped = true;
+ }
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (index)))
+ {
+ error ("array subscript is not an integer");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE)
+ {
+ error ("subscripted value is pointer to function");
+ return error_mark_node;
+ }
+
+ /* Subscripting with type char is likely to lose on a machine where
+ chars are signed. So warn on any machine, but optionally. Don't
+ warn for unsigned char since that type is safe. Don't warn for
+ signed char because anyone who uses that must have done so
+ deliberately. ??? Existing practice has also been to warn only
+ when the char index is syntactically the index, not for
+ char[array]. */
+ if (warn_char_subscripts && !swapped
+ && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
+ warning ("array subscript has type %<char%>");
+
+ /* Apply default promotions *after* noticing character types. */
+ index = default_conversion (index);
+
+ gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+ {
+ tree rval, type;
/* An array that is indexed by a non-constant
cannot be stored in a register; we must be able to do
to access a non-existent part of the register. */
if (TREE_CODE (index) == INTEGER_CST
&& TYPE_DOMAIN (TREE_TYPE (array))
- && ! int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
+ && !int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
{
if (!c_mark_addressable (array))
return error_mark_node;
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
- pedwarn ("ISO C forbids subscripting `register' array");
- else if (! flag_isoc99 && ! lvalue_p (foo))
+ pedwarn ("ISO C forbids subscripting %<register%> array");
+ else if (!flag_isoc99 && !lvalue_p (foo))
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
- rval = build (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
+ 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. */
TREE_READONLY (rval)
| TREE_THIS_VOLATILE (array));
return require_complete_type (fold (rval));
}
+ else
+ {
+ tree ar = default_conversion (array);
- {
- tree ar = default_conversion (array);
- tree ind = default_conversion (index);
-
- /* Do the same warning check as above, but only on the part that's
- syntactically the index and only if it is also semantically
- the index. */
- if (warn_char_subscripts
- && TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
- && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("subscript has type `char'");
-
- /* Put the integer in IND to simplify error checking. */
- if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
- {
- tree temp = ar;
- ar = ind;
- ind = temp;
- }
-
- if (ar == error_mark_node)
- return ar;
+ if (ar == error_mark_node)
+ return ar;
- if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE)
- {
- error ("subscripted value is neither array nor pointer");
- return error_mark_node;
- }
- if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
- {
- error ("array subscript is not an integer");
- return error_mark_node;
- }
+ gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
+ gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
- return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0),
- "array indexing");
- }
+ return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
+ "array indexing");
+ }
}
\f
/* Build an external reference to identifier ID. FUN indicates
{
tree ref;
tree decl = lookup_name (id);
- tree objc_ivar = lookup_objc_ivar (id);
+
+ /* In Objective-C, an instance variable (ivar) may be preferred to
+ whatever lookup_name() found. */
+ decl = objc_lookup_ivar (decl, id);
if (decl && decl != error_mark_node)
- {
- /* Properly declared variable or function reference. */
- if (!objc_ivar)
- ref = decl;
- else if (decl != objc_ivar && !DECL_FILE_SCOPE_P (decl))
- {
- warning ("local declaration of `%s' hides instance variable",
- IDENTIFIER_POINTER (id));
- ref = decl;
- }
- else
- ref = objc_ivar;
- }
- else if (objc_ivar)
- ref = objc_ivar;
+ ref = decl;
else if (fun)
/* Implicit function declaration. */
ref = implicitly_declare (id);
assemble_external (ref);
TREE_USED (ref) = 1;
+ if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
+ {
+ if (!in_sizeof && !in_typeof)
+ C_DECL_USED (ref) = 1;
+ else if (DECL_INITIAL (ref) == 0
+ && DECL_EXTERNAL (ref)
+ && !TREE_PUBLIC (ref))
+ record_maybe_used_decl (ref);
+ }
+
if (TREE_CODE (ref) == CONST_DECL)
{
ref = DECL_INITIAL (ref);
return ref;
}
+/* Record details of decls possibly used inside sizeof or typeof. */
+struct maybe_used_decl
+{
+ /* The decl. */
+ tree decl;
+ /* The level seen at (in_sizeof + in_typeof). */
+ int level;
+ /* The next one at this level or above, or NULL. */
+ struct maybe_used_decl *next;
+};
+
+static struct maybe_used_decl *maybe_used_decls;
+
+/* Record that DECL, an undefined static function reference seen
+ inside sizeof or typeof, might be used if the operand of sizeof is
+ a VLA type or the operand of typeof is a variably modified
+ type. */
+
+static void
+record_maybe_used_decl (tree decl)
+{
+ struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
+ t->decl = decl;
+ t->level = in_sizeof + in_typeof;
+ t->next = maybe_used_decls;
+ maybe_used_decls = t;
+}
+
+/* Pop the stack of decls possibly used inside sizeof or typeof. If
+ USED is false, just discard them. If it is true, mark them used
+ (if no longer inside sizeof or typeof) or move them to the next
+ level up (if still inside sizeof or typeof). */
+
+void
+pop_maybe_used (bool used)
+{
+ struct maybe_used_decl *p = maybe_used_decls;
+ int cur_level = in_sizeof + in_typeof;
+ while (p && p->level > cur_level)
+ {
+ if (used)
+ {
+ if (cur_level == 0)
+ C_DECL_USED (p->decl) = 1;
+ else
+ p->level = cur_level;
+ }
+ p = p->next;
+ }
+ if (!used || cur_level == 0)
+ maybe_used_decls = p;
+}
+
+/* Return the result of sizeof applied to EXPR. */
+
+struct c_expr
+c_expr_sizeof_expr (struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ ret.value = c_sizeof (TREE_TYPE (expr.value));
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ }
+ return ret;
+}
+
+/* Return the result of sizeof applied to T, a structure for the type
+ name passed to sizeof (rather than the type itself). */
+
+struct c_expr
+c_expr_sizeof_type (struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ type = groktypename (t);
+ ret.value = c_sizeof (type);
+ ret.original_code = ERROR_MARK;
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
TREE_VALUE of each node is a parameter-expression.
if (!(TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))
{
- error ("called object is not a function");
+ error ("called object %qE is not a function", function);
return error_mark_node;
}
??? This doesn't work for Objective-C because objc_comptypes
refuses to compare function prototypes, yet the compiler appears
to build calls that are flagged as invalid by C's comptypes. */
- if (! c_dialect_objc ()
+ if (!c_dialect_objc ()
&& TREE_CODE (function) == NOP_EXPR
&& TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
- && ! comptypes (fntype, TREE_TYPE (tem)))
+ && !comptypes (fntype, TREE_TYPE (tem)))
{
tree return_type = TREE_TYPE (fntype);
tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
else
rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
- return build (COMPOUND_EXPR, return_type, trap, rhs);
+ return build2 (COMPOUND_EXPR, return_type, trap, rhs);
}
}
function prototype, or apply default promotions. */
coerced_params
- = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
+ = convert_arguments (TYPE_ARG_TYPES (fntype), params, function, fundecl);
+
+ if (coerced_params == error_mark_node)
+ return error_mark_node;
/* Check that the arguments to the function are valid. */
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
- to do something useful. */
-
- if (TREE_CODE (function) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
- && DECL_BUILT_IN (TREE_OPERAND (function, 0)))
- {
- result = expand_tree_builtin (TREE_OPERAND (function, 0),
- params, coerced_params);
- if (result)
- return result;
- }
-
- result = build (CALL_EXPR, TREE_TYPE (fntype),
- function, coerced_params, NULL_TREE);
+ result = build3 (CALL_EXPR, TREE_TYPE (fntype),
+ function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1;
if (require_constant_value)
\f
/* Convert the argument expressions in the list VALUES
to the types in the list TYPELIST. The result is a list of converted
- argument expressions.
+ argument expressions, unless there are too few arguments in which
+ case it is error_mark_node.
If TYPELIST is exhausted, or when an element has NULL as its type,
perform the default conversions.
It may be 0, if that info is not available.
It is used only for generating error messages.
- NAME is an IDENTIFIER_NODE or 0. It is used only for error messages.
+ FUNCTION is a tree for the called function. It is used only for
+ error messages, where it is formatted with %qE.
This is also where warnings about wrong number of args are generated.
with the elements of the list in the TREE_VALUE slots of those nodes. */
static tree
-convert_arguments (tree typelist, tree values, tree name, tree fundecl)
+convert_arguments (tree typelist, tree values, tree function, tree fundecl)
{
tree typetail, valtail;
tree result = NULL;
int parmnum;
+ tree selector;
+
+ /* Change pointer to function to the function itself for
+ diagnostics. */
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ function = TREE_OPERAND (function, 0);
+
+ /* Handle an ObjC selector specially for diagnostics. */
+ selector = objc_message_selector ();
/* Scan the given expressions and types, producing individual
converted arguments and pushing them on RESULT in reverse order. */
{
tree type = typetail ? TREE_VALUE (typetail) : 0;
tree val = TREE_VALUE (valtail);
+ tree rname = function;
+ int argnum = parmnum + 1;
if (type == void_type_node)
{
- if (name)
- error ("too many arguments to function `%s'",
- IDENTIFIER_POINTER (name));
- else
- error ("too many arguments to function");
+ error ("too many arguments to function %qE", function);
break;
}
+ if (selector && argnum > 2)
+ {
+ rname = selector;
+ 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. */
differ from the default conversions. */
if (warn_conversion || warn_traditional)
{
- int formal_prec = TYPE_PRECISION (type);
+ unsigned int formal_prec = TYPE_PRECISION (type);
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("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)
- warn_for_assignment ("%s as integer rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("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)
- warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("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)))
- warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("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)))
- warn_for_assignment ("%s as complex rather than integer due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("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)
- warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("passing argument %d of %qE as floating "
+ "rather than complex due to prototype",
+ argnum, rname);
/* ??? At some point, messages should be written about
conversions between complex types, but that's too messy
to do now. */
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
if (formal_prec == TYPE_PRECISION (float_type_node))
- warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("passing argument %d of %qE as %<float%> "
+ "rather than %<double%> due to prototype",
+ argnum, rname);
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("passing argument %d of %qE with different "
+ "width due to prototype", argnum, rname);
else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
;
/* Don't complain if the formal parameter type
&& TYPE_UNSIGNED (TREE_TYPE (val)))
;
else if (TYPE_UNSIGNED (type))
- warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("passing argument %d of %qE as unsigned "
+ "due to prototype", argnum, rname);
else
- warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1);
+ warning ("passing argument %d of %qE as signed "
+ "due to prototype", argnum, rname);
}
}
- parmval = convert_for_assignment (type, val,
- (char *) 0, /* arg passing */
- fundecl, name, parmnum + 1);
+ parmval = convert_for_assignment (type, val, ic_argpass,
+ fundecl, function,
+ parmnum + 1);
if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
&& INTEGRAL_TYPE_P (type)
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
- if (name)
- error ("too few arguments to function `%s'",
- IDENTIFIER_POINTER (name));
- else
- error ("too few arguments to function");
+ error ("too few arguments to function %qE", function);
+ return error_mark_node;
}
return nreverse (result);
we check for operands that were written with other binary operators
in a way that is likely to confuse the user. */
-tree
-parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
+struct c_expr
+parser_build_binary_op (enum tree_code code, struct c_expr arg1,
+ struct c_expr arg2)
{
- tree result = build_binary_op (code, arg1, arg2, 1);
+ struct c_expr result;
- char class;
- char class1 = TREE_CODE_CLASS (TREE_CODE (arg1));
- char class2 = TREE_CODE_CLASS (TREE_CODE (arg2));
- enum tree_code code1 = ERROR_MARK;
- enum tree_code code2 = ERROR_MARK;
+ enum tree_code code1 = arg1.original_code;
+ enum tree_code code2 = arg2.original_code;
- if (TREE_CODE (result) == ERROR_MARK)
- return error_mark_node;
+ result.value = build_binary_op (code, arg1.value, arg2.value, 1);
+ result.original_code = code;
- if (IS_EXPR_CODE_CLASS (class1))
- code1 = C_EXP_ORIGINAL_CODE (arg1);
- if (IS_EXPR_CODE_CLASS (class2))
- code2 = C_EXP_ORIGINAL_CODE (arg2);
+ if (TREE_CODE (result.value) == ERROR_MARK)
+ return result;
/* Check for cases such as x+y<<z which users are likely
- to misinterpret. If parens are used, C_EXP_ORIGINAL_CODE
- is cleared to prevent these warnings. */
+ to misinterpret. */
if (warn_parentheses)
{
if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of |");
}
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of ^");
}
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning ("suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
- if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+ if (TREE_CODE_CLASS (code1) == tcc_comparison
+ || TREE_CODE_CLASS (code2) == tcc_comparison)
warning ("suggest parentheses around comparison in operand of &");
}
- }
-
- /* Similarly, check for cases like 1<=i<=10 that are probably errors. */
- if (TREE_CODE_CLASS (code) == '<' && extra_warnings
- && (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<'))
- warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
+ /* 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");
- unsigned_conversion_warning (result, arg1);
- unsigned_conversion_warning (result, arg2);
- overflow_warning (result);
-
- class = TREE_CODE_CLASS (TREE_CODE (result));
-
- /* Record the code that was specified in the source,
- for the sake of warnings about confusing nesting. */
- if (IS_EXPR_CODE_CLASS (class))
- C_SET_EXP_ORIGINAL_CODE (result, code);
- else
- {
- /* We used to use NOP_EXPR rather than NON_LVALUE_EXPR
- so that convert_for_assignment wouldn't strip it.
- That way, we got warnings for things like p = (1 - 1).
- But it turns out we should not get those warnings. */
- result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result);
- C_SET_EXP_ORIGINAL_CODE (result, code);
}
+ unsigned_conversion_warning (result.value, arg1.value);
+ unsigned_conversion_warning (result.value, arg2.value);
+ overflow_warning (result.value);
+
return result;
}
\f
if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn ("pointer of type `void *' used in subtraction");
+ pedwarn ("pointer of type %<void *%> used in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
pedwarn ("pointer to a function used in subtraction");
}
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold (build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)));
+ return fold (build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)));
}
\f
/* Construct and perhaps optimize a tree representation
is enough to prevent anybody from looking inside for
associativity, but won't generate any code. */
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
- || typecode == COMPLEX_TYPE))
+ || typecode == COMPLEX_TYPE
+ || typecode == VECTOR_TYPE))
{
error ("wrong type argument to unary plus");
return error_mark_node;
{
code = CONJ_EXPR;
if (pedantic)
- pedwarn ("ISO C does not support `~' for complex conjugation");
+ pedwarn ("ISO C does not support %<~%> for complex conjugation");
if (!noconvert)
arg = default_conversion (arg);
}
tree real, imag;
if (pedantic)
- pedwarn ("ISO C does not support `++' and `--' on complex types");
+ pedwarn ("ISO C does not support %<++%> and %<--%>"
+ " on complex types");
arg = stabilize_reference (arg);
real = build_unary_op (REALPART_EXPR, arg, 1);
imag = build_unary_op (IMAGPART_EXPR, arg, 1);
- return build (COMPLEX_EXPR, TREE_TYPE (arg),
- build_unary_op (code, real, 1), imag);
+ return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
+ build_unary_op (code, real, 1), imag);
}
/* Report invalid types. */
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
- ? "invalid lvalue in increment"
- : "invalid lvalue in decrement")))
+ ? lv_increment
+ : lv_decrement)))
return error_mark_node;
/* Report a read-only lvalue. */
readonly_error (arg,
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"));
+ ? lv_increment : lv_decrement));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
else
- val = build (code, TREE_TYPE (arg), arg, inc);
+ val = build2 (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
val = convert (result_type, val);
if (TREE_CODE (val) != code)
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
- && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
+ && !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
to which the address will point. Note that you can't get a
restricted pointer by taking the address of something, so we
only have to deal with `const' and `volatile' here. */
- if ((DECL_P (arg) || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
+ if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
&& (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
argtype = c_build_type_variant (argtype,
TREE_READONLY (arg),
TREE_THIS_VOLATILE (arg));
- argtype = build_pointer_type (argtype);
-
if (!c_mark_addressable (arg))
return error_mark_node;
- {
- tree addr;
+ gcc_assert (TREE_CODE (arg) != COMPONENT_REF
+ || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)));
- if (TREE_CODE (arg) == COMPONENT_REF)
- {
- tree field = TREE_OPERAND (arg, 1);
+ argtype = build_pointer_type (argtype);
- addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
+ /* ??? Cope with user tricks that amount to offsetof. Delete this
+ when we have proper support for integer constant expressions. */
+ val = get_base_address (arg);
+ if (val && TREE_CODE (val) == INDIRECT_REF
+ && integer_zerop (TREE_OPERAND (val, 0)))
+ return fold_convert (argtype, fold_offsetof (arg));
- if (DECL_C_BIT_FIELD (field))
- {
- error ("attempt to take address of bit-field structure member `%s'",
- IDENTIFIER_POINTER (DECL_NAME (field)));
- return error_mark_node;
- }
+ val = build1 (ADDR_EXPR, argtype, arg);
- addr = fold (build (PLUS_EXPR, argtype,
- convert (argtype, addr),
- convert (argtype, byte_position (field))));
- }
- else
- addr = build1 (code, argtype, arg);
+ if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+ TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
- if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
- TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
-
- return addr;
- }
+ return val;
default:
break;
&& TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
case BIND_EXPR:
- case RTL_EXPR:
return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
default:
return 0;
}
}
-
-/* Return nonzero if REF is an lvalue valid for this language;
- otherwise, print an error message and return zero. */
-
-static int
-lvalue_or_else (tree ref, const char *msgid)
-{
- int win = lvalue_p (ref);
-
- if (! win)
- error ("%s", msgid);
-
- return win;
-}
-
\f
-/* Warn about storing in something that is `const'. */
+/* Give an error for storing in something that is 'const'. */
-void
-readonly_error (tree arg, const char *msgid)
+static void
+readonly_error (tree arg, enum lvalue_use use)
{
+ gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement);
+ /* Using this macro rather than (for example) arrays of messages
+ ensures that all the format strings are checked at compile
+ time. */
+#define READONLY_MSG(A, I, D) (use == lv_assign \
+ ? (A) \
+ : (use == lv_increment ? (I) : (D)))
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- readonly_error (TREE_OPERAND (arg, 0), msgid);
+ readonly_error (TREE_OPERAND (arg, 0), use);
else
- error ("%s of read-only member `%s'", _(msgid),
+ 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))));
}
else if (TREE_CODE (arg) == VAR_DECL)
- error ("%s of read-only variable `%s'", _(msgid),
+ 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)));
else
- error ("%s of read-only location", _(msgid));
+ error (READONLY_MSG (N_("assignment of read-only location"),
+ N_("increment of read-only location"),
+ N_("decrement of read-only location")));
}
\f
/* Mark EXP saying that we need to be able to take the
case COMPONENT_REF:
if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
{
- error ("cannot take address of bit-field `%s'",
- IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
+ error
+ ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1));
return false;
}
{
if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
{
- error ("global register variable `%s' used in nested function",
- IDENTIFIER_POINTER (DECL_NAME (x)));
+ error
+ ("global register variable %qD used in nested function", x);
return false;
}
- pedwarn ("register variable `%s' used in nested function",
- IDENTIFIER_POINTER (DECL_NAME (x)));
+ pedwarn ("register variable %qD used in nested function", x);
}
else if (C_DECL_REGISTER (x))
{
if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
- {
- error ("address of global register variable `%s' requested",
- IDENTIFIER_POINTER (DECL_NAME (x)));
- return false;
- }
-
- pedwarn ("address of register variable `%s' requested",
- IDENTIFIER_POINTER (DECL_NAME (x)));
+ error ("address of global register variable %qD requested", x);
+ else
+ error ("address of register variable %qD requested", x);
+ return false;
}
- put_var_into_stack (x, /*rescan=*/true);
/* drops in */
case FUNCTION_DECL:
/* Do not warn if the result type is signed, since the
signed type will only be chosen if it can represent
all the values of the unsigned type. */
- if (! TYPE_UNSIGNED (result_type))
+ if (!TYPE_UNSIGNED (result_type))
/* OK */;
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+ pedwarn ("ISO C forbids conditional expr between "
+ "%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
TREE_TYPE (type2)));
}
else if (VOID_TYPE_P (TREE_TYPE (type2)))
{
if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+ pedwarn ("ISO C forbids conditional expr between "
+ "%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
TREE_TYPE (type1)));
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
- if (! integer_zerop (op2))
+ if (!integer_zerop (op2))
pedwarn ("pointer/integer type mismatch in conditional expression");
else
{
if (TREE_CODE (ifexp) == INTEGER_CST)
return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
- return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
+ return fold (build3 (COND_EXPR, result_type, ifexp, op1, op2));
}
\f
-/* Given a list of expressions, return a compound expression
- that performs them all and returns the value of the last of them. */
+/* Return a compound expression that performs two expressions and
+ returns the value of the second of them. */
tree
-build_compound_expr (tree list)
+build_compound_expr (tree expr1, tree expr2)
{
- return internal_build_compound_expr (list, TRUE);
-}
-
-static tree
-internal_build_compound_expr (tree list, int first_p)
-{
- tree rest;
-
- if (TREE_CHAIN (list) == 0)
- {
- /* 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)))
- return non_lvalue (TREE_VALUE (list));
- return TREE_VALUE (list);
- }
-
- rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
+ /* Convert arrays and functions to pointers. */
+ expr2 = default_function_array_conversion (expr2);
- if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+ if (!TREE_SIDE_EFFECTS (expr1))
{
/* 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 (TREE_VALUE (list)) == CONVERT_EXPR
- && VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
+ && !(TREE_CODE (expr1) == CONVERT_EXPR
+ && VOID_TYPE_P (TREE_TYPE (expr1))))
warning ("left-hand operand of comma expression has no effect");
}
`foo() + bar(), baz()' the result of the `+' operator is not used,
so we should issue a warning. */
else if (warn_unused_value)
- warn_if_unused_value (TREE_VALUE (list), input_location);
+ warn_if_unused_value (expr1, input_location);
- return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
}
/* Build an expression representing a cast to type TYPE of expression EXPR. */
/* 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 (!c_dialect_objc () || !objc_is_object_ptr (type))
- type = TYPE_MAIN_VARIANT (type);
+ if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
+ return build1 (NOP_EXPR, type, expr);
+
+ type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
{
t = digest_init (type,
build_constructor (type,
build_tree_list (field, value)),
- 0);
+ true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
TREE_INVARIANT (t) = TREE_INVARIANT (value);
return t;
if (warn_bad_function_cast
&& TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning ("cast does not match function type");
+ warning ("cast from function call of type %qT to non-matching "
+ "type %qT", otype, type);
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
{
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-
- if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
+ if (EXPR_P (ovalue))
+ /* If OVALUE had overflow set, then so will VALUE, so it
+ is safe to overwrite. */
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ else
+ TREE_OVERFLOW (value) = 0;
+
+ if (CONSTANT_CLASS_P (ovalue))
+ /* Similarly, constant_overflow cannot have become
+ cleared. */
TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
}
}
- /* Don't let (void *) (FOO *) 0 be a null pointer constant. */
- if (TREE_CODE (value) == INTEGER_CST
- && TREE_CODE (expr) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
- value = non_lvalue (value);
-
/* Don't let a cast be an lvalue. */
if (value == expr)
value = non_lvalue (value);
/* Interpret a cast of expression EXPR to type TYPE. */
tree
-c_cast_expr (tree type, tree expr)
+c_cast_expr (struct c_type_name *type_name, tree expr)
{
+ tree type;
int saved_wsp = warn_strict_prototypes;
/* This avoids warnings about unprototyped casts on
integers. E.g. "#define SIG_DFL (void(*)())0". */
if (TREE_CODE (expr) == INTEGER_CST)
warn_strict_prototypes = 0;
- type = groktypename (type);
+ type = groktypename (type_name);
warn_strict_prototypes = saved_wsp;
return build_c_cast (type, expr);
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
+ if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
- /* Warn about storing in something that is `const'. */
+ /* Give an error for storing in something that is 'const'. */
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
- readonly_error (lhs, "assignment");
+ readonly_error (lhs, lv_assign);
/* If storing into a structure or union member,
it has probably been given type `int'.
/* Convert new value to destination type. */
- newrhs = convert_for_assignment (lhstype, newrhs, _("assignment"),
+ newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
NULL_TREE, NULL_TREE, 0);
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
- /* Scan operands */
+ /* Scan operands. */
- result = build (MODIFY_EXPR, lhstype, lhs, newrhs);
+ result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
/* If we got the LHS in a different type for storing in,
if (olhstype == TREE_TYPE (result))
return result;
- return convert_for_assignment (olhstype, result, _("assignment"),
+ return convert_for_assignment (olhstype, result, ic_assign,
NULL_TREE, NULL_TREE, 0);
}
\f
The real work of conversion is done by `convert'.
The purpose of this function is to generate error messages
for assignments that are not allowed in C.
- ERRTYPE is a string to use in error messages:
- "assignment", "return", etc. If it is null, this is parameter passing
- for a function call (and different error messages are output).
+ ERRTYPE says whether it is argument passing, assignment,
+ initialization or return.
- FUNNAME is the name of the function being called,
- as an IDENTIFIER_NODE, or null.
+ FUNCTION is a tree for the function being called.
PARMNUM is the number of the argument, for printing in error messages. */
static tree
-convert_for_assignment (tree type, tree rhs, const char *errtype,
- tree fundecl, tree funname, int parmnum)
+convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
+ tree fundecl, tree function, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
tree rhstype;
enum tree_code coder;
+ tree rname = NULL_TREE;
+
+ if (errtype == ic_argpass || errtype == ic_argpass_nonproto)
+ {
+ tree selector;
+ /* Change pointer to function to the function itself for
+ diagnostics. */
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ function = TREE_OPERAND (function, 0);
+
+ /* Handle an ObjC selector specially for diagnostics. */
+ selector = objc_message_selector ();
+ rname = function;
+ if (selector && parmnum > 2)
+ {
+ rname = selector;
+ parmnum -= 2;
+ }
+ }
+
+ /* This macro is used to emit diagnostics to ensure that all format
+ strings are complete sentences, visible to gettext and checked at
+ compile time. */
+#define WARN_FOR_ASSIGNMENT(AR, AS, IN, RE) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ pedwarn (AR, parmnum, rname); \
+ break; \
+ case ic_argpass_nonproto: \
+ warning (AR, parmnum, rname); \
+ break; \
+ case ic_assign: \
+ pedwarn (AS); \
+ break; \
+ case ic_init: \
+ pedwarn (IN); \
+ break; \
+ case ic_return: \
+ pedwarn (RE); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } 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
if (coder == VOID_TYPE)
{
+ /* Except for passing an argument to an unprototyped function,
+ this is a constraint violation. When passing an argument to
+ an unprototyped function, it is compile-time undefined;
+ making it a constraint in that case was rejected in
+ DR#252. */
error ("void value not ignored as it ought to be");
return error_mark_node;
}
return rhs;
}
/* Some types can interconvert without explicit casts. */
- else if (codel == VECTOR_TYPE
+ else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
&& vector_types_convertible_p (type, TREE_TYPE (rhs)))
return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */
/* Conversion to a transparent union from its member types.
This applies only to function arguments. */
- else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
+ else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
+ && (errtype == ic_argpass || errtype == ic_argpass_nonproto))
{
tree memb_types;
tree marginal_memb_type = 0;
break;
/* Keep looking for a better type, but remember this one. */
- if (! marginal_memb_type)
+ if (!marginal_memb_type)
marginal_memb_type = memb_type;
}
}
if (memb_types || marginal_memb_type)
{
- if (! memb_types)
+ if (!memb_types)
{
/* We have only a marginally acceptable member type;
it needs a warning. */
function where an ordinary one is wanted, but not
vice-versa. */
if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- warn_for_assignment ("%s makes qualified function pointer from unqualified",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE "
+ "makes qualified function "
+ "pointer from unqualified"),
+ N_("assignment makes qualified "
+ "function pointer from "
+ "unqualified"),
+ N_("initialization makes qualified "
+ "function pointer from "
+ "unqualified"),
+ N_("return makes qualified function "
+ "pointer from unqualified"));
}
else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- warn_for_assignment ("%s discards qualifiers from pointer target type",
- errtype, funname,
- parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ "qualifiers from pointer target type"),
+ N_("assignment discards qualifiers "
+ "from pointer target type"),
+ N_("initialization discards qualifiers "
+ "from pointer target type"),
+ N_("return discards qualifiers from "
+ "pointer target type"));
}
- if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
+ if (pedantic && !DECL_IN_SYSTEM_HEADER (fundecl))
pedwarn ("ISO C prohibits argument conversion to union type");
return build1 (NOP_EXPR, type, rhs);
which are not ANSI null ptr constants. */
&& (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- warn_for_assignment ("ISO C forbids %s between function pointer and `void *'",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("ISO C forbids passing argument %d of "
+ "%qE between function pointer "
+ "and %<void *%>"),
+ N_("ISO C forbids assignment between "
+ "function pointer and %<void *%>"),
+ N_("ISO C forbids initialization between "
+ "function pointer and %<void *%>"),
+ N_("ISO C forbids return between function "
+ "pointer and %<void *%>"));
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- warn_for_assignment ("%s discards qualifiers from pointer target type",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ "qualifiers from pointer target type"),
+ N_("assignment discards qualifiers "
+ "from pointer target type"),
+ N_("initialization discards qualifiers "
+ "from pointer target type"),
+ N_("return discards qualifiers from "
+ "pointer target 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)
|| target_cmp)
;
/* If there is a mismatch, do warn. */
- else if (pedantic)
- warn_for_assignment ("pointer targets in %s differ in signedness",
- errtype, funname, parmnum);
+ else
+ WARN_FOR_ASSIGNMENT (N_("pointer targets in passing argument "
+ "%d of %qE differ in signedness"),
+ N_("pointer targets in assignment "
+ "differ in signedness"),
+ N_("pointer targets in initialization "
+ "differ in signedness"),
+ N_("pointer targets in return differ "
+ "in signedness"));
}
else if (TREE_CODE (ttl) == FUNCTION_TYPE
&& TREE_CODE (ttr) == FUNCTION_TYPE)
it is okay to use a const or volatile function
where an ordinary one is wanted, but not vice-versa. */
if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- warn_for_assignment ("%s makes qualified function pointer from unqualified",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes "
+ "qualified function pointer "
+ "from unqualified"),
+ N_("assignment makes qualified function "
+ "pointer from unqualified"),
+ N_("initialization makes qualified "
+ "function pointer from unqualified"),
+ N_("return makes qualified function "
+ "pointer from unqualified"));
}
}
else
- warn_for_assignment ("%s from incompatible pointer type",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE from "
+ "incompatible pointer type"),
+ N_("assignment from incompatible pointer type"),
+ N_("initialization from incompatible "
+ "pointer type"),
+ N_("return from incompatible pointer type"));
return convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
{
+ /* ??? This should not be an error when inlining calls to
+ unprototyped functions. */
error ("invalid use of non-lvalue array");
return error_mark_node;
}
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
- if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
+ if (!(TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
&&
- ! (TREE_CODE (rhs) == NOP_EXPR
- && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
- && integer_zerop (TREE_OPERAND (rhs, 0))))
- warn_for_assignment ("%s makes pointer from integer without a cast",
- errtype, funname, parmnum);
+ !(TREE_CODE (rhs) == NOP_EXPR
+ && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
+ && integer_zerop (TREE_OPERAND (rhs, 0))))
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes "
+ "pointer from integer without a cast"),
+ N_("assignment makes pointer from integer "
+ "without a cast"),
+ N_("initialization makes pointer from "
+ "integer without a cast"),
+ N_("return makes pointer from integer "
+ "without a cast"));
return convert (type, rhs);
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
- warn_for_assignment ("%s makes integer from pointer without a cast",
- errtype, funname, parmnum);
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes integer "
+ "from pointer without a cast"),
+ N_("assignment makes integer from pointer "
+ "without a cast"),
+ N_("initialization makes integer from pointer "
+ "without a cast"),
+ N_("return makes integer from pointer "
+ "without a cast"));
return convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
return convert (type, rhs);
- if (!errtype)
+ switch (errtype)
{
- if (funname)
- {
- tree selector = objc_message_selector ();
-
- if (selector && parmnum > 2)
- error ("incompatible type for argument %d of `%s'",
- parmnum - 2, IDENTIFIER_POINTER (selector));
- else
- error ("incompatible type for argument %d of `%s'",
- parmnum, IDENTIFIER_POINTER (funname));
- }
- else
- error ("incompatible type for argument %d of indirect function call",
- parmnum);
+ case ic_argpass:
+ case ic_argpass_nonproto:
+ /* ??? This should not be an error when inlining calls to
+ unprototyped functions. */
+ error ("incompatible type for argument %d of %qE", parmnum, rname);
+ break;
+ case ic_assign:
+ error ("incompatible types in assignment");
+ break;
+ case ic_init:
+ error ("incompatible types in initialization");
+ break;
+ case ic_return:
+ error ("incompatible types in return");
+ break;
+ default:
+ gcc_unreachable ();
}
- else
- error ("incompatible types in %s", errtype);
return error_mark_node;
}
/* If FN was prototyped, the value has been converted already
in convert_arguments. */
- if (! value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
+ 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), argnum);
+ ic_argpass_nonproto, fn,
+ fn, argnum);
if (targetm.calls.promote_prototypes (TREE_TYPE (fn))
&& 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 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 (const char *msgid, const char *opname, tree function,
- int argnum)
-{
- if (opname == 0)
- {
- tree selector = objc_message_selector ();
- char * new_opname;
-
- if (selector && argnum > 2)
- {
- function = selector;
- argnum -= 2;
- }
- if (argnum == 0)
- {
- if (function)
- {
- /* Function name is known; supply it. */
- const char *const argstring = _("passing arg of `%s'");
- new_opname = 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 = 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'");
- new_opname = alloca (IDENTIFIER_LENGTH (function)
- + strlen (argstring) + 1 + 25 /*%d*/ + 1);
- sprintf (new_opname, argstring, argnum,
- IDENTIFIER_POINTER (function));
- }
- else
- {
- /* Function name unknown (call through ptr); just give arg number. */
- const char *const argnofun = _("passing arg %d of pointer to function");
- new_opname = alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1);
- sprintf (new_opname, argnofun, argnum);
- }
- opname = new_opname;
- }
- pedwarn (msgid, opname);
-}
\f
/* If VALUE is a compound expr all of whose expressions are constant, then
return its value. Otherwise, return error_mark_node.
return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
endtype);
}
- else if (! TREE_CONSTANT (value)
- && ! initializer_constant_valid_p (value, endtype))
+ else if (!initializer_constant_valid_p (value, endtype))
return error_mark_node;
else
return value;
/* Digest the specified initializer into an expression. */
- value = digest_init (type, init, TREE_STATIC (decl));
+ value = digest_init (type, init, true, TREE_STATIC (decl));
/* Store the expression if valid; else report error. */
if (warn_traditional && !in_system_header
- && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && ! TREE_STATIC (decl))
+ && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
warning ("traditional C rejects automatic aggregate initialization");
DECL_INITIAL (decl) = value;
if (depth >= spelling_size) \
{ \
spelling_size += 10; \
- if (spelling_base == 0) \
- spelling_base = xmalloc (spelling_size * sizeof (struct spelling)); \
- else \
- spelling_base = xrealloc (spelling_base, \
- spelling_size * sizeof (struct spelling)); \
+ spelling_base = XRESIZEVEC (struct spelling, spelling_base, \
+ spelling_size); \
RESTORE_SPELLING_DEPTH (depth); \
} \
\
char *ofwhat;
error ("%s", _(msgid));
- ofwhat = print_spelling (alloca (spelling_length () + 1));
+ ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- error ("(near initialization for `%s')", ofwhat);
+ error ("(near initialization for %qs)", ofwhat);
}
/* Issue a pedantic warning for a bad initializer component.
char *ofwhat;
pedwarn ("%s", _(msgid));
- ofwhat = print_spelling (alloca (spelling_length () + 1));
+ ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- pedwarn ("(near initialization for `%s')", ofwhat);
+ pedwarn ("(near initialization for %qs)", ofwhat);
}
/* Issue a warning for a bad initializer component.
char *ofwhat;
warning ("%s", _(msgid));
- ofwhat = print_spelling (alloca (spelling_length () + 1));
+ ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning ("(near initialization for `%s')", ofwhat);
+ warning ("(near initialization for %qs)", ofwhat);
}
\f
+/* If TYPE is an array type and EXPR is a parenthesized string
+ constant, warn if pedantic that EXPR is being used to initialize an
+ object of type TYPE. */
+
+void
+maybe_warn_string_init (tree type, struct c_expr expr)
+{
+ if (pedantic
+ && TREE_CODE (type) == ARRAY_TYPE
+ && TREE_CODE (expr.value) == STRING_CST
+ && expr.original_code != STRING_CST)
+ pedwarn_init ("array initialized from parenthesized string constant");
+}
+
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
+ If INIT is a string constant, STRICT_STRING is true if it is
+ unparenthesized or we should not warn here for it being parenthesized.
+ For other types of INIT, STRICT_STRING is not used.
+
REQUIRE_CONSTANT requests an error if non-constant initializers or
elements are seen. */
static tree
-digest_init (tree type, tree init, int require_constant)
+digest_init (tree type, tree init, bool strict_string, int require_constant)
{
enum tree_code code = TREE_CODE (type);
tree inside_init = init;
/* Initialization of an array of chars from a string constant
optionally enclosed in braces. */
- if (code == ARRAY_TYPE)
+ if (code == ARRAY_TYPE && inside_init
+ && TREE_CODE (inside_init) == STRING_CST)
{
tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
- if ((typ1 == char_type_node
- || typ1 == signed_char_type_node
- || typ1 == unsigned_char_type_node
- || typ1 == unsigned_wchar_type_node
- || typ1 == signed_wchar_type_node)
- && ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
+ /* Note that an array could be both an array of character type
+ and an array of wchar_t if wchar_t is signed char or unsigned
+ char. */
+ bool char_array = (typ1 == char_type_node
+ || typ1 == signed_char_type_node
+ || typ1 == unsigned_char_type_node);
+ bool wchar_array = !!comptypes (typ1, wchar_type_node);
+ if (char_array || wchar_array)
{
+ struct c_expr expr;
+ bool char_string;
+ expr.value = inside_init;
+ expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
+ maybe_warn_string_init (type, expr);
+
+ char_string
+ = (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
+ == char_type_node);
+
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
TYPE_MAIN_VARIANT (type)))
return inside_init;
- if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
- != char_type_node)
- && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node))
+ if (!wchar_array && !char_string)
{
error_init ("char-array initialized from wide string");
return error_mark_node;
}
- if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
- == char_type_node)
- && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node))
+ if (char_string && !char_array)
{
- error_init ("int-array initialized from non-wide string");
+ error_init ("wchar_t-array initialized from non-wide string");
return error_mark_node;
}
return inside_init;
}
+ else if (INTEGRAL_TYPE_P (typ1))
+ {
+ error_init ("array of inappropriate type initialized "
+ "from string constant");
+ return error_mark_node;
+ }
}
/* 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))
{
inside_init = error_mark_node;
}
else if (require_constant
- && (!TREE_CONSTANT (inside_init)
- /* This test catches things like `7 / 0' which
- result in an expression for which TREE_CONSTANT
- is true, but which is not actually something
- that is a legal constant. We really should not
- be using this function, because it is a part of
- the back-end. Instead, the expression should
- already have been turned into ERROR_MARK_NODE. */
- || !initializer_constant_valid_p (inside_init,
- TREE_TYPE (inside_init))))
+ && !initializer_constant_valid_p (inside_init,
+ TREE_TYPE (inside_init)))
{
error_init ("initializer element is not constant");
inside_init = error_mark_node;
for arrays and functions. We must not call it in the
case where inside_init is a null pointer constant. */
inside_init
- = convert_for_assignment (type, init, _("initialization"),
+ = convert_for_assignment (type, init, ic_init,
NULL_TREE, NULL_TREE, 0);
- if (require_constant && ! TREE_CONSTANT (inside_init))
+ /* Check to see if we have already given an error message. */
+ if (inside_init == error_mark_node)
+ ;
+ else if (require_constant && !TREE_CONSTANT (inside_init))
{
error_init ("initializer element is not constant");
inside_init = error_mark_node;
}
else if (require_constant
- && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
+ && !initializer_constant_valid_p (inside_init,
+ TREE_TYPE (inside_init)))
{
error_init ("initializer element is not computable at load time");
inside_init = error_mark_node;
such as (struct foo) {...}. */
static tree constructor_decl;
-/* start_init saves the ASMSPEC arg here for really_start_incremental_init. */
-static const char *constructor_asmspec;
-
/* Nonzero if this is an initializer for a top-level decl. */
static int constructor_top_level;
struct init_node *pending_elts;
int offset;
int depth;
- /* If nonzero, this value should replace the entire
+ /* If value nonzero, this value should replace the entire
constructor at this level. */
- tree replacement_value;
+ struct c_expr replacement_value;
struct constructor_range_stack *range_stack;
char constant;
char simple;
{
struct initializer_stack *next;
tree decl;
- const char *asmspec;
struct constructor_stack *constructor_stack;
struct constructor_range_stack *constructor_range_stack;
tree elements;
/* Prepare to parse and output the initializer for variable DECL. */
void
-start_init (tree decl, tree asmspec_tree, int top_level)
+start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level)
{
const char *locus;
struct initializer_stack *p = xmalloc (sizeof (struct initializer_stack));
- const char *asmspec = 0;
-
- if (asmspec_tree)
- asmspec = TREE_STRING_POINTER (asmspec_tree);
p->decl = constructor_decl;
- p->asmspec = constructor_asmspec;
p->require_constant_value = require_constant_value;
p->require_constant_elements = require_constant_elements;
p->constructor_stack = constructor_stack;
initializer_stack = p;
constructor_decl = decl;
- constructor_asmspec = asmspec;
constructor_designated = 0;
constructor_top_level = top_level;
free (q);
}
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
/* Pop back to the data of the outer initializer (if any). */
free (spelling_base);
constructor_decl = p->decl;
- constructor_asmspec = p->asmspec;
require_constant_value = p->require_constant_value;
require_constant_elements = p->require_constant_elements;
constructor_stack = p->constructor_stack;
void
really_start_incremental_init (tree type)
{
- struct constructor_stack *p = xmalloc (sizeof (struct constructor_stack));
+ struct constructor_stack *p = XNEW (struct constructor_stack);
if (type == 0)
type = TREE_TYPE (constructor_decl);
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
p->depth = constructor_depth;
- p->replacement_value = 0;
+ p->replacement_value.value = 0;
+ p->replacement_value.original_code = ERROR_MARK;
p->implicit = 0;
p->range_stack = 0;
p->outer = 0;
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_2 (-1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -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_max_index = build_int_cst (NULL_TREE, -1);
constructor_index
= convert (bitsizetype,
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = convert (bitsizetype, bitsize_zero_node);
constructor_unfilled_index = constructor_index;
}
value = find_init_member (constructor_index);
}
- p = xmalloc (sizeof (struct constructor_stack));
+ p = XNEW (struct constructor_stack);
p->type = constructor_type;
p->fields = constructor_fields;
p->index = constructor_index;
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
p->depth = constructor_depth;
- p->replacement_value = 0;
+ p->replacement_value.value = 0;
+ p->replacement_value.original_code = ERROR_MARK;
p->implicit = implicit;
p->outer = 0;
p->incremental = constructor_incremental;
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+ build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = convert (bitsizetype, integer_zero_node);
constructor_unfilled_index = constructor_index;
}
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_2 (-1, -1);
+ constructor_max_index = build_int_cst (NULL_TREE, -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_max_index = build_int_cst (NULL_TREE, -1);
constructor_index
= convert (bitsizetype,
}
/* 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
+ finish up that level of constructor. If a single expression
+ with redundant braces initialized that level, return the
+ c_expr structure for that expression. Otherwise, the original_code
+ element is set to ERROR_MARK.
+ If we were outputting the elements as they are read, return 0 as the value
from inner levels (process_init_element ignores that),
- but return error_mark_node from the outermost level
+ but return error_mark_node as the value from the outermost level
(that's what we want to put in DECL_INITIAL).
- Otherwise, return a CONSTRUCTOR expression. */
+ Otherwise, return a CONSTRUCTOR expression as the value. */
-tree
+struct c_expr
pop_init_level (int implicit)
{
struct constructor_stack *p;
- tree constructor = 0;
+ struct c_expr ret;
+ ret.value = 0;
+ ret.original_code = ERROR_MARK;
if (implicit == 0)
{
while (constructor_stack->implicit)
process_init_element (pop_init_level (1));
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
}
/* Now output all pending elements. */
if (constructor_type && constructor_fields
&& TREE_CODE (constructor_type) == ARRAY_TYPE
&& TYPE_DOMAIN (constructor_type)
- && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+ && !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
{
/* Silently discard empty initializations. The parser will
already have pedwarned for empty brackets. */
if (integer_zerop (constructor_unfilled_index))
constructor_type = NULL_TREE;
- else if (! TYPE_SIZE (constructor_type))
+ else
{
+ gcc_assert (!TYPE_SIZE (constructor_type));
+
if (constructor_depth > 2)
error_init ("initialization of flexible array member in a nested context");
else if (pedantic)
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
- else
- /* Zero-length arrays are no longer special, so we should no longer
- get here. */
- abort ();
}
/* Warn when some struct elements are implicitly initialized to zero. */
- if (extra_warnings
+ if (warn_missing_field_initializers
&& constructor_type
&& TREE_CODE (constructor_type) == RECORD_TYPE
&& constructor_unfilled_fields)
{
/* Do not warn for flexible array members or zero-length arrays. */
while (constructor_unfilled_fields
- && (! DECL_SIZE (constructor_unfilled_fields)
+ && (!DECL_SIZE (constructor_unfilled_fields)
|| integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
}
/* Pad out the end of the structure. */
- if (p->replacement_value)
+ if (p->replacement_value.value)
/* If this closes a superfluous brace pair,
just pass out the element between them. */
- constructor = p->replacement_value;
+ ret = p->replacement_value;
else if (constructor_type == 0)
;
else if (TREE_CODE (constructor_type) != RECORD_TYPE
{
if (!constructor_erroneous)
error_init ("empty scalar initializer");
- constructor = error_mark_node;
+ ret.value = error_mark_node;
}
else if (TREE_CHAIN (constructor_elements) != 0)
{
error_init ("extra elements in scalar initializer");
- constructor = TREE_VALUE (constructor_elements);
+ ret.value = TREE_VALUE (constructor_elements);
}
else
- constructor = TREE_VALUE (constructor_elements);
+ ret.value = TREE_VALUE (constructor_elements);
}
else
{
if (constructor_erroneous)
- constructor = error_mark_node;
+ ret.value = error_mark_node;
else
{
- constructor = build_constructor (constructor_type,
- nreverse (constructor_elements));
+ ret.value = build_constructor (constructor_type,
+ nreverse (constructor_elements));
if (constructor_constant)
- TREE_CONSTANT (constructor) = TREE_INVARIANT (constructor) = 1;
+ TREE_CONSTANT (ret.value) = TREE_INVARIANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
- TREE_STATIC (constructor) = 1;
+ TREE_STATIC (ret.value) = 1;
}
}
constructor_stack = p->next;
free (p);
- if (constructor == 0)
+ if (ret.value == 0)
{
if (constructor_stack == 0)
- return error_mark_node;
- return NULL_TREE;
+ {
+ ret.value = error_mark_node;
+ return ret;
+ }
+ return ret;
}
- return constructor;
+ return ret;
}
/* Common handling for both array range and field name designators.
if (constructor_type == 0)
return 1;
- /* If there were errors in this designator list already, bail out silently. */
+ /* If there were errors in this designator list already, bail out
+ silently. */
if (designator_errorneous)
return 1;
if (!designator_depth)
{
- if (constructor_range_stack)
- abort ();
+ gcc_assert (!constructor_range_stack);
/* Designator list starts at the level of closest explicit
braces. */
return 1;
}
- if (TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
+ switch (TREE_CODE (constructor_type))
{
+ case RECORD_TYPE:
+ case UNION_TYPE:
subtype = TREE_TYPE (constructor_fields);
if (subtype != error_mark_node)
subtype = TYPE_MAIN_VARIANT (subtype);
- }
- else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- {
+ break;
+ case ARRAY_TYPE:
subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+ break;
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
subcode = TREE_CODE (subtype);
if (array && subcode != ARRAY_TYPE)
{
struct constructor_range_stack *p;
- p = ggc_alloc (sizeof (struct constructor_range_stack));
+ p = GGC_NEW (struct constructor_range_stack);
p->prev = constructor_range_stack;
p->next = 0;
p->fields = constructor_fields;
designator_errorneous = 1;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (first))
+ || (last && !INTEGRAL_TYPE_P (TREE_TYPE (last))))
+ {
+ error_init ("array index in initializer not of integer type");
+ return;
+ }
+
while ((TREE_CODE (first) == NOP_EXPR
|| TREE_CODE (first) == CONVERT_EXPR
|| TREE_CODE (first) == NON_LVALUE_EXPR)
}
if (tail == 0)
- error ("unknown field `%s' specified in initializer",
+ error ("unknown field %qs specified in initializer",
IDENTIFIER_POINTER (fieldname));
else
{
}
}
- r = ggc_alloc (sizeof (struct init_node));
+ r = GGC_NEW (struct init_node);
r->purpose = purpose;
r->value = value;
const char *p, *end;
int byte, wchar_bytes, charwidth, bitpos;
- if (TREE_CODE (constructor_type) != ARRAY_TYPE)
- abort ();
+ gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE);
if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
== TYPE_PRECISION (char_type_node))
wchar_bytes = 1;
- else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
- == TYPE_PRECISION (wchar_type_node))
- wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
else
- abort ();
-
+ {
+ gcc_assert (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+ == TYPE_PRECISION (wchar_type_node));
+ wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+ }
charwidth = TYPE_PRECISION (char_type_node);
type = TREE_TYPE (constructor_type);
p = TREE_STRING_POINTER (str);
<< (bitpos - HOST_BITS_PER_WIDE_INT);
}
- value = build_int_2 (val[1], val[0]);
- TREE_TYPE (value) = type;
+ value = build_int_cst_wide (type, val[1], val[0]);
add_pending_init (purpose, value);
}
Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
TYPE is the data type that the containing data type wants here.
FIELD is the field (a FIELD_DECL) or the index that this element fills.
+ If VALUE is a string constant, STRICT_STRING is true if it is
+ unparenthesized or we should not warn here for it being parenthesized.
+ For other types of VALUE, STRICT_STRING is not used.
PENDING if non-nil means output pending elements that belong
right after this element. (PENDING is normally 1;
it is 0 while outputting pending elements, to avoid recursion.) */
static void
-output_init_element (tree value, tree type, tree field, int pending)
+output_init_element (tree value, bool strict_string, tree type, tree field,
+ int pending)
{
- if (type == error_mark_node)
+ if (type == error_mark_node || value == error_mark_node)
{
constructor_erroneous = 1;
return;
|| (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
&& !(TREE_CODE (value) == STRING_CST
&& TREE_CODE (type) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
+ && INTEGRAL_TYPE_P (TREE_TYPE (type)))
&& !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
TYPE_MAIN_VARIANT (type))))
value = default_conversion (value);
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
constructor_constant = 0;
- else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
+ else if (!initializer_constant_valid_p (value, TREE_TYPE (value))
|| ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& DECL_C_BIT_FIELD (field)
&& TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
- if (require_constant_value && ! TREE_CONSTANT (value))
+ if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
{
- error_init ("initializer element is not constant");
- value = error_mark_node;
+ if (require_constant_value)
+ {
+ error_init ("initializer element is not constant");
+ value = error_mark_node;
+ }
+ else if (require_constant_elements)
+ pedwarn ("initializer element is not computable at load time");
}
- else if (require_constant_elements
- && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
- pedwarn ("initializer element is not computable at load time");
/* If this field is empty (and not at the end of structure),
don't do anything other than checking the initializer. */
|| TREE_CHAIN (field)))))
return;
- value = digest_init (type, value, require_constant_value);
+ value = digest_init (type, value, strict_string, require_constant_value);
if (value == error_mark_node)
{
constructor_erroneous = 1;
{
if (tree_int_cst_equal (elt->purpose,
constructor_unfilled_index))
- output_init_element (elt->value,
+ output_init_element (elt->value, true,
TREE_TYPE (constructor_type),
constructor_unfilled_index, 0);
else if (tree_int_cst_lt (constructor_unfilled_index,
if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
{
constructor_unfilled_fields = elt->purpose;
- output_init_element (elt->value, TREE_TYPE (elt->purpose),
+ output_init_element (elt->value, true, TREE_TYPE (elt->purpose),
elt->purpose, 0);
}
else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
/* Ordinarily return, but not if we want to output all
and there are elements left. */
- if (! (all && next != 0))
+ if (!(all && next != 0))
return;
/* If it's not incremental, just skip over the gap, so that after
it calls output_init_element. */
void
-process_init_element (tree value)
+process_init_element (struct c_expr value)
{
- tree orig_value = value;
- int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
+ tree orig_value = value.value;
+ int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
+ bool strict_string = value.original_code == STRING_CST;
designator_depth = 0;
designator_errorneous = 0;
if (string_flag
&& constructor_type
&& TREE_CODE (constructor_type) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (constructor_type))
&& integer_zerop (constructor_unfilled_index))
{
- if (constructor_stack->replacement_value)
+ if (constructor_stack->replacement_value.value)
error_init ("excess elements in char array initializer");
constructor_stack->replacement_value = value;
return;
}
- if (constructor_stack->replacement_value != 0)
+ if (constructor_stack->replacement_value.value != 0)
{
error_init ("excess elements in struct initializer");
return;
{
/* 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
+ if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
|| !require_constant_value
|| flag_isoc99)
- value = save_expr (value);
+ value.value = save_expr (value.value);
}
while (1)
}
/* Accept a string constant to initialize a subarray. */
- if (value != 0
+ if (value.value != 0
&& fieldcode == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
&& string_flag)
- value = orig_value;
+ value.value = orig_value;
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
- else if (value != 0 && !constructor_no_implicit
- && value != error_mark_node
- && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+ else if (value.value != 0 && !constructor_no_implicit
+ && value.value != error_mark_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
{
continue;
}
- if (value)
+ if (value.value)
{
push_member_name (constructor_fields);
- output_init_element (value, fieldtype, constructor_fields, 1);
+ output_init_element (value.value, strict_string,
+ fieldtype, constructor_fields, 1);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
__STDC__ anyway (and we've already complained about the
member-designator already). */
if (warn_traditional && !in_system_header && !constructor_designated
- && !(value && (integer_zerop (value) || real_zerop (value))))
+ && !(value.value && (integer_zerop (value.value)
+ || real_zerop (value.value))))
warning ("traditional C rejects initialization of unions");
/* Accept a string constant to initialize a subarray. */
- if (value != 0
+ if (value.value != 0
&& fieldcode == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
&& string_flag)
- value = orig_value;
+ value.value = orig_value;
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
- else if (value != 0 && !constructor_no_implicit
- && value != error_mark_node
- && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+ else if (value.value != 0 && !constructor_no_implicit
+ && value.value != error_mark_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
{
continue;
}
- if (value)
+ if (value.value)
{
push_member_name (constructor_fields);
- output_init_element (value, fieldtype, constructor_fields, 1);
+ output_init_element (value.value, strict_string,
+ fieldtype, constructor_fields, 1);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
enum tree_code eltcode = TREE_CODE (elttype);
/* Accept a string constant to initialize a subarray. */
- if (value != 0
+ if (value.value != 0
&& eltcode == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (elttype))
&& string_flag)
- value = orig_value;
+ value.value = orig_value;
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
- else if (value != 0 && !constructor_no_implicit
- && value != error_mark_node
- && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
+ else if (value.value != 0 && !constructor_no_implicit
+ && value.value != error_mark_node
+ && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
|| eltcode == UNION_TYPE))
{
}
/* Now output the actual element. */
- if (value)
+ if (value.value)
{
push_array_bounds (tree_low_cst (constructor_index, 0));
- output_init_element (value, elttype, constructor_index, 1);
+ output_init_element (value.value, strict_string,
+ elttype, constructor_index, 1);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
constructor_index
= size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
- if (! value)
+ if (!value.value)
/* If we are doing the bookkeeping for an element that was
directly output as a constructor, we must update
constructor_unfilled_index. */
}
/* Now output the actual element. */
- if (value)
- output_init_element (value, elttype, constructor_index, 1);
+ if (value.value)
+ output_init_element (value.value, strict_string,
+ elttype, constructor_index, 1);
constructor_index
= size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
- if (! value)
+ if (!value.value)
/* If we are doing the bookkeeping for an element that was
directly output as a constructor, we must update
constructor_unfilled_index. */
}
else
{
- if (value)
- output_init_element (value, constructor_type, NULL_TREE, 1);
+ if (value.value)
+ output_init_element (value.value, strict_string,
+ constructor_type, NULL_TREE, 1);
constructor_fields = 0;
}
constructor_range_stack = 0;
while (constructor_stack != range_stack->stack)
{
- if (!constructor_stack->implicit)
- abort ();
+ gcc_assert (constructor_stack->implicit);
process_init_element (pop_init_level (1));
}
for (p = range_stack;
!p->range_end || tree_int_cst_equal (p->index, p->range_end);
p = p->prev)
{
- if (!constructor_stack->implicit)
- abort ();
+ gcc_assert (constructor_stack->implicit);
process_init_element (pop_init_level (1));
}
tree output = TREE_VALUE (tail);
STRIP_NOPS (output);
TREE_VALUE (tail) = output;
- lvalue_or_else (output, "invalid lvalue in asm statement");
+ lvalue_or_else (output, lv_asm);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
}
return args;
}
+\f
+/* Generate a goto statement to LABEL. */
-/* Expand an ASM statement with operands, handling output operands
- that are not variables or INDIRECT_REFS by transforming such
- cases into cases that expand_asm_operands can handle.
-
- Arguments are same as for expand_asm_operands. */
-
-void
-c_expand_asm_operands (tree string, tree outputs, tree inputs,
- tree clobbers, int vol, location_t locus)
+tree
+c_finish_goto_label (tree label)
{
- int noutputs = list_length (outputs);
- int i;
- /* o[I] is the place that output number I should be written. */
- tree *o = alloca (noutputs * sizeof (tree));
- tree tail;
-
- /* 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);
- if (o[i] == error_mark_node)
- return;
- }
+ tree decl = lookup_label (label);
+ if (!decl)
+ return NULL_TREE;
- /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
- OUTPUTS some trees for where the values were actually stored. */
- expand_asm_operands (string, outputs, inputs, clobbers, vol, locus);
+ TREE_USED (decl) = 1;
+ return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
+}
- /* Copy all the intermediate outputs into the specified outputs. */
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- {
- if (o[i] != TREE_VALUE (tail))
- {
- expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
- NULL_RTX, VOIDmode, EXPAND_NORMAL);
- free_temp_slots ();
+/* Generate a computed goto statement to EXPR. */
- /* Restore the original value so that it's correct the next
- time we expand this function. */
- TREE_VALUE (tail) = o[i];
- }
- /* Detect modification of read-only values.
- (Otherwise done by build_modify_expr.) */
- else
- {
- tree type = TREE_TYPE (o[i]);
- if (TREE_READONLY (o[i])
- || TYPE_READONLY (type)
- || ((TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE)
- && C_TYPE_FIELDS_READONLY (type)))
- readonly_error (o[i], "modification by `asm'");
- }
- }
-
- /* Those MODIFY_EXPRs could do autoincrements. */
- emit_queue ();
+tree
+c_finish_goto_ptr (tree expr)
+{
+ if (pedantic)
+ pedwarn ("ISO C forbids %<goto *expr;%>");
+ expr = convert (ptr_type_node, expr);
+ return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
-\f
+
/* Generate a C `return' statement. RETVAL is the expression for what
to return, or a null pointer for `return;' with no value. */
-void
+tree
c_finish_return (tree retval)
{
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 ("function declared %<noreturn%> has a %<return%> statement");
if (!retval)
{
current_function_returns_null = 1;
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
- pedwarn_c99 ("`return' with no value, in function returning non-void");
+ pedwarn_c99 ("%<return%> with no value, in "
+ "function returning non-void");
}
else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("`return' with a value, in function returning void");
+ pedwarn ("%<return%> with a value, in function returning void");
}
else
{
- tree t = convert_for_assignment (valtype, retval, _("return"),
+ tree t = convert_for_assignment (valtype, retval, ic_return,
NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
tree inner;
current_function_returns_value = 1;
if (t == error_mark_node)
- return;
+ return NULL_TREE;
inner = t = convert (TREE_TYPE (res), t);
{
tree op1 = TREE_OPERAND (inner, 1);
- while (! POINTER_TYPE_P (TREE_TYPE (op1))
+ while (!POINTER_TYPE_P (TREE_TYPE (op1))
&& (TREE_CODE (op1) == NOP_EXPR
|| TREE_CODE (op1) == NON_LVALUE_EXPR
|| TREE_CODE (op1) == CONVERT_EXPR))
case ADDR_EXPR:
inner = TREE_OPERAND (inner, 0);
- while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
+ while (REFERENCE_CLASS_P (inner)
+ && TREE_CODE (inner) != INDIRECT_REF)
inner = TREE_OPERAND (inner, 0);
if (DECL_P (inner)
- && ! DECL_EXTERNAL (inner)
- && ! TREE_STATIC (inner)
+ && !DECL_EXTERNAL (inner)
+ && !TREE_STATIC (inner)
&& DECL_CONTEXT (inner) == current_function_decl)
warning ("function returns address of local variable");
break;
break;
}
- retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
+ retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t);
}
- add_stmt (build_stmt (RETURN_EXPR, retval));
+ return add_stmt (build_stmt (RETURN_EXPR, retval));
}
\f
struct c_switch {
/* The SWITCH_STMT being built. */
tree switch_stmt;
+
+ /* The original type of the testing expression, i.e. before the
+ default conversion is applied. */
+ tree orig_type;
+
/* A splay-tree mapping the low element of a case range to the high
element, or NULL_TREE if there is no high element. Used to
determine whether or not a new case label duplicates an old case
label. We need a tree, rather than simply a hash table, because
of the GNU case range extension. */
splay_tree cases;
+
/* The next node on the stack. */
struct c_switch *next;
};
during the processing of the body of a function, and we never
collect at that point. */
-static struct c_switch *switch_stack;
+struct c_switch *c_switch_stack;
/* Start a C switch statement, testing expression EXP. Return the new
SWITCH_STMT. */
code = TREE_CODE (TREE_TYPE (exp));
orig_type = TREE_TYPE (exp);
- if (! INTEGRAL_TYPE_P (orig_type)
+ if (!INTEGRAL_TYPE_P (orig_type)
&& code != ERROR_MARK)
{
error ("switch quantity not an integer");
if (warn_traditional && !in_system_header
&& (type == long_integer_type_node
|| type == long_unsigned_type_node))
- warning ("`long' switch expression not converted to `int' in ISO C");
+ warning ("%<long%> switch expression not converted to "
+ "%<int%> in ISO C");
exp = default_conversion (exp);
type = TREE_TYPE (exp);
}
/* Add this new SWITCH_STMT to the stack. */
- cs = xmalloc (sizeof (*cs));
- cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
+ cs = XNEW (struct c_switch);
+ cs->switch_stmt = build_stmt ((enum tree_code) SWITCH_STMT, exp, NULL_TREE,
+ orig_type);
+ cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
- cs->next = switch_stack;
- switch_stack = cs;
+ cs->next = c_switch_stack;
+ c_switch_stack = cs;
- return add_stmt (switch_stack->switch_stmt);
+ return add_stmt (cs->switch_stmt);
}
/* Process a case label. */
{
tree label = NULL_TREE;
- if (switch_stack)
+ if (c_switch_stack)
{
- label = c_add_case_label (switch_stack->cases,
- SWITCH_COND (switch_stack->switch_stmt),
+ label = c_add_case_label (c_switch_stack->cases,
+ SWITCH_COND (c_switch_stack->switch_stmt),
+ c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
else if (low_value)
error ("case label not within a switch statement");
else
- error ("`default' label not within a switch statement");
+ error ("%<default%> label not within a switch statement");
return label;
}
void
c_finish_case (tree body)
{
- struct c_switch *cs = switch_stack;
+ struct c_switch *cs = c_switch_stack;
SWITCH_BODY (cs->switch_stmt) = body;
c_do_switch_warnings (cs->cases, cs->switch_stmt);
/* Pop the stack. */
- switch_stack = switch_stack->next;
+ c_switch_stack = cs->next;
splay_tree_delete (cs->cases);
- free (cs);
+ XDELETE (cs);
}
\f
-/* Keep a stack of if statements. We record the number of compound
- statements seen up to the if keyword, as well as the line number
- and file of the if. If a potentially ambiguous else is seen, that
- fact is recorded; the warning is issued when we can be sure that
- the enclosing if statement does not have an else branch. */
-typedef struct
-{
- tree if_stmt;
- location_t empty_locus;
- int compstmt_count;
- int stmt_count;
- unsigned int needs_warning : 1;
- unsigned int saw_else : 1;
-} if_elt;
-
-static if_elt *if_stack;
-
-/* Amount of space in the if statement stack. */
-static int if_stack_space = 0;
-
-/* Stack pointer. */
-static int if_stack_pointer = 0;
-
-/* Begin an if-statement. */
+/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND,
+ THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK
+ may be null. NESTED_IF is true if THEN_BLOCK contains another IF
+ statement, and was not surrounded with parenthesis. */
void
-c_begin_if_stmt (void)
+c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
+ tree else_block, bool nested_if)
{
- tree r;
- if_elt *elt;
+ tree stmt;
- /* Make sure there is enough space on the stack. */
- if (if_stack_space == 0)
+ /* Diagnose an ambiguous else if if-then-else is nested inside if-then. */
+ if (warn_parentheses && nested_if && else_block == NULL)
{
- if_stack_space = 10;
- if_stack = xmalloc (10 * sizeof (if_elt));
- }
- else if (if_stack_space == if_stack_pointer)
- {
- if_stack_space += 10;
- if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
- }
+ tree inner_if = then_block;
- r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE));
-
- /* Record this if statement. */
- elt = &if_stack[if_stack_pointer++];
- memset (elt, 0, sizeof (*elt));
- elt->if_stmt = r;
-}
-
-/* Record the start of an if-then, and record the start of it
- for ambiguous else detection.
-
- COND is the condition for the if-then statement.
-
- IF_STMT is the statement node that has already been created for
- this if-then statement. It is created before parsing the
- condition to keep line number information accurate. */
-
-void
-c_finish_if_cond (tree cond, int compstmt_count, int stmt_count)
-{
- if_elt *elt = &if_stack[if_stack_pointer - 1];
- elt->compstmt_count = compstmt_count;
- elt->stmt_count = stmt_count;
- COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond);
-}
-
-/* Called after the then-clause for an if-statement is processed. */
-
-void
-c_finish_then (tree then_stmt)
-{
- if_elt *elt = &if_stack[if_stack_pointer - 1];
- COND_EXPR_THEN (elt->if_stmt) = then_stmt;
- elt->empty_locus = input_location;
-}
-
-/* Called between the then-clause and the else-clause
- of an if-then-else. */
-
-void
-c_begin_else (int stmt_count)
-{
- if_elt *elt = &if_stack[if_stack_pointer - 1];
-
- /* An ambiguous else warning must be generated for the enclosing if
- statement, unless we see an else branch for that one, too. */
- if (warn_parentheses
- && if_stack_pointer > 1
- && (elt[0].compstmt_count == elt[-1].compstmt_count))
- elt[-1].needs_warning = 1;
-
- /* Even if a nested if statement had an else branch, it can't be
- ambiguous if this one also has an else. So don't warn in that
- case. Also don't warn for any if statements nested in this else. */
- elt->needs_warning = 0;
- elt->compstmt_count--;
- elt->saw_else = 1;
- elt->stmt_count = stmt_count;
-}
-
-/* Called after the else-clause for an if-statement is processed. */
-
-void
-c_finish_else (tree else_stmt)
-{
- if_elt *elt = &if_stack[if_stack_pointer - 1];
- COND_EXPR_ELSE (elt->if_stmt) = else_stmt;
- elt->empty_locus = input_location;
-}
-
-/* Record the end of an if-then. Optionally warn if a nested
- if statement had an ambiguous else clause. */
-
-void
-c_finish_if_stmt (int stmt_count)
-{
- if_elt *elt = &if_stack[--if_stack_pointer];
-
- if (COND_EXPR_ELSE (elt->if_stmt) == NULL)
- COND_EXPR_ELSE (elt->if_stmt) = build_empty_stmt ();
+ /* We know from the grammar productions that there is an IF nested
+ within THEN_BLOCK. Due to labels and c99 conditional declarations,
+ it might not be exactly THEN_BLOCK, but should be the last
+ non-container statement within. */
+ while (1)
+ switch (TREE_CODE (inner_if))
+ {
+ case COND_EXPR:
+ goto found;
+ case BIND_EXPR:
+ inner_if = BIND_EXPR_BODY (inner_if);
+ break;
+ case STATEMENT_LIST:
+ inner_if = expr_last (then_block);
+ break;
+ case TRY_FINALLY_EXPR:
+ case TRY_CATCH_EXPR:
+ inner_if = TREE_OPERAND (inner_if, 0);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ found:
- if (elt->needs_warning)
- warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
- EXPR_LOCUS (elt->if_stmt));
+ if (COND_EXPR_ELSE (inner_if))
+ warning ("%Hsuggest explicit braces to avoid ambiguous %<else%>",
+ &if_locus);
+ }
- if (extra_warnings && stmt_count == elt->stmt_count)
+ /* Diagnose ";" via the special empty statement node that we create. */
+ if (extra_warnings)
{
- if (elt->saw_else)
- warning ("%Hempty body in an else-statement", &elt->empty_locus);
- else
- warning ("%Hempty body in an if-statement", &elt->empty_locus);
+ if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
+ {
+ if (!else_block)
+ warning ("%Hempty body in an if-statement",
+ EXPR_LOCUS (then_block));
+ then_block = alloc_stmt_list ();
+ }
+ if (else_block
+ && TREE_CODE (else_block) == NOP_EXPR
+ && !TREE_TYPE (else_block))
+ {
+ warning ("%Hempty body in an else-statement",
+ EXPR_LOCUS (else_block));
+ else_block = alloc_stmt_list ();
+ }
}
-}
-\f
-/* Begin a while statement. Returns a newly created WHILE_STMT if
- appropriate. */
-tree
-c_begin_while_stmt (void)
-{
- tree r;
- r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
- return r;
+ stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+ SET_EXPR_LOCATION (stmt, if_locus);
+ add_stmt (stmt);
}
-void
-c_finish_while_stmt_cond (tree cond, tree while_stmt)
-{
- WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
-}
+/* Emit a general-purpose loop construct. START_LOCUS is the location of
+ the beginning of the loop. COND is the loop condition. COND_IS_FIRST
+ is false for DO loops. INCR is the FOR increment expression. BODY is
+ the statement controlled by the loop. BLAB is the break label. CLAB is
+ the continue label. Everything is allowed to be NULL. */
void
-c_finish_while_stmt (tree body, tree while_stmt)
+c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
+ tree blab, tree clab, bool cond_is_first)
{
- WHILE_BODY (while_stmt) = body;
+ tree entry = NULL, exit = NULL, t;
+
+ /* Detect do { ... } while (0) and don't generate loop construct. */
+ if (cond && !cond_is_first && integer_zerop (cond))
+ cond = NULL;
+ if (cond_is_first || cond)
+ {
+ tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+
+ /* If we have an exit condition, then we build an IF with gotos either
+ out of the loop, or to the top of it. If there's no exit condition,
+ then we just build a jump back to the top. */
+ exit = build_and_jump (&LABEL_EXPR_LABEL (top));
+
+ if (cond)
+ {
+ /* Canonicalize the loop condition to the end. This means
+ generating a branch to the loop condition. Reuse the
+ continue label, if possible. */
+ if (cond_is_first)
+ {
+ if (incr || !clab)
+ {
+ entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+ t = build_and_jump (&LABEL_EXPR_LABEL (entry));
+ }
+ else
+ t = build1 (GOTO_EXPR, void_type_node, clab);
+ SET_EXPR_LOCATION (t, start_locus);
+ add_stmt (t);
+ }
+
+ t = build_and_jump (&blab);
+ exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
+ exit = fold (exit);
+ if (cond_is_first)
+ SET_EXPR_LOCATION (exit, start_locus);
+ else
+ SET_EXPR_LOCATION (exit, input_location);
+ }
+
+ add_stmt (top);
+ }
+
+ if (body)
+ add_stmt (body);
+ if (clab)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, clab));
+ if (incr)
+ add_stmt (incr);
+ if (entry)
+ add_stmt (entry);
+ if (exit)
+ add_stmt (exit);
+ if (blab)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, blab));
}
-\f
-/* Create a for statement. */
tree
-c_begin_for_stmt (void)
-{
- tree r;
- r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
- NULL_TREE, NULL_TREE));
- FOR_INIT_STMT (r) = push_stmt_list ();
- return r;
-}
-
-void
-c_finish_for_stmt_init (tree for_stmt)
+c_finish_bc_stmt (tree *label_p, bool is_break)
{
- FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
-}
+ tree label = *label_p;
-void
-c_finish_for_stmt_cond (tree cond, tree for_stmt)
-{
- if (cond)
- FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
-}
+ if (!label)
+ *label_p = label = create_artificial_label ();
+ else if (TREE_CODE (label) != LABEL_DECL)
+ {
+ if (is_break)
+ error ("break statement not within loop or switch");
+ else
+ error ("continue statement not within a loop");
+ return NULL_TREE;
+ }
-void
-c_finish_for_stmt_incr (tree expr, tree for_stmt)
-{
- FOR_EXPR (for_stmt) = expr;
+ return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
}
-void
-c_finish_for_stmt (tree body, tree for_stmt)
-{
- FOR_BODY (for_stmt) = body;
-}
-\f
-/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr. */
+/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */
static void
emit_side_effect_warnings (tree expr)
{
- if (!TREE_SIDE_EFFECTS (expr))
+ if (expr == error_mark_node)
+ ;
+ else if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
warning ("%Hstatement with no effect",
- EXPR_LOCUS (expr) ? EXPR_LOCUS (expr) : &input_location);
+ EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
}
else if (warn_unused_value)
warn_if_unused_value (expr, input_location);
}
-/* Emit an expression as a statement. */
+/* Process an expression as if it were a complete statement. Emit
+ diagnostics, but do not call ADD_STMT. */
-void
-c_finish_expr_stmt (tree expr)
+tree
+c_process_expr_stmt (tree expr)
{
if (!expr)
- return;
+ return NULL_TREE;
/* Do default conversion if safe and possibly important,
in case within ({...}). */
/* If the expression is not of a type to which we cannot assign a line
number, wrap the thing in a no-op NOP_EXPR. */
- if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+ if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
- add_stmt (expr);
+ if (EXPR_P (expr))
+ SET_EXPR_LOCATION (expr, input_location);
+
+ return expr;
+}
+
+/* Emit an expression as a statement. */
+
+tree
+c_finish_expr_stmt (tree expr)
+{
+ if (expr)
+ return add_stmt (c_process_expr_stmt (expr));
+ else
+ return NULL;
}
/* Do the opposite and emit a statement as an expression. To begin,
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
- if (last == BIND_EXPR_BODY (body) && BIND_EXPR_VARS (body) == NULL)
+ if (last == error_mark_node
+ || (last == BIND_EXPR_BODY (body)
+ && BIND_EXPR_VARS (body) == NULL))
return last;
/* Extract the type of said expression. */
&& TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
val = TREE_OPERAND (val, 0);
- *last_p = build (MODIFY_EXPR, void_type_node, tmp, val);
+ *last_p = build2 (MODIFY_EXPR, void_type_node, tmp, val);
SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
- return build (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
+ return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
\f
/* Begin and end compound statements. This is as simple as pushing
{
tree stmt = push_stmt_list ();
if (do_scope)
- {
- push_scope ();
- clear_last_expr ();
- }
+ push_scope ();
return stmt;
}
&& STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
&& TREE_CODE (stmt) != BIND_EXPR)
{
- stmt = build (BIND_EXPR, void_type_node, NULL, stmt, NULL);
+ stmt = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL);
TREE_SIDE_EFFECTS (stmt) = 1;
}
meant to apply to normal control flow transfer. */
void
-push_cleanup (tree decl ATTRIBUTE_UNUSED, tree cleanup, bool eh_only)
+push_cleanup (tree ARG_UNUSED (decl), tree cleanup, bool eh_only)
{
enum tree_code code;
tree stmt, list;
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
+ if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
+ code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+ if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
+ code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
dividing by something we know != -1. */
shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
|| (TREE_CODE (op1) == INTEGER_CST
- && ! integer_all_onesp (op1)));
+ && !integer_all_onesp (op1)));
common = 1;
}
break;
only if unsigned or if dividing by something we know != -1. */
shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
|| (TREE_CODE (op1) == INTEGER_CST
- && ! integer_all_onesp (op1)));
+ && !integer_all_onesp (op1)));
common = 1;
}
break;
warning ("right shift count is negative");
else
{
- if (! integer_zerop (op1))
+ if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
}
break;
- case RROTATE_EXPR:
- case LROTATE_EXPR:
- if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
- {
- if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
- {
- if (tree_int_cst_sgn (op1) < 0)
- warning ("shift count is negative");
- else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("shift count >= width of type");
- }
-
- /* Use the type of the value to be shifted. */
- result_type = type0;
- /* 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;
-
case EQ_EXPR:
case NE_EXPR:
if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
whose value is 0 but which isn't a valid null ptr const. */
if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
&& TREE_CODE (tt1) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C forbids comparison of %<void *%>"
+ " with function pointer");
}
else if (VOID_TYPE_P (tt1))
{
if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
&& TREE_CODE (tt0) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C forbids comparison of %<void *%>"
+ " with function pointer");
}
else
pedwarn ("comparison of distinct pointer types lacks a cast");
}
break;
- case MAX_EXPR:
- case MIN_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
- shorten = 1;
- else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
- {
- if (comp_target_types (type0, type1, 1))
- {
- result_type = common_pointer_type (type0, type1);
- if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
- }
- else
- {
- result_type = ptr_type_node;
- pedwarn ("comparison of distinct pointer types lacks a cast");
- }
- }
- break;
-
case LE_EXPR:
case GE_EXPR:
case LT_EXPR:
}
break;
- case UNORDERED_EXPR:
- case ORDERED_EXPR:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case UNEQ_EXPR:
- case LTGT_EXPR:
- build_type = integer_type_node;
- if (code0 != REAL_TYPE || code1 != REAL_TYPE)
- {
- error ("unordered comparison on non-floating point argument");
- return error_mark_node;
- }
- common = 1;
- break;
-
default:
- break;
+ gcc_unreachable ();
}
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
if (warn_sign_compare && skip_evaluation == 0)
{
- int op0_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op0));
- int op1_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+ int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1));
int unsignedp0, unsignedp1;
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
Do not warn if the comparison is being done in a signed type,
since the signed type will only be chosen if it can represent
all the values of the unsigned type. */
- if (! TYPE_UNSIGNED (result_type))
+ if (!TYPE_UNSIGNED (result_type))
/* OK */;
/* Do not warn if both operands are the same signedness. */
else if (op0_signed == op1_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)),
+ (TYPE_MAX_VALUE (TREE_TYPE (uop)),
c_common_signed_type (result_type)))
/* OK */;
else
if (bits < TYPE_PRECISION (result_type)
&& bits < HOST_BITS_PER_WIDE_INT && unsignedp)
{
- mask = (~ (HOST_WIDE_INT) 0) << bits;
+ mask = (~(HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
warning ("comparison of promoted ~unsigned with constant");
}
return error_mark_node;
}
- if (! converted)
+ if (!converted)
{
if (TREE_TYPE (op0) != result_type)
op0 = convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
op1 = convert (result_type, op1);
+
+ /* This can happen if one operand has a vector type, and the other
+ has a different type. */
+ if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
}
if (build_type == NULL_TREE)
build_type = result_type;
{
- tree result = build (resultcode, build_type, op0, op1);
+ tree result = build2 (resultcode, build_type, op0, op1);
/* Treat expressions in initializers specially as they can't trap. */
result = require_constant_value ? fold_initializer (result)
return result;
}
}
-
-/* Build the result of __builtin_offsetof. TYPE is the first argument to
- offsetof, i.e. a type. LIST is a tree_list that encodes component and
- array references; PURPOSE is set for the former and VALUE is set for
- the later. */
-
-tree
-build_offsetof (tree type, tree list)
-{
- tree t;
-
- /* Build "*(type *)0". */
- t = convert (build_pointer_type (type), null_pointer_node);
- t = build_indirect_ref (t, "");
-
- /* Build COMPONENT and ARRAY_REF expressions as needed. */
- for (list = nreverse (list); list ; list = TREE_CHAIN (list))
- if (TREE_PURPOSE (list))
- t = build_component_ref (t, TREE_PURPOSE (list));
- else
- t = build_array_ref (t, TREE_VALUE (list));
-
- /* Finalize the offsetof expression. For now all we need to do is take
- the address of the expression we created, and cast that to an integer
- type; this mirrors the traditional macro implementation of offsetof. */
- t = build_unary_op (ADDR_EXPR, t, 0);
- return convert (size_type_node, t);
-}