/* Build expressions with type checking for C compiler.
- Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file is part of the C front end.
#include "target.h"
#include "tree-iterator.h"
#include "tree-gimple.h"
-
-/* Places where an lvalue, or modifiable lvalue, may be required.
- Used to select diagnostic messages in lvalue_or_else and
- readonly_error. */
-enum lvalue_use {
- lv_assign,
- lv_increment,
- lv_decrement,
- lv_addressof,
- lv_asm
-};
+#include "tree-flow.h"
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
/* The level of nesting inside "typeof". */
int in_typeof;
+struct c_label_context_se *label_context_stack_se;
+struct c_label_context_vm *label_context_stack_vm;
+
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
static tree qualify_type (tree, tree);
static int tagged_types_tu_compatible_p (tree, tree);
-static int comp_target_types (tree, tree, int);
+static int comp_target_types (tree, tree);
static int function_types_compatible_p (tree, tree);
static int type_lists_compatible_p (tree, tree);
static tree decl_constant_value_for_broken_optimization (tree);
-static tree default_function_array_conversion (tree);
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, 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, enum lvalue_use);
static void readonly_error (tree, enum lvalue_use);
+static int lvalue_or_else (tree, enum lvalue_use);
+static int lvalue_p (tree);
static void record_maybe_used_decl (tree);
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
if (value != 0 && (TREE_CODE (value) == VAR_DECL
|| TREE_CODE (value) == PARM_DECL))
- error ("%qs has an incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (value)));
+ error ("%qD has an incomplete type", value);
else
{
retry:
}
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- error ("invalid use of undefined type %<%s %s%>",
- type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type)));
+ error ("invalid use of undefined type %<%s %E%>",
+ type_code_string, TYPE_NAME (type));
else
/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
- error ("invalid use of incomplete typedef %qs",
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+ error ("invalid use of incomplete typedef %qD", TYPE_NAME (type));
}
}
case ARRAY_TYPE:
{
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
-
+ int quals;
+ tree unqual_elt;
+
/* We should not have any type quals on arrays at all. */
gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t2, attributes);
- /* Merge the element types, and have a size if either arg has one. */
- t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ /* Merge the element types, and have a size if either arg has
+ one. We may have qualifiers on the element types. To set
+ up TYPE_MAIN_VARIANT correctly, we need to form the
+ composite of the unqualified types and add the qualifiers
+ back at the end. */
+ quals = TYPE_QUALS (strip_array_types (elt));
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+ t1 = build_array_type (unqual_elt,
+ TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ t1 = c_build_qualified_type (t1, quals);
return build_type_attribute_variant (t1, attributes);
}
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
/* Tell global_bindings_p to return false so that variable_size
- doesn't abort on VLAs in parameter types. */
+ doesn't die on VLAs in parameter types. */
c_override_global_bindings_to_false = true;
len = list_length (p1);
&& TREE_VALUE (p1) != TREE_VALUE (p2))
{
tree memb;
+ tree mv2 = TREE_VALUE (p2);
+ if (mv2 && mv2 != error_mark_node
+ && TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (mv2);
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
- {
- TREE_VALUE (n) = TREE_VALUE (p2);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p2));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
&& TREE_VALUE (p2) != TREE_VALUE (p1))
{
tree memb;
+ tree mv1 = TREE_VALUE (p1);
+ if (mv1 && mv1 != error_mark_node
+ && TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (mv1);
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
- {
- TREE_VALUE (n) = TREE_VALUE (p1);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p1));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
parm_done: ;
common_pointer_type (tree t1, tree t2)
{
tree attributes;
- tree pointed_to_1;
- tree pointed_to_2;
+ tree pointed_to_1, mv1;
+ tree pointed_to_2, mv2;
tree target;
/* Save time if the two types are the same. */
attributes = targetm.merge_type_attributes (t1, t2);
/* Find the composite type of the target types, and combine the
- qualifiers of the two types' targets. */
- pointed_to_1 = TREE_TYPE (t1);
- pointed_to_2 = TREE_TYPE (t2);
- target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
- TYPE_MAIN_VARIANT (pointed_to_2));
+ qualifiers of the two types' targets. Do not lose qualifiers on
+ array element types by taking the TYPE_MAIN_VARIANT. */
+ mv1 = pointed_to_1 = TREE_TYPE (t1);
+ mv2 = pointed_to_2 = TREE_TYPE (t2);
+ if (TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (pointed_to_1);
+ if (TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
+ target = composite_type (mv1, mv2);
t1 = build_pointer_type (c_build_qualified_type
(target,
TYPE_QUALS (pointed_to_1) |
This is the type for the result of most arithmetic operations
if the operands have the given two types. */
-tree
-common_type (tree t1, tree t2)
+static tree
+c_common_type (tree t1, tree t2)
{
enum tree_code code1;
enum tree_code code2;
{
tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
- tree subtype = common_type (subtype1, subtype2);
+ tree subtype = c_common_type (subtype1, subtype2);
if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
return t1;
return t2;
}
\f
+/* Wrapper around c_common_type that is used by c-common.c. ENUMERAL_TYPEs
+ are allowed here and are converted to their compatible integer types.
+ BOOLEAN_TYPEs are allowed here and return either boolean_type_node or
+ preferably a non-Boolean type as the common type. */
+tree
+common_type (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) == ENUMERAL_TYPE)
+ t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
+ if (TREE_CODE (t2) == ENUMERAL_TYPE)
+ t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
+
+ /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */
+ if (TREE_CODE (t1) == BOOLEAN_TYPE
+ && TREE_CODE (t2) == BOOLEAN_TYPE)
+ return boolean_type_node;
+
+ /* If either type is BOOLEAN_TYPE, then return the other. */
+ if (TREE_CODE (t1) == BOOLEAN_TYPE)
+ return t2;
+ if (TREE_CODE (t2) == BOOLEAN_TYPE)
+ return t1;
+
+ return c_common_type (t1, t2);
+}
+\f
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. */
definition. Note that we already checked for equality of the type
qualifiers (just above). */
- if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ if (TREE_CODE (t1) != ARRAY_TYPE
+ && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
switch (TREE_CODE (t1))
{
case POINTER_TYPE:
- /* We must give ObjC the first crack at comparing pointers, since
- 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;
}
- case RECORD_TYPE:
- /* We are dealing with two distinct structs. In assorted Objective-C
- corner cases, however, these can still be deemed equivalent. */
- if (c_dialect_objc () && objc_comptypes (t1, t2, 0) == 1)
- val = 1;
-
case ENUMERAL_TYPE:
+ case RECORD_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
val = tagged_types_tu_compatible_p (t1, t2);
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. REFLEXIVE is only used by ObjC - set it
- to 1 or 0 depending if the check of the pointer types is meant to
- be reflexive or not (typically, assignments are not reflexive,
- while comparisons are reflexive).
-*/
+ ignoring their qualifiers. */
static int
-comp_target_types (tree ttl, tree ttr, int reflexive)
+comp_target_types (tree ttl, tree ttr)
{
int val;
-
- /* Give objc_comptypes a crack at letting these types through. */
- if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
- return val;
-
- val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
- TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+ tree mvl, mvr;
+
+ /* Do not lose qualifiers on element types of array types that are
+ pointer targets by taking their TYPE_MAIN_VARIANT. */
+ mvl = TREE_TYPE (ttl);
+ mvr = TREE_TYPE (ttr);
+ if (TREE_CODE (mvl) != ARRAY_TYPE)
+ mvl = TYPE_MAIN_VARIANT (mvl);
+ if (TREE_CODE (mvr) != ARRAY_TYPE)
+ mvr = TYPE_MAIN_VARIANT (mvr);
+ val = comptypes (mvl, mvr);
if (val == 2 && pedantic)
pedwarn ("types are not quite compatible");
while (1)
{
+ tree a1, mv1, a2, mv2;
if (args1 == 0 && args2 == 0)
return val;
/* If one list is shorter than the other,
they fail to match. */
if (args1 == 0 || args2 == 0)
return 0;
+ mv1 = a1 = TREE_VALUE (args1);
+ mv2 = a2 = TREE_VALUE (args2);
+ if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (mv1);
+ if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (mv2);
/* A null pointer instead of a type
means there is supposed to be an argument
but nothing is specified about what type it has.
So match anything that self-promotes. */
- if (TREE_VALUE (args1) == 0)
+ if (a1 == 0)
{
- if (c_type_promotes_to (TREE_VALUE (args2)) != TREE_VALUE (args2))
+ if (c_type_promotes_to (a2) != a2)
return 0;
}
- else if (TREE_VALUE (args2) == 0)
+ else if (a2 == 0)
{
- if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
+ if (c_type_promotes_to (a1) != a1)
return 0;
}
/* If one of the lists has an error marker, ignore this arg. */
- else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
- || TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
+ else if (TREE_CODE (a1) == ERROR_MARK
+ || TREE_CODE (a2) == ERROR_MARK)
;
- else if (!(newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
- TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+ else if (!(newval = comptypes (mv1, mv2)))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
- if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
- && (TYPE_NAME (TREE_VALUE (args1)) == 0
- || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
- && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
- && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
- TYPE_SIZE (TREE_VALUE (args2))))
+ if (TREE_CODE (a1) == UNION_TYPE
+ && (TYPE_NAME (a1) == 0
+ || TYPE_TRANSPARENT_UNION (a1))
+ && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
+ && tree_int_cst_equal (TYPE_SIZE (a1),
+ TYPE_SIZE (a2)))
{
tree memb;
- for (memb = TYPE_FIELDS (TREE_VALUE (args1));
+ for (memb = TYPE_FIELDS (a1);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ break;
+ }
if (memb == 0)
return 0;
}
- else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
- && (TYPE_NAME (TREE_VALUE (args2)) == 0
- || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
- && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
- && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
- TYPE_SIZE (TREE_VALUE (args1))))
+ else if (TREE_CODE (a2) == UNION_TYPE
+ && (TYPE_NAME (a2) == 0
+ || TYPE_TRANSPARENT_UNION (a2))
+ && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
+ && tree_int_cst_equal (TYPE_SIZE (a2),
+ TYPE_SIZE (a1)))
{
tree memb;
- for (memb = TYPE_FIELDS (TREE_VALUE (args2));
+ for (memb = TYPE_FIELDS (a2);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ break;
+ }
if (memb == 0)
return 0;
}
static tree
decl_constant_value_for_broken_optimization (tree decl)
{
+ tree ret;
+
if (pedantic || DECL_MODE (decl) == BLKmode)
return decl;
- else
- return decl_constant_value (decl);
-}
-
-/* Perform the default conversion of arrays and functions to pointers.
- Return the result of converting EXP. For any other expression, just
- return EXP. */
+ ret = decl_constant_value (decl);
+ /* Avoid unwanted tree sharing between the initializer and current
+ function's body where the tree can be modified e.g. by the
+ gimplifier. */
+ if (ret != decl && TREE_STATIC (decl))
+ ret = unshare_expr (ret);
+ return ret;
+}
+/* Convert the array expression EXP to a pointer. */
static tree
-default_function_array_conversion (tree exp)
+array_to_pointer_conversion (tree exp)
{
- tree orig_exp;
+ tree orig_exp = exp;
tree type = TREE_TYPE (exp);
- enum tree_code code = TREE_CODE (type);
- int not_lvalue = 0;
+ tree adr;
+ tree restype = TREE_TYPE (type);
+ tree ptrtype;
- /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
- an lvalue.
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
- Do not use STRIP_NOPS here! It will remove conversions from pointer
- to integer and cause infinite recursion. */
- orig_exp = exp;
- while (TREE_CODE (exp) == NON_LVALUE_EXPR
- || (TREE_CODE (exp) == NOP_EXPR
- && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
- {
- if (TREE_CODE (exp) == NON_LVALUE_EXPR)
- not_lvalue = 1;
- exp = TREE_OPERAND (exp, 0);
- }
+ STRIP_TYPE_NOPS (exp);
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
- if (code == FUNCTION_TYPE)
+ ptrtype = build_pointer_type (restype);
+
+ if (TREE_CODE (exp) == INDIRECT_REF)
+ return convert (ptrtype, TREE_OPERAND (exp, 0));
+
+ if (TREE_CODE (exp) == VAR_DECL)
{
- return build_unary_op (ADDR_EXPR, exp, 0);
+ /* We are making an ADDR_EXPR of ptrtype. This is a valid
+ ADDR_EXPR because it's the best way of representing what
+ happens in C when we take the address of an array and place
+ it in a pointer to the element type. */
+ adr = build1 (ADDR_EXPR, ptrtype, exp);
+ if (!c_mark_addressable (exp))
+ return error_mark_node;
+ TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
+ return adr;
}
- if (code == ARRAY_TYPE)
- {
- tree adr;
- tree restype = TREE_TYPE (type);
- tree ptrtype;
- int constp = 0;
- int volatilep = 0;
- int lvalue_array_p;
-
- if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
- {
- constp = TREE_READONLY (exp);
- volatilep = TREE_THIS_VOLATILE (exp);
- }
- if (TYPE_QUALS (type) || constp || volatilep)
- restype
- = c_build_qualified_type (restype,
- TYPE_QUALS (type)
- | (constp * TYPE_QUAL_CONST)
- | (volatilep * TYPE_QUAL_VOLATILE));
+ /* This way is better for a COMPONENT_REF since it can
+ simplify the offset for a component. */
+ adr = build_unary_op (ADDR_EXPR, exp, 1);
+ return convert (ptrtype, adr);
+}
- if (TREE_CODE (exp) == INDIRECT_REF)
- return convert (build_pointer_type (restype),
- TREE_OPERAND (exp, 0));
+/* Convert the function expression EXP to a pointer. */
+static tree
+function_to_pointer_conversion (tree exp)
+{
+ tree orig_exp = exp;
- if (TREE_CODE (exp) == COMPOUND_EXPR)
- {
- tree op1 = default_conversion (TREE_OPERAND (exp, 1));
- return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
- TREE_OPERAND (exp, 0), op1);
- }
+ gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE);
- lvalue_array_p = !not_lvalue && lvalue_p (exp);
- if (!flag_isoc99 && !lvalue_array_p)
- {
- /* Before C99, non-lvalue arrays do not decay to pointers.
- Normally, using such an array would be invalid; but it can
- be used correctly inside sizeof or as a statement expression.
- Thus, do not give an error here; an error will result later. */
- return exp;
- }
+ STRIP_TYPE_NOPS (exp);
- ptrtype = build_pointer_type (restype);
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
- if (TREE_CODE (exp) == VAR_DECL)
- {
- /* We are making an ADDR_EXPR of ptrtype. This is a valid
- ADDR_EXPR because it's the best way of representing what
- happens in C when we take the address of an array and place
- it in a pointer to the element type. */
- adr = build1 (ADDR_EXPR, ptrtype, exp);
- if (!c_mark_addressable (exp))
- return error_mark_node;
- TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
- return adr;
- }
- /* This way is better for a COMPONENT_REF since it can
- simplify the offset for a component. */
- adr = build_unary_op (ADDR_EXPR, exp, 1);
- return convert (ptrtype, adr);
- }
- return exp;
+ return build_unary_op (ADDR_EXPR, exp, 0);
}
-/* Perform default promotions for C data used in expressions.
- Arrays and functions are converted to pointers;
- enumeral types or short or char, to int.
- In addition, manifest constants symbols are replaced by their values. */
+/* Perform the default conversion of arrays and functions to pointers.
+ Return the result of converting EXP. For any other expression, just
+ return EXP after removing NOPs. */
-tree
-default_conversion (tree exp)
+struct c_expr
+default_function_array_conversion (struct c_expr exp)
{
- tree orig_exp;
- tree type = TREE_TYPE (exp);
+ tree orig_exp = exp.value;
+ tree type = TREE_TYPE (exp.value);
enum tree_code code = TREE_CODE (type);
- if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
- return default_function_array_conversion (exp);
+ switch (code)
+ {
+ case ARRAY_TYPE:
+ {
+ bool not_lvalue = false;
+ bool lvalue_array_p;
- /* Constants can be used directly unless they're not loadable. */
- if (TREE_CODE (exp) == CONST_DECL)
- exp = DECL_INITIAL (exp);
+ while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR
+ || TREE_CODE (exp.value) == NOP_EXPR)
+ && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type)
+ {
+ if (TREE_CODE (exp.value) == NON_LVALUE_EXPR)
+ not_lvalue = true;
+ exp.value = TREE_OPERAND (exp.value, 0);
+ }
- /* Replace a nonvolatile const static variable with its value unless
- it is an array, in which case we must be sure that taking the
- address of the array produces consistent results. */
- else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
- {
- exp = decl_constant_value_for_broken_optimization (exp);
- type = TREE_TYPE (exp);
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp.value) = 1;
+
+ lvalue_array_p = !not_lvalue && lvalue_p (exp.value);
+ if (!flag_isoc99 && !lvalue_array_p)
+ {
+ /* Before C99, non-lvalue arrays do not decay to pointers.
+ Normally, using such an array would be invalid; but it can
+ be used correctly inside sizeof or as a statement expression.
+ Thus, do not give an error here; an error will result later. */
+ return exp;
+ }
+
+ exp.value = array_to_pointer_conversion (exp.value);
+ }
+ break;
+ case FUNCTION_TYPE:
+ exp.value = function_to_pointer_conversion (exp.value);
+ break;
+ default:
+ STRIP_TYPE_NOPS (exp.value);
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp.value) = 1;
+ break;
}
- /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
- an lvalue.
+ return exp;
+}
- Do not use STRIP_NOPS here! It will remove conversions from pointer
- to integer and cause infinite recursion. */
- orig_exp = exp;
- while (TREE_CODE (exp) == NON_LVALUE_EXPR
- || (TREE_CODE (exp) == NOP_EXPR
- && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
- exp = TREE_OPERAND (exp, 0);
- if (TREE_NO_WARNING (orig_exp))
- TREE_NO_WARNING (exp) = 1;
+/* EXP is an expression of integer type. Apply the integer promotions
+ to it and return the promoted value. */
+
+tree
+perform_integral_promotions (tree exp)
+{
+ tree type = TREE_TYPE (exp);
+ enum tree_code code = TREE_CODE (type);
+
+ gcc_assert (INTEGRAL_TYPE_P (type));
/* Normally convert enums to int,
but convert wide enums to something wider. */
return convert (type, exp);
}
+ /* ??? This should no longer be needed now bit-fields have their
+ proper types. */
if (TREE_CODE (exp) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
/* If it's thinner than an int, promote it like a
return convert (integer_type_node, exp);
}
+ return exp;
+}
+
+
+/* Perform default promotions for C data used in expressions.
+ Enumeral types or short or char are converted to int.
+ In addition, manifest constants symbols are replaced by their values. */
+
+tree
+default_conversion (tree exp)
+{
+ tree orig_exp;
+ tree type = TREE_TYPE (exp);
+ enum tree_code code = TREE_CODE (type);
+
+ /* Functions and arrays have been converted during parsing. */
+ gcc_assert (code != FUNCTION_TYPE);
+ if (code == ARRAY_TYPE)
+ return exp;
+
+ /* Constants can be used directly unless they're not loadable. */
+ if (TREE_CODE (exp) == CONST_DECL)
+ exp = DECL_INITIAL (exp);
+
+ /* Replace a nonvolatile const static variable with its value unless
+ it is an array, in which case we must be sure that taking the
+ address of the array produces consistent results. */
+ else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
+ {
+ exp = decl_constant_value_for_broken_optimization (exp);
+ type = TREE_TYPE (exp);
+ }
+
+ /* Strip no-op conversions. */
+ orig_exp = exp;
+ STRIP_TYPE_NOPS (exp);
+
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
+
+ if (INTEGRAL_TYPE_P (type))
+ return perform_integral_promotions (exp);
+
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC
will always be set for structures which have many elements. */
- if (TYPE_LANG_SPECIFIC (type))
+ if (TYPE_LANG_SPECIFIC (type) && TYPE_LANG_SPECIFIC (type)->s)
{
int bot, top, half;
tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0];
if (!field)
{
- error ("%qT has no member named %qs", type,
- IDENTIFIER_POINTER (component));
+ error ("%qT has no member named %qE", type, component);
return error_mark_node;
}
return ref;
}
else if (code != ERROR_MARK)
- error ("request for member %qs in something not a structure or union",
- IDENTIFIER_POINTER (component));
+ error ("request for member %qE in something not a structure or union",
+ component);
return error_mark_node;
}
else
{
tree t = TREE_TYPE (type);
- tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
+ tree ref;
+
+ ref = build1 (INDIRECT_REF, t, pointer);
if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
{
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning ("dereferencing %<void *%> pointer");
+ warning (0, "dereferencing %<void *%> pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
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 (!swapped
+ && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
+ warning (OPT_Wchar_subscripts, "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
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
- type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+ type = TREE_TYPE (TREE_TYPE (array));
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ type = TYPE_MAIN_VARIANT (type);
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is. */
| 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
- whether this will be used for a function call. */
+ whether this will be used for a function call. LOC is the source
+ location of the identifier. */
tree
-build_external_ref (tree id, int fun)
+build_external_ref (tree id, int fun, location_t loc)
{
tree ref;
tree decl = lookup_name (id);
return error_mark_node;
else
{
- undeclared_variable (id);
+ undeclared_variable (id, loc);
return error_mark_node;
}
/* Convert anything with function type to a pointer-to-function. */
if (TREE_CODE (function) == FUNCTION_DECL)
{
- name = DECL_NAME (function);
+ /* Implement type-directed function overloading for builtins.
+ resolve_overloaded_builtin and targetm.resolve_overloaded_builtin
+ handle all the type checking. The result is a complete expression
+ that implements this function call. */
+ tem = resolve_overloaded_builtin (function, params);
+ if (tem)
+ return tem;
- /* Differs from default_conversion by not setting TREE_ADDRESSABLE
- (because calling an inline function does not mean the function
- needs to be separately compiled). */
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
+ name = DECL_NAME (function);
fundecl = function;
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
}
- else
- function = default_conversion (function);
+ if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
+ function = function_to_pointer_conversion (function);
+
+ /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
+ expressions, like those used for ObjC messenger dispatches. */
+ function = objc_rewrite_function_call (function, params);
fntype = TREE_TYPE (function);
If it is not, replace the call by a trap, wrapped up in a compound
expression if necessary. This has the nice side-effect to prevent
the tree-inliner from generating invalid assignment trees which may
- blow up in the RTL expander later.
-
- ??? 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 ()
- && TREE_CODE (function) == NOP_EXPR
+ blow up in the RTL expander later. */
+ if (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)))
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
executions of the program must execute the code. */
- warning ("function called through a non-compatible type");
+ warning (0, "function called through a non-compatible type");
/* We can, however, treat "undefined" any way we please.
Call abort to encourage the user to fix the program. */
if (AGGREGATE_TYPE_P (return_type))
rhs = build_compound_literal (return_type,
- build_constructor (return_type,
- NULL_TREE));
+ build_constructor (return_type, 0));
else
- rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
+ rhs = fold_build1 (NOP_EXPR, return_type, integer_zero_node);
return build2 (COMPOUND_EXPR, return_type, trap, rhs);
}
/* Check that the arguments to the function are valid. */
- check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
+ check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
+ TYPE_ARG_TYPES (fntype));
result = build3 (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
tree val = TREE_VALUE (valtail);
tree rname = function;
int argnum = parmnum + 1;
+ const char *invalid_func_diag;
if (type == void_type_node)
{
argnum -= 2;
}
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here! We do not want an enumerator with value 0
- to convert automatically to a pointer. */
- if (TREE_CODE (val) == NON_LVALUE_EXPR)
- val = TREE_OPERAND (val, 0);
-
- val = default_function_array_conversion (val);
+ STRIP_TYPE_NOPS (val);
val = require_complete_type (val);
/* Formal parm type is specified by a function prototype. */
tree parmval;
- if (!COMPLETE_TYPE_P (type))
+ if (type == error_mark_node || !COMPLETE_TYPE_P (type))
{
error ("type of formal parameter %d is incomplete", parmnum + 1);
parmval = val;
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than floating due to prototype",
argnum, rname);
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than complex due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than floating due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than complex due to prototype",
argnum, rname);
/* ??? At some point, messages should be written about
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
if (formal_prec == TYPE_PRECISION (float_type_node))
- warning ("passing argument %d of %qE as %<float%> "
+ warning (0, "passing argument %d of %qE as %<float%> "
"rather than %<double%> due to prototype",
argnum, rname);
}
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warning ("passing argument %d of %qE with different "
- "width due to prototype", argnum, rname);
+ warning (OPT_Wconversion, "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
/* Change in signedness doesn't matter
if a constant value is unaffected. */
;
- /* Likewise for a constant in a NOP_EXPR. */
- else if (TREE_CODE (val) == NOP_EXPR
- && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST
- && int_fits_type_p (TREE_OPERAND (val, 0), type))
- ;
/* If the value is extended from a narrower
unsigned type, it doesn't matter whether we
pass it as signed or unsigned; the value
&& TYPE_UNSIGNED (TREE_TYPE (val)))
;
else if (TYPE_UNSIGNED (type))
- warning ("passing argument %d of %qE as unsigned "
- "due to prototype", argnum, rname);
+ warning (OPT_Wconversion, "passing argument %d of %qE "
+ "as unsigned due to prototype",
+ argnum, rname);
else
- warning ("passing argument %d of %qE as signed "
- "due to prototype", argnum, rname);
+ warning (OPT_Wconversion, "passing argument %d of %qE "
+ "as signed due to prototype", argnum, rname);
}
}
< TYPE_PRECISION (double_type_node)))
/* Convert `float' to `double'. */
result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+ else if ((invalid_func_diag =
+ targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+ {
+ error (invalid_func_diag);
+ return error_mark_node;
+ }
else
/* Convert `short' and `char' to full-size `int'. */
result = tree_cons (NULL_TREE, default_conversion (val), result);
return nreverse (result);
}
\f
-/* This is the entry point used by the parser
- for binary operators in the input.
- In addition to constructing the expression,
- we check for operands that were written with other binary operators
- in a way that is likely to confuse the user. */
+/* This is the entry point used by the parser to build unary operators
+ in the input. CODE, a tree_code, specifies the unary operator, and
+ ARG is the operand. For unary plus, the C parser currently uses
+ CONVERT_EXPR for code. */
+
+struct c_expr
+parser_build_unary_op (enum tree_code code, struct c_expr arg)
+{
+ struct c_expr result;
+
+ result.original_code = ERROR_MARK;
+ result.value = build_unary_op (code, arg.value, 0);
+ overflow_warning (result.value);
+ return result;
+}
+
+/* This is the entry point used by the parser to build binary operators
+ in the input. CODE, a tree_code, specifies the binary operator, and
+ ARG1 and ARG2 are the operands. In addition to constructing the
+ expression, we check for operands that were written with other binary
+ operators in a way that is likely to confuse the user. */
struct c_expr
parser_build_binary_op (enum tree_code code, struct c_expr arg1,
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around + or - inside shift");
+ warning (0, "suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code1 == TRUTH_ANDIF_EXPR
|| code2 == TRUTH_ANDIF_EXPR)
- warning ("suggest parentheses around && within ||");
+ warning (0, "suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of |");
+ warning (0, "suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of |");
+ warning (0, "suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of ^");
+ warning (0, "suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of ^");
+ warning (0, "suggest parentheses around comparison in operand of ^");
}
if (code == BIT_AND_EXPR)
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around + or - in operand of &");
+ warning (0, "suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning ("suggest parentheses around comparison in operand of &");
+ warning (0, "suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
if (TREE_CODE_CLASS (code) == tcc_comparison
&& (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison))
- warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
+ warning (0, "comparisons like X<=Y<=Z do not have their mathematical meaning");
}
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold (build2 (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
enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
tree val;
int noconvert = flag;
+ const char *invalid_op_diag;
if (typecode == ERROR_MARK)
return error_mark_node;
if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
typecode = INTEGER_TYPE;
+ if ((invalid_op_diag
+ = targetm.invalid_unary_op (code, TREE_TYPE (xarg))))
+ {
+ error (invalid_op_diag);
+ return error_mark_node;
+ }
+
switch (code)
{
case CONVERT_EXPR:
case TRUTH_NOT_EXPR:
if (typecode != INTEGER_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
- && typecode != COMPLEX_TYPE
- /* These will convert to a pointer. */
- && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
+ && typecode != COMPLEX_TYPE)
{
error ("wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = lang_hooks.truthvalue_conversion (arg);
+ arg = c_objc_common_truthvalue_conversion (arg);
return invert_truthvalue (arg);
case NOP_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_REALPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ return fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
return arg;
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_IMAGPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ return fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
return convert (TREE_TYPE (arg), integer_zero_node);
/* For &x[y], return x+y */
if (TREE_CODE (arg) == ARRAY_REF)
{
- if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
+ tree op0 = TREE_OPERAND (arg, 0);
+ if (!c_mark_addressable (op0))
return error_mark_node;
- return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
+ return build_binary_op (PLUS_EXPR,
+ (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
+ ? array_to_pointer_conversion (op0)
+ : op0),
TREE_OPERAND (arg, 1), 1);
}
val = build1 (ADDR_EXPR, argtype, arg);
- if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
- TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
-
return val;
default:
Lvalues can be assigned, unless their type has TYPE_READONLY.
Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
-int
+static int
lvalue_p (tree ref)
{
enum tree_code code = TREE_CODE (ref);
return 0;
}
}
-
-/* Return nonzero if REF is an lvalue valid for this language;
- otherwise, print an error message and return zero. USE says
- how the lvalue is being used and so selects the error message. */
-
-static int
-lvalue_or_else (tree ref, enum lvalue_use use)
-{
- int win = lvalue_p (ref);
-
- if (!win)
- {
- switch (use)
- {
- case lv_assign:
- error ("invalid lvalue in assignment");
- break;
- case lv_increment:
- error ("invalid lvalue in increment");
- break;
- case lv_decrement:
- error ("invalid lvalue in decrement");
- break;
- case lv_addressof:
- error ("invalid lvalue in unary %<&%>");
- break;
- case lv_asm:
- error ("invalid lvalue in asm statement");
- break;
- default:
- gcc_unreachable ();
- }
- }
-
- return win;
-}
-
\f
/* Give an error for storing in something that is 'const'. */
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
readonly_error (TREE_OPERAND (arg, 0), use);
else
- error (READONLY_MSG (N_("assignment of read-only member %qs"),
- N_("increment of read-only member %qs"),
- N_("decrement of read-only member %qs")),
- IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
+ error (READONLY_MSG (G_("assignment of read-only member %qD"),
+ G_("increment of read-only member %qD"),
+ G_("decrement of read-only member %qD")),
+ TREE_OPERAND (arg, 1));
}
else if (TREE_CODE (arg) == VAR_DECL)
- error (READONLY_MSG (N_("assignment of read-only variable %qs"),
- N_("increment of read-only variable %qs"),
- N_("decrement of read-only variable %qs")),
- IDENTIFIER_POINTER (DECL_NAME (arg)));
+ error (READONLY_MSG (G_("assignment of read-only variable %qD"),
+ G_("increment of read-only variable %qD"),
+ G_("decrement of read-only variable %qD")),
+ arg);
else
- error (READONLY_MSG (N_("assignment of read-only location"),
- N_("increment of read-only location"),
- N_("decrement of read-only location")));
+ error (READONLY_MSG (G_("assignment of read-only location"),
+ G_("increment of read-only location"),
+ G_("decrement of read-only location")));
+}
+
+
+/* Return nonzero if REF is an lvalue valid for this language;
+ otherwise, print an error message and return zero. USE says
+ how the lvalue is being used and so selects the error message. */
+
+static int
+lvalue_or_else (tree ref, enum lvalue_use use)
+{
+ int win = lvalue_p (ref);
+
+ if (!win)
+ lvalue_error (use);
+
+ return win;
}
\f
/* Mark EXP saying that we need to be able to take the
tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
- ifexp = lang_hooks.truthvalue_conversion (default_conversion (ifexp));
-
/* Promote both alternatives. */
if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE
|| code2 == COMPLEX_TYPE))
{
- result_type = common_type (type1, type2);
+ result_type = c_common_type (type1, type2);
/* If -Wsign-compare, warn here if type1 and type2 have
different signedness. We'll promote the signed to unsigned
|| (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
- warning ("signed and unsigned type in conditional expression");
+ warning (0, "signed and unsigned type in conditional expression");
}
}
}
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
- if (comp_target_types (type1, type2, 1))
+ if (comp_target_types (type1, type2))
result_type = common_pointer_type (type1, type2);
else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
&& TREE_CODE (orig_op1) != NOP_EXPR)
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
-
- return fold (build3 (COND_EXPR, result_type, ifexp, op1, op2));
+ return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
}
\f
/* Return a compound expression that performs two expressions and
tree
build_compound_expr (tree expr1, tree expr2)
{
- /* Convert arrays and functions to pointers. */
- expr2 = default_function_array_conversion (expr2);
-
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 (expr1) == CONVERT_EXPR
- && VOID_TYPE_P (TREE_TYPE (expr1))))
- warning ("left-hand operand of comma expression has no effect");
+ if (warn_unused_value)
+ {
+ if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == CONVERT_EXPR)
+ ; /* (void) a, b */
+ else if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR)
+ ; /* (void) a, (void) b, c */
+ else
+ warning (0, "left-hand operand of comma expression has no effect");
+ }
}
/* With -Wunused, we should also warn if the left-hand operand does have
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
- value = default_function_array_conversion (value);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
if (pedantic)
pedwarn ("ISO C forbids casts to union type");
t = digest_init (type,
- build_constructor (type,
- build_tree_list (field, value)),
+ build_constructor_single (type, field, value),
true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
TREE_INVARIANT (t) = TREE_INVARIANT (value);
{
tree otype, ovalue;
- /* If casting to void, avoid the error that would come
- from default_conversion in the case of a non-lvalue array. */
if (type == void_type_node)
return build1 (CONVERT_EXPR, type, value);
- /* Convert functions and arrays to pointers,
- but don't convert any other types. */
- value = default_function_array_conversion (value);
otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */
&& TREE_CODE (in_otype) == POINTER_TYPE);
if (added)
- warning ("cast adds new qualifiers to function type");
+ warning (0, "cast adds new qualifiers to function type");
if (discarded)
/* There are qualifiers present in IN_OTYPE that are not
present in IN_TYPE. */
- warning ("cast discards qualifiers from pointer target type");
+ warning (0, "cast discards qualifiers from pointer target type");
}
/* Warn about possible alignment problems. */
- if (STRICT_ALIGNMENT && warn_cast_align
+ if (STRICT_ALIGNMENT
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
|| TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
&& TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast increases required alignment of target type");
+ warning (OPT_Wcast_align,
+ "cast increases required alignment of target type");
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
&& !TREE_CONSTANT (value))
- warning ("cast from pointer to integer of different size");
+ warning (OPT_Wpointer_to_int_cast,
+ "cast from pointer to integer of different size");
- if (warn_bad_function_cast
- && TREE_CODE (value) == CALL_EXPR
+ if (TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning ("cast from function call of type %qT to non-matching "
- "type %qT", otype, type);
+ warning (OPT_Wbad_function_cast, "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
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
/* Don't warn about converting any constant. */
&& !TREE_CONSTANT (value))
- warning ("cast to pointer from integer of different size");
+ warning (OPT_Wint_to_pointer_cast, "cast to pointer from integer "
+ "of different size");
- if (TREE_CODE (type) == POINTER_TYPE
+ if (flag_strict_aliasing && warn_strict_aliasing
+ && TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (expr) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (expr, 0))
- && flag_strict_aliasing && warn_strict_aliasing
+ && (DECL_P (TREE_OPERAND (expr, 0))
+ || TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF)
&& !VOID_TYPE_P (TREE_TYPE (type)))
{
- /* Casting the address of a decl to non void pointer. Warn
+ /* Casting the address of an object to non void pointer. Warn
if the cast breaks type based aliasing. */
if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
- warning ("type-punning to incomplete type might break strict-aliasing rules");
+ warning (OPT_Wstrict_aliasing, "type-punning to incomplete type "
+ "might break strict-aliasing rules");
else
{
HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
if (!alias_sets_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+ warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+ "pointer will break strict-aliasing rules");
else if (warn_strict_aliasing > 1
&& !alias_sets_might_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+ warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+ "pointer might break strict-aliasing rules");
}
}
pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
ovalue = value;
- /* Replace a nonvolatile const static variable with its value. */
- if (optimize && TREE_CODE (value) == VAR_DECL)
- value = decl_constant_value (value);
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
{
- 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);
+ /* If OVALUE had overflow set, then so will VALUE, so it
+ is safe to overwrite. */
+ if (CONSTANT_CLASS_P (ovalue))
+ {
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ /* Similarly, constant_overflow cannot have become cleared. */
+ TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_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);
}
}
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ STRIP_TYPE_NOPS (rhs);
newrhs = rhs;
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
+ /* Emit ObjC write barrier, if necessary. */
+ if (c_dialect_objc () && flag_objc_gc)
+ {
+ result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+ if (result)
+ return result;
+ }
+
/* Scan operands. */
result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
tree rhstype;
enum tree_code coder;
tree rname = NULL_TREE;
+ bool objc_ok = false;
if (errtype == ic_argpass || errtype == ic_argpass_nonproto)
{
pedwarn (AR, parmnum, rname); \
break; \
case ic_argpass_nonproto: \
- warning (AR, parmnum, rname); \
+ warning (0, AR, parmnum, rname); \
break; \
case ic_assign: \
pedwarn (AS); \
} \
} while (0)
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
- rhs = TREE_OPERAND (rhs, 0);
+ STRIP_TYPE_NOPS (rhs);
- if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
- rhs = default_conversion (rhs);
- else if (optimize && TREE_CODE (rhs) == VAR_DECL)
+ if (optimize && TREE_CODE (rhs) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
rhs = decl_constant_value_for_broken_optimization (rhs);
rhstype = TREE_TYPE (rhs);
if (coder == ERROR_MARK)
return error_mark_node;
+ if (c_dialect_objc ())
+ {
+ int parmno;
+
+ switch (errtype)
+ {
+ case ic_return:
+ parmno = 0;
+ break;
+
+ case ic_assign:
+ parmno = -1;
+ break;
+
+ case ic_init:
+ parmno = -2;
+ break;
+
+ default:
+ parmno = parmnum;
+ break;
+ }
+
+ objc_ok = objc_compare_types (type, rhstype, parmno, rname);
+ }
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
overflow_warning (rhs);
- /* Check for Objective-C protocols. This will automatically
- issue a warning if there are protocol violations. No need to
- use the return value. */
- if (c_dialect_objc ())
- objc_comptypes (type, rhstype, 0);
return rhs;
}
Meanwhile, the lhs target must have all the qualifiers of
the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (memb_type, rhstype, 0))
+ || comp_target_types (memb_type, rhstype))
{
/* If this type won't generate any warnings, use it. */
if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
function where an ordinary one is wanted, but not
vice-versa. */
if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE "
"makes qualified function "
"pointer from unqualified"),
- N_("assignment makes qualified "
+ G_("assignment makes qualified "
"function pointer from "
"unqualified"),
- N_("initialization makes qualified "
+ G_("initialization makes qualified "
"function pointer from "
"unqualified"),
- N_("return makes qualified function "
+ G_("return makes qualified function "
"pointer from unqualified"));
}
else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
- N_("assignment discards qualifiers "
+ G_("assignment discards qualifiers "
"from pointer target type"),
- N_("initialization discards qualifiers "
+ G_("initialization discards qualifiers "
"from pointer target type"),
- N_("return discards qualifiers from "
+ G_("return discards qualifiers from "
"pointer target type"));
}
{
tree ttl = TREE_TYPE (type);
tree ttr = TREE_TYPE (rhstype);
+ tree mvl = ttl;
+ tree mvr = ttr;
bool is_opaque_pointer;
int target_cmp = 0; /* Cache comp_target_types () result. */
+ if (TREE_CODE (mvl) != ARRAY_TYPE)
+ mvl = TYPE_MAIN_VARIANT (mvl);
+ if (TREE_CODE (mvr) != ARRAY_TYPE)
+ mvr = TYPE_MAIN_VARIANT (mvr);
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = (targetm.vector_opaque_p (type)
|| targetm.vector_opaque_p (rhstype))
&& TREE_CODE (ttl) == VECTOR_TYPE
&& TREE_CODE (ttr) == VECTOR_TYPE;
+
+ /* C++ does not allow the implicit conversion void* -> T*. However,
+ for the purpose of reducing the number of false positives, we
+ tolerate the special case of
+ int *p = NULL;
+
+ where NULL is typically defined in C to be '(void *) 0'. */
+ if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl))
+ warning (OPT_Wc___compat, "request for implicit conversion from "
+ "%qT to %qT not permitted in C++", rhstype, type);
+
+ /* Check if the right-hand side has a format attribute but the
+ left-hand side doesn't. */
+ if (warn_missing_format_attribute)
+ {
+ tree rattrs = TYPE_ATTRIBUTES (ttr), ra;
+ for (ra = rattrs; ra; ra = TREE_CHAIN (ra))
+ {
+ if (is_attribute_p ("format", TREE_PURPOSE (ra)))
+ break;
+ }
+ if (ra)
+ {
+ tree lattrs = TYPE_ATTRIBUTES (ttl), la;
+ for (la = lattrs; la; la = TREE_CHAIN (la))
+ {
+ if (is_attribute_p ("format", TREE_PURPOSE (la)))
+ break;
+ }
+ if (!la)
+ switch (errtype)
+ {
+ case ic_argpass:
+ case ic_argpass_nonproto:
+ warning (OPT_Wmissing_format_attribute,
+ "argument %d of %qE might be "
+ "a candidate for a format attribute",
+ parmnum, rname);
+ break;
+ case ic_assign:
+ warning (OPT_Wmissing_format_attribute,
+ "assignment left-hand side might be "
+ "a candidate for a format attribute");
+ break;
+ case ic_init:
+ warning (OPT_Wmissing_format_attribute,
+ "initialization left-hand side might be "
+ "a candidate for a format attribute");
+ break;
+ case ic_return:
+ warning (OPT_Wmissing_format_attribute,
+ "return type might be "
+ "a candidate for a format attribute");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ }
+
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || (target_cmp = comp_target_types (type, rhstype, 0))
+ || (target_cmp = comp_target_types (type, rhstype))
|| is_opaque_pointer
- || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
- == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+ || (c_common_unsigned_type (mvl)
+ == c_common_unsigned_type (mvr)))
{
if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
which are not ANSI null ptr constants. */
&& (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- WARN_FOR_ASSIGNMENT (N_("ISO C forbids passing argument %d of "
+ WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
"%qE between function pointer "
"and %<void *%>"),
- N_("ISO C forbids assignment between "
+ G_("ISO C forbids assignment between "
"function pointer and %<void *%>"),
- N_("ISO C forbids initialization between "
+ G_("ISO C forbids initialization between "
"function pointer and %<void *%>"),
- N_("ISO C forbids return between function "
+ G_("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. */
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- 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"));
+ {
+ /* Types differing only by the presence of the 'volatile'
+ qualifier are acceptable if the 'volatile' has been added
+ in by the Objective-C EH machinery. */
+ if (!objc_type_quals_match (ttl, ttr))
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
+ "qualifiers from pointer target type"),
+ G_("assignment discards qualifiers "
+ "from pointer target type"),
+ G_("initialization discards qualifiers "
+ "from pointer target type"),
+ G_("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
- WARN_FOR_ASSIGNMENT (N_("pointer targets in passing argument "
+ else if (warn_pointer_sign)
+ WARN_FOR_ASSIGNMENT (G_("pointer targets in passing argument "
"%d of %qE differ in signedness"),
- N_("pointer targets in assignment "
+ G_("pointer targets in assignment "
"differ in signedness"),
- N_("pointer targets in initialization "
+ G_("pointer targets in initialization "
"differ in signedness"),
- N_("pointer targets in return differ "
+ G_("pointer targets in return differ "
"in signedness"));
}
else if (TREE_CODE (ttl) == 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 (N_("passing argument %d of %qE makes "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
"qualified function pointer "
"from unqualified"),
- N_("assignment makes qualified function "
+ G_("assignment makes qualified function "
"pointer from unqualified"),
- N_("initialization makes qualified "
+ G_("initialization makes qualified "
"function pointer from unqualified"),
- N_("return makes qualified function "
+ G_("return makes qualified function "
"pointer from unqualified"));
}
}
else
- 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"));
+ /* Avoid warning about the volatile ObjC EH puts on decls. */
+ if (!objc_ok)
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE from "
+ "incompatible pointer type"),
+ G_("assignment from incompatible pointer type"),
+ G_("initialization from incompatible "
+ "pointer type"),
+ G_("return from incompatible pointer type"));
+
return convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
&& 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 "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
"pointer from integer without a cast"),
- N_("assignment makes pointer from integer "
+ G_("assignment makes pointer from integer "
"without a cast"),
- N_("initialization makes pointer from "
+ G_("initialization makes pointer from "
"integer without a cast"),
- N_("return makes pointer from integer "
+ G_("return makes pointer from integer "
"without a cast"));
return convert (type, rhs);
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes integer "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes integer "
"from pointer without a cast"),
- N_("assignment makes integer from pointer "
+ G_("assignment makes integer from pointer "
"without a cast"),
- N_("initialization makes integer from pointer "
+ G_("initialization makes integer from pointer "
"without a cast"),
- N_("return makes integer from pointer "
+ G_("return makes integer from pointer "
"without a cast"));
return convert (type, rhs);
}
/* Store the expression if valid; else report error. */
- if (warn_traditional && !in_system_header
+ if (!in_system_header
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
- warning ("traditional C rejects automatic aggregate initialization");
+ warning (OPT_Wtraditional, "traditional C rejects automatic "
+ "aggregate initialization");
DECL_INITIAL (decl) = value;
{
tree inside_init = init;
- if (TREE_CODE (init) == NON_LVALUE_EXPR)
- inside_init = TREE_OPERAND (init, 0);
+ STRIP_TYPE_NOPS (inside_init);
inside_init = fold (inside_init);
if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
char *ofwhat;
- warning ("%s", _(msgid));
+ warning (0, "%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning ("(near initialization for %qs)", ofwhat);
+ warning (0, "(near initialization for %qs)", ofwhat);
}
\f
/* If TYPE is an array type and EXPR is a parenthesized string
|| TREE_TYPE (init) == error_mark_node)
return error_mark_node;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- /* Do not use STRIP_NOPS here. We do not want an enumerator
- whose value is 0 to count as a null pointer constant. */
- if (TREE_CODE (init) == NON_LVALUE_EXPR)
- inside_init = TREE_OPERAND (init, 0);
+ STRIP_TYPE_NOPS (inside_init);
inside_init = fold (inside_init);
/* Build a VECTOR_CST from a *constant* vector constructor. If the
vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
below and handle as a constructor. */
- if (code == VECTOR_TYPE
- && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
- && vector_types_convertible_p (TREE_TYPE (inside_init), type)
- && TREE_CONSTANT (inside_init))
- {
- if (TREE_CODE (inside_init) == VECTOR_CST
- && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
- TYPE_MAIN_VARIANT (type)))
- return inside_init;
- else
- return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
- }
+ if (code == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
+ && vector_types_convertible_p (TREE_TYPE (inside_init), type)
+ && TREE_CONSTANT (inside_init))
+ {
+ if (TREE_CODE (inside_init) == VECTOR_CST
+ && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+ TYPE_MAIN_VARIANT (type)))
+ return inside_init;
+
+ if (TREE_CODE (inside_init) == CONSTRUCTOR)
+ {
+ unsigned HOST_WIDE_INT ix;
+ tree value;
+ bool constant_p = true;
+
+ /* Iterate through elements and check if all constructor
+ elements are *_CSTs. */
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value)
+ if (!CONSTANT_CLASS_P (value))
+ {
+ constant_p = false;
+ break;
+ }
+
+ if (constant_p)
+ return build_vector_from_ctor (type,
+ CONSTRUCTOR_ELTS (inside_init));
+ }
+ }
/* Any type can be initialized
from an expression of the same type, optionally with braces. */
|| (code == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
- TREE_TYPE (type)))
- || (code == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE
- && comptypes (TREE_TYPE (inside_init),
TREE_TYPE (type)))))
{
if (code == POINTER_TYPE)
{
- inside_init = default_function_array_conversion (inside_init);
-
if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE)
{
- error_init ("invalid use of non-lvalue array");
- return error_mark_node;
+ if (TREE_CODE (inside_init) == STRING_CST
+ || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+ inside_init = array_to_pointer_conversion (inside_init);
+ else
+ {
+ error_init ("invalid use of non-lvalue array");
+ return error_mark_node;
+ }
}
- }
+ }
if (code == VECTOR_TYPE)
/* Although the types are compatible, we may require a
inside_init = error_mark_node;
}
+ /* Added to enable additional -Wmissing-format-attribute warnings. */
+ if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
+ inside_init = convert_for_assignment (type, inside_init, ic_init, NULL_TREE,
+ NULL_TREE, 0);
return inside_init;
}
|| code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
|| code == VECTOR_TYPE)
{
- /* Note that convert_for_assignment calls default_conversion
- for arrays and functions. We must not call it in the
- case where inside_init is a null pointer constant. */
+ if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
+ && (TREE_CODE (init) == STRING_CST
+ || TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
+ init = array_to_pointer_conversion (init);
inside_init
= convert_for_assignment (type, init, ic_init,
NULL_TREE, NULL_TREE, 0);
/* If we are saving up the elements rather than allocating them,
this is the list of elements so far (in reverse order,
most recent first). */
-static tree constructor_elements;
+static VEC(constructor_elt,gc) *constructor_elements;
/* 1 if constructor should be incrementally stored into a constructor chain,
0 if all the elements should be kept in AVL tree. */
/* The SPELLING_DEPTH of this constructor. */
static int constructor_depth;
-/* 0 if implicitly pushing constructor levels is allowed. */
-int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */
-
/* DECL node for which an initializer is being read.
0 means we are reading a constructor expression
such as (struct foo) {...}. */
tree unfilled_index;
tree unfilled_fields;
tree bit_index;
- tree elements;
+ VEC(constructor_elt,gc) *elements;
struct init_node *pending_elts;
int offset;
int depth;
char designated;
};
-struct constructor_stack *constructor_stack;
+static struct constructor_stack *constructor_stack;
/* This stack represents designators from some range designator up to
the last designator in the list. */
tree fields;
};
-struct constructor_range_stack *constructor_range_stack;
+static struct constructor_range_stack *constructor_range_stack;
/* This stack records separate initializers that are nested.
Nested initializers can't happen in ANSI C, but GNU C allows them
tree decl;
struct constructor_stack *constructor_stack;
struct constructor_range_stack *constructor_range_stack;
- tree elements;
+ VEC(constructor_elt,gc) *elements;
struct spelling *spelling;
struct spelling *spelling_base;
int spelling_size;
char require_constant_elements;
};
-struct initializer_stack *initializer_stack;
+static struct initializer_stack *initializer_stack;
\f
/* Prepare to parse and output the initializer for variable DECL. */
constructor_designated = 0;
constructor_top_level = top_level;
- if (decl != 0)
+ if (decl != 0 && decl != error_mark_node)
{
require_constant_value = TREE_STATIC (decl);
require_constant_elements
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
}
else
- constructor_index = bitsize_zero_node;
+ {
+ constructor_index = bitsize_zero_node;
+ constructor_max_index = NULL_TREE;
+ }
constructor_unfilled_index = constructor_index;
}
tree value = NULL_TREE;
/* If we've exhausted any levels that didn't have braces,
- pop them now. */
- while (constructor_stack->implicit)
+ pop them now. If implicit == 1, this will have been done in
+ process_init_element; do not repeat it here because in the case
+ of excess initializers for an empty aggregate this leads to an
+ infinite cycle of popping a level and immediately recreating
+ it. */
+ if (implicit != 1)
{
- if ((TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
- && constructor_fields == 0)
- process_init_element (pop_init_level (1));
- else if (TREE_CODE (constructor_type) == ARRAY_TYPE
- && constructor_max_index
- && tree_int_cst_lt (constructor_max_index, constructor_index))
- process_init_element (pop_init_level (1));
- else
- break;
+ while (constructor_stack->implicit)
+ {
+ if ((TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == UNION_TYPE)
+ && constructor_fields == 0)
+ process_init_element (pop_init_level (1));
+ else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+ && constructor_max_index
+ && tree_int_cst_lt (constructor_max_index,
+ constructor_index))
+ process_init_element (pop_init_level (1));
+ else
+ break;
+ }
}
/* Unless this is an explicit brace, we need to preserve previous
constructor_constant = TREE_CONSTANT (value);
constructor_simple = TREE_STATIC (value);
constructor_elements = CONSTRUCTOR_ELTS (value);
- if (constructor_elements
+ if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == ARRAY_TYPE))
set_nonincremental_init ();
}
else
{
- warning_init ("braces around scalar initializer");
+ if (constructor_type != error_mark_node)
+ warning_init ("braces around scalar initializer");
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
}
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
- Discard the initializer so that we do not abort later. */
+ Discard the initializer so that we do not die later. */
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
{
/* A nonincremental scalar initializer--just return
the element, after verifying there is just one. */
- if (constructor_elements == 0)
+ if (VEC_empty (constructor_elt,constructor_elements))
{
if (!constructor_erroneous)
error_init ("empty scalar initializer");
ret.value = error_mark_node;
}
- else if (TREE_CHAIN (constructor_elements) != 0)
+ else if (VEC_length (constructor_elt,constructor_elements) != 1)
{
error_init ("extra elements in scalar initializer");
- ret.value = TREE_VALUE (constructor_elements);
+ ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
}
else
- ret.value = TREE_VALUE (constructor_elements);
+ ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
}
else
{
else
{
ret.value = build_constructor (constructor_type,
- nreverse (constructor_elements));
+ constructor_elements);
if (constructor_constant)
TREE_CONSTANT (ret.value) = TREE_INVARIANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
return 0;
}
- if (constructor_no_implicit)
- {
- error_init ("initialization designators may not nest");
- return 1;
- }
-
switch (TREE_CODE (constructor_type))
{
case RECORD_TYPE:
return;
}
- while ((TREE_CODE (first) == NOP_EXPR
- || TREE_CODE (first) == CONVERT_EXPR
- || TREE_CODE (first) == NON_LVALUE_EXPR)
- && (TYPE_MODE (TREE_TYPE (first))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
- first = TREE_OPERAND (first, 0);
-
- if (last)
- while ((TREE_CODE (last) == NOP_EXPR
- || TREE_CODE (last) == CONVERT_EXPR
- || TREE_CODE (last) == NON_LVALUE_EXPR)
- && (TYPE_MODE (TREE_TYPE (last))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
- last = TREE_OPERAND (last, 0);
-
if (TREE_CODE (first) != INTEGER_CST)
error_init ("nonconstant array index in initializer");
else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
}
if (tail == 0)
- error ("unknown field %qs specified in initializer",
- IDENTIFIER_POINTER (fieldname));
+ error ("unknown field %qE specified in initializer", fieldname);
else
{
constructor_fields = tail;
static void
set_nonincremental_init (void)
{
- tree chain;
+ unsigned HOST_WIDE_INT ix;
+ tree index, value;
if (TREE_CODE (constructor_type) != RECORD_TYPE
&& TREE_CODE (constructor_type) != ARRAY_TYPE)
return;
- for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
- add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+ FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
+ add_pending_init (index, value);
constructor_elements = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
}
else if (TREE_CODE (constructor_type) == UNION_TYPE)
{
- if (constructor_elements
- && TREE_PURPOSE (constructor_elements) == field)
- return TREE_VALUE (constructor_elements);
+ if (!VEC_empty (constructor_elt, constructor_elements)
+ && (VEC_last (constructor_elt, constructor_elements)->index
+ == field))
+ return VEC_last (constructor_elt, constructor_elements)->value;
}
return 0;
}
output_init_element (tree value, bool strict_string, tree type, tree field,
int pending)
{
+ constructor_elt *celt;
+
if (type == error_mark_node || value == error_mark_node)
{
constructor_erroneous = 1;
return;
}
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- && !(TREE_CODE (value) == STRING_CST
- && TREE_CODE (type) == ARRAY_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (type)))
- && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
- TYPE_MAIN_VARIANT (type))))
- value = default_conversion (value);
+ if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+ && (TREE_CODE (value) == STRING_CST
+ || TREE_CODE (value) == COMPOUND_LITERAL_EXPR)
+ && !(TREE_CODE (value) == STRING_CST
+ && TREE_CODE (type) == ARRAY_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+ && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
+ TYPE_MAIN_VARIANT (type)))
+ value = array_to_pointer_conversion (value);
if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
&& require_constant_value && !flag_isoc99 && pending)
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
- && constructor_elements)
+ && !VEC_empty (constructor_elt, constructor_elements))
{
- if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+ if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
+ constructor_elements)->value))
warning_init ("initialized field with side-effects overwritten");
/* We can have just one union field set. */
/* Otherwise, output this element either to
constructor_elements or to the assembler file. */
- if (field && TREE_CODE (field) == INTEGER_CST)
- field = copy_node (field);
- constructor_elements
- = tree_cons (field, value, constructor_elements);
+ celt = VEC_safe_push (constructor_elt, gc, constructor_elements, NULL);
+ celt->index = field;
+ celt->value = value;
/* Advance the variable that indicates sequential elements output. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
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.value != 0 && !constructor_no_implicit
+ else if (value.value != 0
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
again on the assumption that this must be conditional on
__STDC__ anyway (and we've already complained about the
member-designator already). */
- if (warn_traditional && !in_system_header && !constructor_designated
+ if (!in_system_header && !constructor_designated
&& !(value.value && (integer_zerop (value.value)
|| real_zerop (value.value))))
- warning ("traditional C rejects initialization of unions");
+ warning (OPT_Wtraditional, "traditional C rejects initialization "
+ "of unions");
/* Accept a string constant to initialize a subarray. */
if (value.value != 0
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.value != 0 && !constructor_no_implicit
+ else if (value.value != 0
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
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.value != 0 && !constructor_no_implicit
+ else if (value.value != 0
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
/* Handle the sole element allowed in a braced initializer
for a scalar variable. */
- else if (constructor_fields == 0)
+ else if (constructor_type != error_mark_node
+ && constructor_fields == 0)
{
pedwarn_init ("excess elements in scalar initializer");
break;
tree args;
int i;
const char *constraint;
+ const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
- int ninputs;
- int noutputs;
+ int ninputs, noutputs;
ninputs = list_length (inputs);
noutputs = list_length (outputs);
+ oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
+
+ string = resolve_asm_operand_names (string, outputs, inputs);
/* Remove output conversions that change the type but not the mode. */
for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
{
tree output = TREE_VALUE (tail);
+
+ /* ??? Really, this should not be here. Users should be using a
+ proper lvalue, dammit. But there's a long history of using casts
+ in the output operands. In cases like longlong.h, this becomes a
+ primitive form of typechecking -- if the cast can be removed, then
+ the output operand had a type of the proper width; otherwise we'll
+ get an error. Gross, but ... */
STRIP_NOPS (output);
- TREE_VALUE (tail) = output;
- lvalue_or_else (output, lv_asm);
+
+ if (!lvalue_or_else (output, lv_asm))
+ output = error_mark_node;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+ oconstraints[i] = constraint;
- if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
- {
- /* By marking this operand as erroneous, we will not try
- to process this operand again in expand_asm_operands. */
- TREE_VALUE (tail) = error_mark_node;
- continue;
- }
+ if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+ &allows_mem, &allows_reg, &is_inout))
+ {
+ /* If the operand is going to end up in memory,
+ mark it addressable. */
+ if (!allows_reg && !c_mark_addressable (output))
+ output = error_mark_node;
+ }
+ else
+ output = error_mark_node;
- /* If the operand is a DECL that is going to end up in
- memory, assume it is addressable. This is a bit more
- conservative than it would ideally be; the exact test is
- buried deep in expand_asm_operands and depends on the
- DECL_RTL for the OPERAND -- which we don't have at this
- point. */
- if (!allows_reg && DECL_P (output))
- c_mark_addressable (output);
+ TREE_VALUE (tail) = output;
}
- /* Perform default conversions on array and function inputs.
- Don't do this for other types as it would screw up operands
- expected to be in memory. */
- for (tail = inputs; tail; tail = TREE_CHAIN (tail))
- TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
+ for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
+ {
+ tree input;
+
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+ input = TREE_VALUE (tail);
+
+ if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg))
+ {
+ /* If the operand is going to end up in memory,
+ mark it addressable. */
+ if (!allows_reg && allows_mem)
+ {
+ /* Strip the nops as we allow this case. FIXME, this really
+ should be rejected or made deprecated. */
+ STRIP_NOPS (input);
+ if (!c_mark_addressable (input))
+ input = error_mark_node;
+ }
+ }
+ else
+ input = error_mark_node;
+
+ TREE_VALUE (tail) = input;
+ }
args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
ASM_VOLATILE_P (args) = 1;
ASM_INPUT_P (args) = 1;
}
+
return args;
}
\f
if (!decl)
return NULL_TREE;
+ if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
+ {
+ error ("jump into statement expression");
+ return NULL_TREE;
+ }
+
+ if (C_DECL_UNJUMPABLE_VM (decl))
+ {
+ error ("jump into scope of identifier with variably modified type");
+ return NULL_TREE;
+ }
+
+ if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
+ {
+ /* No jump from outside this statement expression context, so
+ record that there is a jump from within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack_se->labels_used;
+ nlist->label = decl;
+ label_context_stack_se->labels_used = nlist;
+ }
+
+ if (!C_DECL_UNDEFINABLE_VM (decl))
+ {
+ /* No jump from outside this context context of identifiers with
+ variably modified type, so record that there is a jump from
+ within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack_vm->labels_used;
+ nlist->label = decl;
+ label_context_stack_vm->labels_used = nlist;
+ }
+
TREE_USED (decl) = 1;
return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
}
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared %<noreturn%> has a %<return%> statement");
+ warning (0, "function declared %<noreturn%> has a %<return%> statement");
if (!retval)
{
&& !DECL_EXTERNAL (inner)
&& !TREE_STATIC (inner)
&& DECL_CONTEXT (inner) == current_function_decl)
- warning ("function returns address of local variable");
+ warning (0, "function returns address of local variable");
break;
default:
}
\f
struct c_switch {
- /* The SWITCH_STMT being built. */
- tree switch_stmt;
+ /* The SWITCH_EXPR being built. */
+ tree switch_expr;
/* The original type of the testing expression, i.e. before the
default conversion is applied. */
of the GNU case range extension. */
splay_tree cases;
+ /* Number of nested statement expressions within this switch
+ statement; if nonzero, case and default labels may not
+ appear. */
+ unsigned int blocked_stmt_expr;
+
+ /* Scope of outermost declarations of identifiers with variably
+ modified type within this switch statement; if nonzero, case and
+ default labels may not appear. */
+ unsigned int blocked_vm;
+
/* The next node on the stack. */
struct c_switch *next;
};
struct c_switch *c_switch_stack;
/* Start a C switch statement, testing expression EXP. Return the new
- SWITCH_STMT. */
+ SWITCH_EXPR. */
tree
c_start_case (tree exp)
{
error ("switch quantity not an integer");
exp = integer_zero_node;
+ orig_type = error_mark_node;
}
else
{
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
- if (warn_traditional && !in_system_header
+ if (!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 (OPT_Wtraditional, "%<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. */
+ /* Add this new SWITCH_EXPR to the stack. */
cs = XNEW (struct c_switch);
- cs->switch_stmt = build_stmt ((enum tree_code) SWITCH_STMT, exp, NULL_TREE,
- orig_type);
+ cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
+ cs->blocked_stmt_expr = 0;
+ cs->blocked_vm = 0;
cs->next = c_switch_stack;
c_switch_stack = cs;
- return add_stmt (cs->switch_stmt);
+ return add_stmt (cs->switch_expr);
}
/* Process a case label. */
{
tree label = NULL_TREE;
- if (c_switch_stack)
+ if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
+ && !c_switch_stack->blocked_vm)
{
label = c_add_case_label (c_switch_stack->cases,
- SWITCH_COND (c_switch_stack->switch_stmt),
+ SWITCH_COND (c_switch_stack->switch_expr),
c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
}
+ else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
+ {
+ if (low_value)
+ error ("case label in statement expression not containing "
+ "enclosing switch statement");
+ else
+ error ("%<default%> label in statement expression not containing "
+ "enclosing switch statement");
+ }
+ else if (c_switch_stack && c_switch_stack->blocked_vm)
+ {
+ if (low_value)
+ error ("case label in scope of identifier with variably modified "
+ "type not containing enclosing switch statement");
+ else
+ error ("%<default%> label in scope of identifier with variably "
+ "modified type not containing enclosing switch statement");
+ }
else if (low_value)
error ("case label not within a switch statement");
else
c_finish_case (tree body)
{
struct c_switch *cs = c_switch_stack;
+ location_t switch_location;
+
+ SWITCH_BODY (cs->switch_expr) = body;
- SWITCH_BODY (cs->switch_stmt) = body;
+ /* We must not be within a statement expression nested in the switch
+ at this point; we might, however, be within the scope of an
+ identifier with variably modified type nested in the switch. */
+ gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
- c_do_switch_warnings (cs->cases, cs->switch_stmt);
+ if (EXPR_HAS_LOCATION (cs->switch_expr))
+ switch_location = EXPR_LOCATION (cs->switch_expr);
+ else
+ switch_location = input_location;
+ c_do_switch_warnings (cs->cases, switch_location,
+ TREE_TYPE (cs->switch_expr),
+ SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
c_switch_stack = cs->next;
found:
if (COND_EXPR_ELSE (inner_if))
- warning ("%Hsuggest explicit braces to avoid ambiguous %<else%>",
+ warning (0, "%Hsuggest explicit braces to avoid ambiguous %<else%>",
&if_locus);
}
if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
{
if (!else_block)
- warning ("%Hempty body in an if-statement",
+ warning (0, "%Hempty body in an if-statement",
EXPR_LOCUS (then_block));
then_block = alloc_stmt_list ();
}
&& TREE_CODE (else_block) == NOP_EXPR
&& !TREE_TYPE (else_block))
{
- warning ("%Hempty body in an else-statement",
+ warning (0, "%Hempty body in an else-statement",
EXPR_LOCUS (else_block));
else_block = alloc_stmt_list ();
}
}
- stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+ stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
SET_EXPR_LOCATION (stmt, if_locus);
add_stmt (stmt);
}
{
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)
+ /* If the condition is zero don't generate a loop construct. */
+ if (cond && integer_zerop (cond))
+ {
+ if (cond_is_first)
+ {
+ t = build_and_jump (&blab);
+ SET_EXPR_LOCATION (t, start_locus);
+ add_stmt (t);
+ }
+ }
+ else
{
tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
then we just build a jump back to the top. */
exit = build_and_jump (&LABEL_EXPR_LABEL (top));
- if (cond)
+ if (cond && !integer_nonzerop (cond))
{
/* Canonicalize the loop condition to the end. This means
generating a branch to the loop condition. Reuse the
tree
c_finish_bc_stmt (tree *label_p, bool is_break)
{
+ bool skip;
tree label = *label_p;
+ /* In switch statements break is sometimes stylistically used after
+ a return statement. This can lead to spurious warnings about
+ control reaching the end of a non-void function when it is
+ inlined. Note that we are calling block_may_fallthru with
+ language specific tree nodes; this works because
+ block_may_fallthru returns true when given something it does not
+ understand. */
+ skip = !block_may_fallthru (cur_stmt_list);
+
if (!label)
- *label_p = label = create_artificial_label ();
+ {
+ if (!skip)
+ *label_p = label = create_artificial_label ();
+ }
else if (TREE_CODE (label) != LABEL_DECL)
{
if (is_break)
return NULL_TREE;
}
+ if (skip)
+ return NULL_TREE;
+
return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
}
else if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
- warning ("%Hstatement with no effect",
+ warning (0, "%Hstatement with no effect",
EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
}
else if (warn_unused_value)
if (!expr)
return NULL_TREE;
- /* Do default conversion if safe and possibly important,
- in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
- && (flag_isoc99 || lvalue_p (expr)))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
- expr = default_conversion (expr);
-
if (warn_sequence_point)
verify_sequence_points (expr);
c_begin_stmt_expr (void)
{
tree ret;
+ struct c_label_context_se *nstack;
+ struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
later, there is a way to turn off the entire subtree of blocks that
are contained in it. */
keep_next_level ();
ret = c_begin_compound_stmt (true);
+ if (c_switch_stack)
+ {
+ c_switch_stack->blocked_stmt_expr++;
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ }
+ for (glist = label_context_stack_se->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->next = label_context_stack_se;
+ label_context_stack_se = nstack;
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
{
tree last, type, tmp, val;
tree *last_p;
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
body = c_end_compound_stmt (body, true);
+ if (c_switch_stack)
+ {
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ c_switch_stack->blocked_stmt_expr--;
+ }
+ /* It is no longer possible to jump to labels defined within this
+ statement expression. */
+ for (dlist = label_context_stack_se->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this statement expression. */
+ for (glist = label_context_stack_se->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_se->labels_used;
+ else
+ label_context_stack_se->next->labels_used
+ = label_context_stack_se->labels_used;
+ label_context_stack_se = label_context_stack_se->next;
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
+
+/* Begin the scope of an identifier of variably modified type, scope
+ number SCOPE. Jumping from outside this scope to inside it is not
+ permitted. */
+
+void
+c_begin_vm_scope (unsigned int scope)
+{
+ struct c_label_context_vm *nstack;
+ struct c_label_list *glist;
+
+ gcc_assert (scope > 0);
+ if (c_switch_stack && !c_switch_stack->blocked_vm)
+ c_switch_stack->blocked_vm = scope;
+ for (glist = label_context_stack_vm->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->scope = scope;
+ nstack->next = label_context_stack_vm;
+ label_context_stack_vm = nstack;
+}
+
+/* End a scope which may contain identifiers of variably modified
+ type, scope number SCOPE. */
+
+void
+c_end_vm_scope (unsigned int scope)
+{
+ if (label_context_stack_vm == NULL)
+ return;
+ if (c_switch_stack && c_switch_stack->blocked_vm == scope)
+ c_switch_stack->blocked_vm = 0;
+ /* We may have a number of nested scopes of identifiers with
+ variably modified type, all at this depth. Pop each in turn. */
+ while (label_context_stack_vm->scope == scope)
+ {
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
+
+ /* It is no longer possible to jump to labels defined within this
+ scope. */
+ for (dlist = label_context_stack_vm->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this scope. */
+ for (glist = label_context_stack_vm->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_vm->labels_used;
+ else
+ label_context_stack_vm->next->labels_used
+ = label_context_stack_vm->labels_used;
+ label_context_stack_vm = label_context_stack_vm->next;
+ }
+}
\f
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */
tree type0, type1;
enum tree_code code0, code1;
tree op0, op1;
+ const char *invalid_op_diag;
/* Expression code to give to the expression when it is built.
Normally this is CODE, which is what the caller asked for,
/* Nonzero means set RESULT_TYPE to the common type of the args. */
int common = 0;
+ /* True means types are compatible as far as ObjC is concerned. */
+ bool objc_ok;
+
if (convert_p)
{
op0 = default_conversion (orig_op0);
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
+ if ((invalid_op_diag
+ = targetm.invalid_binary_op (code, type0, type1)))
+ {
+ error (invalid_op_diag);
+ return error_mark_node;
+ }
+
+ objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+
switch (code)
{
case PLUS_EXPR:
/* Subtraction of two similar pointers.
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
- && comp_target_types (type0, type1, 1))
+ && comp_target_types (type0, type1))
return pointer_diff (op0, op1);
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
case EXACT_DIV_EXPR:
/* Floating point division by zero is a legitimate way to obtain
infinities and NaNs. */
- if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ if (skip_evaluation == 0 && integer_zerop (op1))
+ warning (OPT_Wdiv_by_zero, "division by zero");
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
+ enum tree_code tcode0 = code0, tcode1 = code1;
+
if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
- code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+ tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
- code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+ tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
- if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+ if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
/* Although it would be tempting to shorten always here, that
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
- if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ if (skip_evaluation == 0 && integer_zerop (op1))
+ warning (OPT_Wdiv_by_zero, "division by zero");
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
but that does not mean the operands should be
converted to ints! */
result_type = integer_type_node;
- op0 = lang_hooks.truthvalue_conversion (op0);
- op1 = lang_hooks.truthvalue_conversion (op1);
+ op0 = c_common_truthvalue_conversion (op0);
+ op1 = c_common_truthvalue_conversion (op1);
converted = 1;
}
break;
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("right shift count is negative");
+ warning (0, "right shift count is negative");
else
{
if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("right shift count >= width of type");
+ warning (0, "right shift count >= width of type");
}
}
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("left shift count is negative");
+ warning (0, "left shift count is negative");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("left shift count >= width of type");
+ warning (0, "left shift count >= width of type");
}
/* Use the type of the value to be shifted. */
case EQ_EXPR:
case NE_EXPR:
- if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
- warning ("comparing floating point with == or != is unsafe");
+ if (code0 == REAL_TYPE || code1 == REAL_TYPE)
+ warning (OPT_Wfloat_equal,
+ "comparing floating point with == or != is unsafe");
/* Result of comparison is always int,
but don't convert the args to int! */
build_type = integer_type_node;
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
- if (comp_target_types (type0, type1, 1))
+ if (comp_target_types (type0, type1))
result_type = common_pointer_type (type0, type1);
else if (VOID_TYPE_P (tt0))
{
" with function pointer");
}
else
- pedwarn ("comparison of distinct pointer types lacks a cast");
+ /* Avoid warning about the volatile ObjC EH puts on decls. */
+ if (!objc_ok)
+ pedwarn ("comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
result_type = ptr_type_node;
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1, 1))
+ if (comp_target_types (type0, type1))
{
result_type = common_pointer_type (type0, type1);
if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
+ || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
+ TREE_TYPE (type1))))
+ {
+ binary_op_error (code);
+ return error_mark_node;
+ }
+
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
|| code0 == VECTOR_TYPE)
&&
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
if (shorten || common || short_compare)
- result_type = common_type (type0, type1);
+ result_type = c_common_type (type0, type1);
/* For certain operations (which identify themselves by shorten != 0)
if both args were extended from the same smaller type,
&& (unsigned0 || !uns))
result_type
= c_common_signed_or_unsigned_type
- (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ (unsigned0, c_common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
c_common_signed_type (result_type)))
/* OK */;
else
- warning ("comparison between signed and unsigned");
+ warning (0, "comparison between signed and unsigned");
}
/* Warn if two unsigned values are being compared in a size
{
mask = (~(HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
- warning ("comparison of promoted ~unsigned with constant");
+ warning (0, "comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
< TYPE_PRECISION (result_type)))
- warning ("comparison of promoted ~unsigned with unsigned");
+ warning (0, "comparison of promoted ~unsigned with unsigned");
}
}
}
return result;
}
}
+
+
+/* Convert EXPR to be a truth-value, validating its type for this
+ purpose. */
+
+tree
+c_objc_common_truthvalue_conversion (tree expr)
+{
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case ARRAY_TYPE:
+ error ("used array that cannot be converted to pointer where scalar is required");
+ return error_mark_node;
+
+ case RECORD_TYPE:
+ error ("used struct type value where scalar is required");
+ return error_mark_node;
+
+ case UNION_TYPE:
+ error ("used union type value where scalar is required");
+ return error_mark_node;
+
+ case FUNCTION_TYPE:
+ gcc_unreachable ();
+
+ default:
+ break;
+ }
+
+ /* ??? Should we also give an error for void and vectors rather than
+ leaving those to give errors later? */
+ return c_common_truthvalue_conversion (expr);
+}
+\f
+
+/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as
+ required. */
+
+tree
+c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED,
+ bool *ti ATTRIBUTE_UNUSED, bool *se)
+{
+ if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR)
+ {
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (expr);
+ /* Executing a compound literal inside a function reinitializes
+ it. */
+ if (!TREE_STATIC (decl))
+ *se = true;
+ return decl;
+ }
+ else
+ return expr;
+}