/* Build expressions with type checking for C compiler.
- Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file is part of the C front end.
#include "tree.h"
#include "c-tree.h"
#include "flags.h"
+#include "output.h"
-/* Nonzero if we've already printed a "partly bracketed initializer"
+/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
-static int partial_bracket_mentioned = 0;
+static int missing_braces_mentioned;
extern char *index ();
extern char *rindex ();
-int mark_addressable ();
-static tree convert_for_assignment ();
-static void warn_for_assignment ();
-static int function_types_compatible_p ();
-static int type_lists_compatible_p ();
-int self_promoting_args_p ();
-static int self_promoting_type_p ();
-static int comp_target_types ();
-static tree pointer_int_sum ();
-static tree pointer_diff ();
-static tree convert_sequence ();
-static tree unary_complex_lvalue ();
-static tree process_init_constructor ();
-static tree convert_arguments ();
-static char *get_spelling ();
-static tree digest_init ();
-static void pedantic_lvalue_warning ();
-tree truthvalue_conversion ();
-void incomplete_type_error ();
-void readonly_warning ();
-static tree internal_build_compound_expr ();
-
-void process_init_element ();
+static tree quality_type PROTO((tree, tree));
+static int comp_target_types PROTO((tree, tree));
+static int function_types_compatible_p PROTO((tree, tree));
+static int type_lists_compatible_p PROTO((tree, tree));
+static int self_promoting_type_p PROTO((tree));
+static tree decl_constant_value PROTO((tree));
+static tree lookup_field PROTO((tree, tree, tree *));
+static tree convert_arguments PROTO((tree, tree, tree, tree));
+static tree pointer_int_sum PROTO((enum tree_code, tree, tree));
+static tree pointer_diff PROTO((tree, tree));
+static tree unary_complex_lvalue PROTO((enum tree_code, tree));
+static void pedantic_lvalue_warning PROTO((enum tree_code));
+static tree internal_build_compound_expr PROTO((tree, int));
+static tree convert_for_assignment PROTO((tree, tree, char *, tree,
+ tree, int));
+static void warn_for_assignment PROTO((char *, char *, tree, int));
+static tree valid_compound_expr_initializer PROTO((tree, tree));
+static void push_string PROTO((char *));
+static void push_member_name PROTO((tree));
+static void push_array_bounds PROTO((int));
+static int spelling_length PROTO((void));
+static char *print_spelling PROTO((char *));
+static char *get_spelling PROTO((char *));
+static void warning_init PROTO((char *, char *,
+ char *));
+static tree digest_init PROTO((tree, tree, int, int));
+static void check_init_type_bitfields PROTO((tree));
+static void output_init_element PROTO((tree, tree, tree, int));
+static void output_pending_init_elements PROTO((int));
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
{
register enum tree_code code1;
register enum tree_code code2;
+ tree attributes;
/* Save time if the two types are the same. */
if (t2 == error_mark_node)
return t1;
+ /* Merge the attributes */
+
+ { register tree a1, a2;
+ a1 = TYPE_ATTRIBUTES (t1);
+ a2 = TYPE_ATTRIBUTES (t2);
+
+ /* Either one unset? Take the set one. */
+
+ if (!(attributes = a1))
+ attributes = a2;
+
+ /* One that completely contains the other? Take it. */
+
+ else if (a2 && !attribute_list_contained (a1, a2))
+ if (attribute_list_contained (a2, a1))
+ attributes = a2;
+ else
+ {
+ /* Pick the longest list, and hang on the other list. */
+ /* ??? For the moment we punt on the issue of attrs with args. */
+
+ if (list_length (a1) < list_length (a2))
+ attributes = a2, a2 = a1;
+
+ for (; a2; a2 = TREE_CHAIN (a2))
+ if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ attributes) == NULL_TREE)
+ {
+ a1 = copy_node (a2);
+ TREE_CHAIN (a1) = attributes;
+ attributes = a1;
+ }
+ }
+ }
+
/* Treat an enum type as the unsigned integer type of the same width. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
- /* If one type is complex, form the common type
- of the non-complex components,
- then make that complex. */
+ /* If one type is complex, form the common type of the non-complex
+ components, then make that complex. Use T1 or T2 if it is the
+ required type. */
if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
{
- tree subtype1, subtype2, subtype;
- if (code1 == COMPLEX_TYPE)
- subtype1 = TREE_TYPE (t1);
- else
- subtype1 = t1;
- if (code2 == COMPLEX_TYPE)
- subtype2 = TREE_TYPE (t2);
+ tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+ tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+ tree subtype = common_type (subtype1, subtype2);
+
+ if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+ return build_type_attribute_variant (t1, attributes);
+ else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+ return build_type_attribute_variant (t2, attributes);
else
- subtype2 = t2;
- subtype = common_type (subtype1, subtype2);
- return build_complex_type (subtype);
+ return build_type_attribute_variant (build_complex_type (subtype),
+ attributes);
}
switch (code1)
/* If only one is real, use it as the result. */
if (code1 == REAL_TYPE && code2 != REAL_TYPE)
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (code2 == REAL_TYPE && code1 != REAL_TYPE)
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
- return t1;
+ return build_type_attribute_variant (t1, attributes);
else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Same precision. Prefer longs to ints even when same size. */
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
|| TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
- return long_unsigned_type_node;
+ return build_type_attribute_variant (long_unsigned_type_node,
+ attributes);
if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
|| TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
/* But preserve unsignedness from the other type,
since long cannot hold all the values of an unsigned int. */
if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
- return long_unsigned_type_node;
- return long_integer_type_node;
+ t1 = long_unsigned_type_node;
+ else
+ t1 = long_integer_type_node;
+ return build_type_attribute_variant (t1, attributes);
}
/* Otherwise prefer the unsigned one. */
if (TREE_UNSIGNED (t1))
- return t1;
- else return t2;
+ return build_type_attribute_variant (t1, attributes);
+ else
+ return build_type_attribute_variant (t2, attributes);
case POINTER_TYPE:
/* For two pointers, do this recursively on the target type,
= TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
int volatilep
= TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
- return build_pointer_type (c_build_type_variant (target, constp, volatilep));
+ t1 = build_pointer_type (c_build_type_variant (target, constp,
+ volatilep));
+ return build_type_attribute_variant (t1, attributes);
}
#if 0
- return build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
+ t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
+ return build_type_attribute_variant (t1, attributes);
#endif
case ARRAY_TYPE:
tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
/* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Merge the element types, and have a size if either arg has one. */
- return build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ return build_type_attribute_variant (t1, attributes);
}
case FUNCTION_TYPE:
/* Save space: see if the result is identical to one of the args. */
if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2))
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1))
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Simple way if one arg fails to specify argument types. */
if (TYPE_ARG_TYPES (t1) == 0)
- return build_function_type (valtype, TYPE_ARG_TYPES (t2));
+ {
+ t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
+ return build_type_attribute_variant (t1, attributes);
+ }
if (TYPE_ARG_TYPES (t2) == 0)
- return build_function_type (valtype, TYPE_ARG_TYPES (t1));
+ {
+ t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
+ return build_type_attribute_variant (t1, attributes);
+ }
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
parm_done: ;
}
- return build_function_type (valtype, newargs);
+ t1 = build_function_type (valtype, newargs);
+ /* ... falls through ... */
}
default:
- return t1;
+ return build_type_attribute_variant (t1, attributes);
}
}
{
register tree t1 = type1;
register tree t2 = type2;
+ int attrval, val;
/* Suppress errors caused by previously reported errors. */
if (t1 == t2 || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
return 1;
- /* Treat an enum type as the unsigned integer type of the same width. */
+ /* Treat an enum type as the integer type of the same width and
+ signedness. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = type_for_size (TYPE_PRECISION (t1), 1);
+ t1 = type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
if (TREE_CODE (t2) == ENUMERAL_TYPE)
- t2 = type_for_size (TYPE_PRECISION (t2), 1);
+ t2 = type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2));
if (t1 == t2)
return 1;
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
+#ifndef COMP_TYPE_ATTRIBUTES
+#define COMP_TYPE_ATTRIBUTES(t1,t2) 1
+#endif
+
+ /* 1 if no need for warning yet, 2 if warning cause has been seen. */
+ if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
+ return 0;
+
+ /* 1 if no need for warning yet, 2 if warning cause has been seen. */
+ val = 0;
+
switch (TREE_CODE (t1))
{
case POINTER_TYPE:
- return (TREE_TYPE (t1) == TREE_TYPE (t2)
+ val = (TREE_TYPE (t1) == TREE_TYPE (t2)
? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
+ break;
case FUNCTION_TYPE:
- return function_types_compatible_p (t1, t2);
+ val = function_types_compatible_p (t1, t2);
+ break;
case ARRAY_TYPE:
{
- /* 1 if no need for warning yet, 2 if warning cause has been seen. */
- int val = 1;
tree d1 = TYPE_DOMAIN (t1);
tree d2 = TYPE_DOMAIN (t2);
+ val = 1;
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
|| TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)
- return val;
+ break;
- return (((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1))
+ if (! ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1))
== TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2)))
&& (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1))
== TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2)))
&& (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1))
== TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2)))
&& (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1))
- == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2))))
- ? val : 0);
+ == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2)))))
+ val = 0;
+ break;
}
case RECORD_TYPE:
if (maybe_objc_comptypes (t1, t2, 0) == 1)
- return 1;
+ val = 1;
+ break;
}
- return 0;
+ return attrval == 2 && val == 1 ? 2 : val;
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
- int newval;
+ int newval = 0;
while (1)
{
/* 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_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))))
return 0;
}
else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
- && TYPE_NAME (TREE_VALUE (args2)) == 0
+ && (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))))
return long_unsigned_type_node;
if (type1 == long_long_integer_type_node)
return long_long_unsigned_type_node;
+ if (type1 == intDI_type_node)
+ return unsigned_intDI_type_node;
+ if (type1 == intSI_type_node)
+ return unsigned_intSI_type_node;
+ if (type1 == intHI_type_node)
+ return unsigned_intHI_type_node;
+ if (type1 == intQI_type_node)
+ return unsigned_intQI_type_node;
return type;
}
return long_integer_type_node;
if (type1 == long_long_unsigned_type_node)
return long_long_integer_type_node;
+ if (type1 == unsigned_intDI_type_node)
+ return intDI_type_node;
+ if (type1 == unsigned_intSI_type_node)
+ return intSI_type_node;
+ if (type1 == unsigned_intHI_type_node)
+ return intHI_type_node;
+ if (type1 == unsigned_intQI_type_node)
+ return intQI_type_node;
return type;
}
int unsignedp;
tree type;
{
- if (TREE_CODE (type) != INTEGER_TYPE)
+ if (! INTEGRAL_TYPE_P (type))
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
&& current_function_decl != 0
&& ! pedantic
&& ! TREE_THIS_VOLATILE (decl)
+ && TREE_READONLY (decl) && ! ITERATOR_P (decl)
&& DECL_INITIAL (decl) != 0
&& TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
/* This is invalid if initial value is not constant.
/* 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. */
- else if (optimize
- && TREE_CODE (exp) == VAR_DECL
- && TREE_READONLY (exp)
- /* But not for iterators! */
- && !ITERATOR_P (exp)
- && DECL_MODE (exp) != BLKmode)
+
+ /* 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 (exp);
type = TREE_TYPE (exp);
return convert (unsigned_type_node, exp);
return convert (integer_type_node, exp);
}
- if (flag_traditional && TYPE_MAIN_VARIANT (type) == float_type_node)
+ if (flag_traditional && !flag_allow_single_precision
+ && TYPE_MAIN_VARIANT (type) == float_type_node)
return convert (double_type_node, exp);
if (code == VOID_TYPE)
{
return exp;
}
\f
-/* Look up component name in the structure type definition. */
+/* Look up component name in the structure type definition.
+
+ If this component name is found indirectly within an anonymous union,
+ store in *INDIRECT the component which directly contains
+ that anonymous union. Otherwise, set *INDIRECT to 0. */
static tree
-lookup_field (type, component)
+lookup_field (type, component, indirect)
tree type, component;
+ tree *indirect;
{
tree field;
top = TYPE_LANG_SPECIFIC (type)->len;
while (top - bot > 1)
{
- HOST_WIDE_INT cmp;
-
half = (top - bot + 1) >> 1;
field = field_array[bot+half];
/* Step through all anon unions in linear fashion. */
while (DECL_NAME (field_array[bot]) == NULL_TREE)
{
- tree anon;
+ tree anon, junk;
+
field = field_array[bot++];
- anon = lookup_field (TREE_TYPE (field), component);
+ anon = lookup_field (TREE_TYPE (field), component, &junk);
if (anon != NULL_TREE)
- return anon;
+ {
+ *indirect = field;
+ return anon;
+ }
}
/* Entire record is only anon unions. */
continue;
}
- cmp = (HOST_WIDE_INT) DECL_NAME (field) - (HOST_WIDE_INT) component;
- if (cmp == 0)
+ if (DECL_NAME (field) == component)
break;
- if (cmp < 0)
+ if (DECL_NAME (field) < component)
bot += half;
else
top = bot + half;
{
if (DECL_NAME (field) == NULL_TREE)
{
- tree anon = lookup_field (TREE_TYPE (field), component);
+ tree junk;
+ tree anon = lookup_field (TREE_TYPE (field), component, &junk);
if (anon != NULL_TREE)
- return anon;
+ {
+ *indirect = field;
+ return anon;
+ }
}
if (DECL_NAME (field) == component)
}
}
+ *indirect = NULL_TREE;
return field;
}
if (code == RECORD_TYPE || code == UNION_TYPE)
{
+ tree indirect = 0;
+
if (TYPE_SIZE (type) == 0)
{
incomplete_type_error (NULL_TREE, type);
return error_mark_node;
}
- field = lookup_field (type, component);
+ field = lookup_field (type, component, &indirect);
if (!field)
{
if (TREE_TYPE (field) == error_mark_node)
return error_mark_node;
+ /* If FIELD was found buried within an anonymous union,
+ make one COMPONENT_REF to get that anonymous union,
+ then fall thru to make a second COMPONENT_REF to get FIELD. */
+ if (indirect != 0)
+ {
+ ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect);
+ if (TREE_READONLY (datum) || TREE_READONLY (indirect))
+ TREE_READONLY (ref) = 1;
+ if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect))
+ TREE_THIS_VOLATILE (ref) = 1;
+ datum = ref;
+ }
+
ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
if (TREE_READONLY (datum) || TREE_READONLY (field))
}
}
\f
-/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against PARAMS. */
-
-#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
-
-#define T_I &integer_type_node
-#define T_L &long_integer_type_node
-#define T_S &short_integer_type_node
-#define T_UI &unsigned_type_node
-#define T_UL &long_unsigned_type_node
-#define T_US &short_unsigned_type_node
-#define T_F &float_type_node
-#define T_D &double_type_node
-#define T_LD &long_double_type_node
-#define T_C &char_type_node
-#define T_V &void_type_node
-#define T_W &wchar_type_node
-
-typedef struct
-{
- char *format_chars;
- int pointer_count;
- /* Type of argument if no length modifier is used. */
- tree *nolen;
- /* Type of argument if length modifier for shortening is used.
- If NULL, then this modifier is not allowed. */
- tree *hlen;
- /* Type of argument if length modifier `l' is used.
- If NULL, then this modifier is not allowed. */
- tree *llen;
- /* Type of argument if length modifier `L' is used.
- If NULL, then this modifier is not allowed. */
- tree *bigllen;
- /* List of other modifier characters allowed with these options. */
- char *flag_chars;
-} format_char_info;
-
-static format_char_info print_table[]
- = {
- { "di", 0, T_I, T_I, T_L, NULL, "-wp0 +" },
- { "oxX", 0, T_UI, T_UI, T_UL, NULL, "-wp0#" },
- { "u", 0, T_UI, T_UI, T_UL, NULL, "-wp0" },
- { "feEgG", 0, T_D, NULL, NULL, T_LD, "-wp0 +#" },
- { "c", 0, T_I, NULL, T_W, NULL, "-w" },
- { "C", 0, T_W, NULL, NULL, NULL, "-w" },
- { "s", 1, T_C, NULL, T_W, NULL, "-wp" },
- { "S", 1, T_W, NULL, NULL, NULL, "-wp" },
- { "p", 1, T_V, NULL, NULL, NULL, "-w" },
- { "n", 1, T_I, T_S, T_L, NULL, "" },
- { NULL }
- };
-
-static format_char_info scan_table[]
- = {
- { "di", 1, T_I, T_S, T_L, NULL, "*" },
- { "ouxX", 1, T_UI, T_US, T_UL, NULL, "*" },
- { "efgEG", 1, T_F, NULL, T_D, T_LD, "*" },
- { "sc", 1, T_C, NULL, T_W, NULL, "*" },
- { "[", 1, T_C, NULL, NULL, NULL, "*" },
- { "C", 1, T_W, NULL, NULL, NULL, "*" },
- { "S", 1, T_W, NULL, NULL, NULL, "*" },
- { "p", 2, T_V, NULL, NULL, NULL, "*" },
- { "n", 1, T_I, T_S, T_L, NULL, "" },
- { NULL }
- };
-
-typedef struct
-{
- tree function_ident; /* identifier such as "printf" */
- int is_scan; /* TRUE if *scanf */
- int format_num; /* number of format argument */
- int first_arg_num; /* number of first arg (zero for varargs) */
-} function_info;
-
-static unsigned int function_info_entries = 0;
-static function_info *function_info_table = NULL;
-
-/* Record information for argument format checking. FUNCTION_IDENT is
- the identifier node for the name of the function to check (its decl
- need not exist yet). IS_SCAN is true for scanf-type format checking;
- false indicates printf-style format checking. FORMAT_NUM is the number
- of the argument which is the format control string (starting from 1).
- FIRST_ARG_NUM is the number of the first actual argument to check
- against teh format string, or zero if no checking is not be done
- (e.g. for varargs such as vfprintf). */
-
-void
-record_format_info (function_ident, is_scan, format_num, first_arg_num)
- tree function_ident;
- int is_scan;
- int format_num;
- int first_arg_num;
-{
- function_info *info;
-
- function_info_entries++;
- if (function_info_table)
- function_info_table
- = (function_info *) xrealloc (function_info_table,
- function_info_entries * sizeof (function_info));
- else
- function_info_table = (function_info *) xmalloc (sizeof (function_info));
-
- info = &function_info_table[function_info_entries - 1];
-
- info->function_ident = function_ident;
- info->is_scan = is_scan;
- info->format_num = format_num;
- info->first_arg_num = first_arg_num;
-}
-
-/* Initialize the table of functions to perform format checking on.
- The ANSI functions are always checked (whether <stdio.h> is
- included or not), since it is common to call printf without
- including <stdio.h>. There shouldn't be a problem with this,
- since ANSI reserves these function names whether you include the
- header file or not. In any case, the checking is harmless. */
-
-void
-init_format_info_table ()
-{
- record_format_info (get_identifier ("printf"), 0, 1, 2);
- record_format_info (get_identifier ("fprintf"), 0, 2, 3);
- record_format_info (get_identifier ("sprintf"), 0, 2, 3);
- record_format_info (get_identifier ("scanf"), 1, 1, 2);
- record_format_info (get_identifier ("fscanf"), 1, 2, 3);
- record_format_info (get_identifier ("sscanf"), 1, 2, 3);
- record_format_info (get_identifier ("vprintf"), 0, 1, 0);
- record_format_info (get_identifier ("vfprintf"), 0, 2, 0);
- record_format_info (get_identifier ("vsprintf"), 0, 2, 0);
-}
-
-static char tfaff[] = "too few arguments for format";
-\f
-/* Check the argument list of a call to printf, scanf, etc.
- INFO points to the element of function_info_table.
- PARAMS is the list of argument values. */
-
-static void
-check_format (info, params)
- function_info *info;
- tree params;
-{
- int i;
- int arg_num;
- int suppressed, wide, precise;
- int length_char;
- int format_char;
- int format_length;
- tree format_tree;
- tree cur_param;
- tree cur_type;
- tree wanted_type;
- char *format_chars;
- format_char_info *fci;
- static char message[132];
- char flag_chars[8];
-
- /* Skip to format argument. If the argument isn't available, there's
- no work for us to do; prototype checking will catch the problem. */
- for (arg_num = 1; ; ++arg_num)
- {
- if (params == 0)
- return;
- if (arg_num == info->format_num)
- break;
- params = TREE_CHAIN (params);
- }
- format_tree = TREE_VALUE (params);
- params = TREE_CHAIN (params);
- if (format_tree == 0)
- return;
- /* We can only check the format if it's a string constant. */
- while (TREE_CODE (format_tree) == NOP_EXPR)
- format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
- if (format_tree == null_pointer_node)
- {
- warning ("null format string");
- return;
- }
- if (TREE_CODE (format_tree) != ADDR_EXPR)
- return;
- format_tree = TREE_OPERAND (format_tree, 0);
- if (TREE_CODE (format_tree) != STRING_CST)
- return;
- format_chars = TREE_STRING_POINTER (format_tree);
- format_length = TREE_STRING_LENGTH (format_tree);
- if (format_length <= 1)
- warning ("zero-length format string");
- if (format_chars[--format_length] != 0)
- {
- warning ("unterminated format string");
- return;
- }
- /* Skip to first argument to check. */
- while (arg_num + 1 < info->first_arg_num)
- {
- if (params == 0)
- return;
- params = TREE_CHAIN (params);
- ++arg_num;
- }
- while (1)
- {
- if (*format_chars == 0)
- {
- if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
- warning ("embedded `\\0' in format");
- if (info->first_arg_num != 0 && params != 0)
- warning ("too many arguments for format");
- return;
- }
- if (*format_chars++ != '%')
- continue;
- if (*format_chars == 0)
- {
- warning ("spurious trailing `%%' in format");
- continue;
- }
- if (*format_chars == '%')
- {
- ++format_chars;
- continue;
- }
- flag_chars[0] = 0;
- suppressed = wide = precise = FALSE;
- if (info->is_scan)
- {
- suppressed = *format_chars == '*';
- if (suppressed)
- ++format_chars;
- while (ISDIGIT (*format_chars))
- ++format_chars;
- }
- else
- {
- while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
- {
- if (index (flag_chars, *format_chars) != 0)
- {
- sprintf (message, "repeated `%c' flag in format",
- *format_chars);
- warning (message);
- }
- i = strlen (flag_chars);
- flag_chars[i++] = *format_chars++;
- flag_chars[i] = 0;
- }
- /* "If the space and + flags both appear,
- the space flag will be ignored." */
- if (index (flag_chars, ' ') != 0
- && index (flag_chars, '+') != 0)
- warning ("use of both ` ' and `+' flags in format");
- /* "If the 0 and - flags both appear,
- the 0 flag will be ignored." */
- if (index (flag_chars, '0') != 0
- && index (flag_chars, '-') != 0)
- warning ("use of both `0' and `-' flags in format");
- if (*format_chars == '*')
- {
- wide = TRUE;
- /* "...a field width...may be indicated by an asterisk.
- In this case, an int argument supplies the field width..." */
- ++format_chars;
- if (params == 0)
- {
- warning (tfaff);
- return;
- }
- if (info->first_arg_num != 0)
- {
- cur_param = TREE_VALUE (params);
- params = TREE_CHAIN (params);
- ++arg_num;
- /* size_t is generally not valid here.
- It will work on most machines, because size_t and int
- have the same mode. But might as well warn anyway,
- since it will fail on other machines. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
- != integer_type_node)
- {
- sprintf (message,
- "field width is not type int (arg %d)",
- arg_num);
- warning (message);
- }
- }
- }
- else
- {
- while (ISDIGIT (*format_chars))
- {
- wide = TRUE;
- ++format_chars;
- }
- }
- if (*format_chars == '.')
- {
- precise = TRUE;
- ++format_chars;
- if (*format_chars != '*' && !ISDIGIT (*format_chars))
- warning ("`.' not followed by `*' or digit in format");
- /* "...a...precision...may be indicated by an asterisk.
- In this case, an int argument supplies the...precision." */
- if (*format_chars == '*')
- {
- if (info->first_arg_num != 0)
- {
- ++format_chars;
- if (params == 0)
- {
- warning (tfaff);
- return;
- }
- cur_param = TREE_VALUE (params);
- params = TREE_CHAIN (params);
- ++arg_num;
- if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
- != integer_type_node)
- {
- sprintf (message,
- "field width is not type int (arg %d)",
- arg_num);
- warning (message);
- }
- }
- }
- else
- {
- while (ISDIGIT (*format_chars))
- ++format_chars;
- }
- }
- }
- if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'L')
- length_char = *format_chars++;
- else
- length_char = 0;
- if (suppressed && length_char != 0)
- {
- sprintf (message,
- "use of `*' and `%c' together in format",
- length_char);
- warning (message);
- }
- format_char = *format_chars;
- if (format_char == 0)
- {
- warning ("conversion lacks type at end of format");
- continue;
- }
- format_chars++;
- fci = info->is_scan ? scan_table : print_table;
- while (1)
- {
- if (fci->format_chars == 0
- || index (fci->format_chars, format_char) != 0)
- break;
- ++fci;
- }
- if (fci->format_chars == 0)
- {
- if (format_char >= 040 && format_char < 0177)
- sprintf (message,
- "unknown conversion type character `%c' in format",
- format_char);
- else
- sprintf (message,
- "unknown conversion type character 0x%x in format",
- format_char);
- warning (message);
- continue;
- }
- if (wide && index (fci->flag_chars, 'w') == 0)
- {
- sprintf (message, "width used with `%c' format",
- format_char);
- warning (message);
- }
- if (precise && index (fci->flag_chars, 'p') == 0)
- {
- sprintf (message, "precision used with `%c' format",
- format_char);
- warning (message);
- }
- if (info->is_scan && format_char == '[')
- {
- /* Skip over scan set, in case it happens to have '%' in it. */
- if (*format_chars == '^')
- ++format_chars;
- /* Find closing bracket; if one is hit immediately, then
- it's part of the scan set rather than a terminator. */
- if (*format_chars == ']')
- ++format_chars;
- while (*format_chars && *format_chars != ']')
- ++format_chars;
- if (*format_chars != ']')
- /* The end of the format string was reached. */
- warning ("no closing `]' for `%%[' format");
- }
- if (suppressed)
- {
- if (index (fci->flag_chars, '*') == 0)
- {
- sprintf (message,
- "suppression of `%c' conversion in format",
- format_char);
- warning (message);
- }
- continue;
- }
- for (i = 0; flag_chars[i] != 0; ++i)
- {
- if (index (fci->flag_chars, flag_chars[i]) == 0)
- {
- sprintf (message, "flag `%c' used with type `%c'",
- flag_chars[i], format_char);
- warning (message);
- }
- }
- if (precise && index (flag_chars, '0') != 0
- && (format_char == 'd' || format_char == 'i'
- || format_char == 'o' || format_char == 'u'
- || format_char == 'x' || format_char == 'x'))
- {
- sprintf (message,
- "precision and `0' flag not both allowed with `%c' format",
- format_char);
- warning (message);
- }
- switch (length_char)
- {
- default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
- case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
- case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
- case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
- }
- if (wanted_type == 0)
- {
- sprintf (message,
- "use of `%c' length character with `%c' type character",
- length_char, format_char);
- warning (message);
- }
-
- /*
- ** XXX -- should kvetch about stuff such as
- ** {
- ** const int i;
- **
- ** scanf ("%d", &i);
- ** }
- */
-
- /* Finally. . .check type of argument against desired type! */
- if (info->first_arg_num == 0)
- continue;
- if (params == 0)
- {
- warning (tfaff);
- return;
- }
- cur_param = TREE_VALUE (params);
- params = TREE_CHAIN (params);
- ++arg_num;
- cur_type = TREE_TYPE (cur_param);
-
- /* Check the types of any additional pointer arguments
- that precede the "real" argument. */
- for (i = 0; i < fci->pointer_count; ++i)
- {
- if (TREE_CODE (cur_type) == POINTER_TYPE)
- {
- cur_type = TREE_TYPE (cur_type);
- continue;
- }
- sprintf (message,
- "format argument is not a %s (arg %d)",
- ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
- arg_num);
- warning (message);
- break;
- }
-
- /* Check the type of the "real" argument, if there's a type we want. */
- if (i == fci->pointer_count && wanted_type != 0
- && wanted_type != TYPE_MAIN_VARIANT (cur_type)
- /* If we want `void *', allow any pointer type.
- (Anything else would already have got a warning.) */
- && ! (wanted_type == void_type_node
- && fci->pointer_count > 0)
- /* Don't warn about differences merely in signedness. */
- && !(TREE_CODE (wanted_type) == INTEGER_TYPE
- && TREE_CODE (cur_type) == INTEGER_TYPE
- && (wanted_type == (TREE_UNSIGNED (wanted_type)
- ? unsigned_type : signed_type) (cur_type))))
- {
- register char *this;
- register char *that;
-
- this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
- that = 0;
- if (TREE_CODE (cur_type) != ERROR_MARK
- && TYPE_NAME (cur_type) != 0
- && TREE_CODE (cur_type) != INTEGER_TYPE
- && !(TREE_CODE (cur_type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE))
- {
- if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL
- && DECL_NAME (TYPE_NAME (cur_type)) != 0)
- that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
- else
- that = IDENTIFIER_POINTER (TYPE_NAME (cur_type));
- }
-
- /* A nameless type can't possibly match what the format wants.
- So there will be a warning for it.
- Make up a string to describe vaguely what it is. */
- if (that == 0)
- {
- if (TREE_CODE (cur_type) == POINTER_TYPE)
- that = "pointer";
- else
- that = "different type";
- }
-
- if (strcmp (this, that) != 0)
- {
- sprintf (message, "%s format, %s arg (arg %d)",
- this, that, arg_num);
- warning (message);
- }
- }
- }
-}
-\f
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
TREE_VALUE of each node is a parameter-expression.
build_function_call (function, params)
tree function, params;
{
- register tree fntype, fundecl;
+ register tree fntype, fundecl = 0;
register tree coerced_params;
- tree name = NULL_TREE;
+ tree name = NULL_TREE, assembler_name = NULL_TREE;
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
if (TREE_CODE (function) == FUNCTION_DECL)
{
name = DECL_NAME (function);
+ assembler_name = DECL_ASSEMBLER_NAME (function);
+
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
needs to be separately compiled). */
= convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
/* Check for errors in format strings. */
- if (warn_format && name != 0)
- {
- unsigned int i;
- /* See if this function is a format function. */
- for (i = 0; i < function_info_entries; i++)
- if (function_info_table[i].function_ident == name)
- {
- register char *message;
-
- /* If so, check it. */
- check_format (&function_info_table[i], coerced_params);
- break;
- }
- }
+ if (warn_format && (name || assembler_name))
+ check_function_format (name, assembler_name, coerced_params);
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
}
else
{
- tree parmname;
- tree type0 = type;
-#ifdef PROMOTE_PROTOTYPES
- /* Rather than truncating and then reextending,
- convert directly to int, if that's the type we will want. */
- if (! flag_traditional
- && (TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
- type = integer_type_node;
-#endif
-
-#if 0 /* This turns out not to win--there's no way to write a prototype
- for a function whose arg type is a union with no tag. */
- /* Nameless union automatically casts the types it contains. */
- if (TREE_CODE (type) == UNION_TYPE && TYPE_NAME (type) == 0)
- {
- tree field;
-
- for (field = TYPE_FIELDS (type); field;
- field = TREE_CHAIN (field))
- if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
- TYPE_MAIN_VARIANT (TREE_TYPE (val))))
- break;
-
- if (field)
- val = build1 (CONVERT_EXPR, type, val);
- }
-#endif
-
/* Optionally warn about conversions that
differ from the default conversions. */
if (warn_conversion)
{
int formal_prec = TYPE_PRECISION (type);
- if (TREE_CODE (type) != REAL_TYPE
+ if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+ else if (TREE_CODE (type) == COMPLEX_TYPE
+ && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) != REAL_TYPE)
+ && INTEGRAL_TYPE_P (TREE_TYPE (val)))
warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
else if (TREE_CODE (type) == REAL_TYPE
+ && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+ /* ??? At some point, messages should be written about
+ conversions between complex types, but that's too messy
+ to do now. */
+ else if (TREE_CODE (type) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
{
/* Warn if any argument is passed as `float',
warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
}
/* Detect integer changing in width or signedness. */
- else if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE))
+ else if (INTEGRAL_TYPE_P (type)
+ && INTEGRAL_TYPE_P (TREE_TYPE (val)))
{
tree would_have_been = default_conversion (val);
tree type1 = TREE_TYPE (would_have_been);
Zero means they need to be converted to RESULT_TYPE. */
int converted = 0;
+ /* Nonzero means create the expression with this type, rather than
+ RESULT_TYPE. */
+ tree build_type = 0;
+
/* Nonzero means after finally constructing the expression
- give it this type. Otherwise, give it type RESULT_TYPE. */
+ convert it to this type. */
tree final_type = 0;
/* Nonzero if this is an operation like MIN or MAX which can
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
- /* When dividing two signed integers, you have to promote to int.
- E.g. (short) -32868 / (short) -1 doesn't fit in a short. */
- shorten = TREE_UNSIGNED (op0);
+ {
+ /* Although it would be tempting to shorten always here, that
+ loses on some targets, since the modulo instruction is
+ undefined if the quotient can't be represented in the
+ computation mode. We shorten only if unsigned or if
+ dividing by something we know != -1. */
+ shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
+ || (TREE_CODE (op1) == INTEGER_CST
+ && (TREE_INT_CST_LOW (op1) != -1
+ || TREE_INT_CST_HIGH (op1) != -1)));
+ }
common = 1;
}
break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
- shorten = 1;
+ {
+ /* Although it would be tempting to shorten always here, that loses
+ on some targets, since the modulo instruction is undefined if the
+ quotient can't be represented in the computation mode. We shorten
+ only if unsigned or if dividing by something we know != -1. */
+ shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
+ || (TREE_CODE (op1) == INTEGER_CST
+ && (TREE_INT_CST_LOW (op1) != -1
+ || TREE_INT_CST_HIGH (op1) != -1)));
+ common = 1;
+ }
break;
case TRUTH_ANDIF_EXPR:
{
if (TREE_CODE (op1) == INTEGER_CST)
{
- if (tree_int_cst_lt (op1, integer_zero_node))
+ if (tree_int_cst_sgn (op1) < 0)
warning ("right shift count is negative");
else
{
{
if (TREE_CODE (op1) == INTEGER_CST)
{
- if (tree_int_cst_lt (op1, integer_zero_node))
+ if (tree_int_cst_sgn (op1) < 0)
warning ("left shift count is negative");
else if (TREE_INT_CST_HIGH (op1) != 0
|| ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
{
if (TREE_CODE (op1) == INTEGER_CST)
{
- if (tree_int_cst_lt (op1, integer_zero_node))
+ if (tree_int_cst_sgn (op1) < 0)
warning ("shift count is negative");
else if (TREE_INT_CST_HIGH (op1) != 0
|| ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
case NE_EXPR:
/* Result of comparison is always int,
but don't convert the args to int! */
- result_type = integer_type_node;
- converted = 1;
+ build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
if (comp_target_types (type0, type1))
- ;
+ result_type = common_type (type0, type1);
else if (TYPE_MAIN_VARIANT (tt0) == void_type_node)
{
/* op0 != orig_op0 detects the case of something
}
else
pedwarn ("comparison of distinct pointer types lacks a cast");
+
+ if (result_type == NULL_TREE)
+ result_type = ptr_type_node;
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
- op1 = null_pointer_node;
+ result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
- op0 = null_pointer_node;
+ result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
+ result_type = type0;
if (! flag_traditional)
pedwarn ("comparison between pointer and integer");
- op1 = convert (TREE_TYPE (op0), op1);
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
+ result_type = type1;
if (! flag_traditional)
pedwarn ("comparison between pointer and integer");
- op0 = convert (TREE_TYPE (op1), op0);
}
- else
- /* If args are not valid, clear out RESULT_TYPE
- to cause an error message later. */
- result_type = 0;
break;
case MAX_EXPR:
case MIN_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (! comp_target_types (type0, type1))
- pedwarn ("comparison of distinct pointer types lacks a cast");
- else if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
- result_type = common_type (type0, type1);
+ if (comp_target_types (type0, type1))
+ {
+ result_type = common_type (type0, type1);
+ if (pedantic
+ && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+ pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
+ }
+ else
+ {
+ result_type = ptr_type_node;
+ pedwarn ("comparison of distinct pointer types lacks a cast");
+ }
}
break;
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE))
+ build_type = integer_type_node;
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (! comp_target_types (type0, type1))
- pedwarn ("comparison of distinct pointer types lacks a cast");
- else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
- != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
- pedwarn ("comparison of complete and incomplete pointers");
- else if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
- result_type = integer_type_node;
+ if (comp_target_types (type0, type1))
+ {
+ result_type = common_type (type0, type1);
+ if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
+ != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
+ pedwarn ("comparison of complete and incomplete pointers");
+ else if (pedantic
+ && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+ pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
+ }
+ else
+ {
+ result_type = ptr_type_node;
+ pedwarn ("comparison of distinct pointer types lacks a cast");
+ }
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
{
- result_type = integer_type_node;
- op1 = null_pointer_node;
- if (! flag_traditional)
+ result_type = type0;
+ if (pedantic || extra_warnings)
pedwarn ("ordered comparison of pointer with integer zero");
}
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
{
- result_type = integer_type_node;
- op0 = null_pointer_node;
+ result_type = type1;
if (pedantic)
pedwarn ("ordered comparison of pointer with integer zero");
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- result_type = integer_type_node;
+ result_type = type0;
if (! flag_traditional)
pedwarn ("comparison between pointer and integer");
- op1 = convert (TREE_TYPE (op0), op1);
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
- result_type = integer_type_node;
+ result_type = type1;
if (! flag_traditional)
pedwarn ("comparison between pointer and integer");
- op0 = convert (TREE_TYPE (op1), op0);
}
- converted = 1;
break;
}
unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+ /* We can shorten only if the shift count is less than the
+ number of bits in the smaller type size. */
+ && TREE_INT_CST_HIGH (op1) == 0
+ && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1)
/* If arg is sign-extended and then unsigned-shifted,
we can simulate this with a signed shift in arg's type
only if the extended result is at least twice as wide
/* Comparison operations are shortened too but differently.
They identify themselves by setting short_compare = 1. */
- if (short_compare && none_complex)
+ if (short_compare)
{
/* Don't write &op0, etc., because that would prevent op0
from being kept in a register.
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
return val;
- op0 = xop0, op1 = xop1, result_type = xresult_type;
+ op0 = xop0, op1 = xop1;
+ converted = 1;
resultcode = xresultcode;
if (extra_warnings)
{
- tree op0_type = TREE_TYPE (orig_op0);
- tree op1_type = TREE_TYPE (orig_op1);
- int op0_unsigned = TREE_UNSIGNED (op0_type);
- int op1_unsigned = TREE_UNSIGNED (op1_type);
+ int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+
+ int unsignedp0, unsignedp1;
+ tree primop0 = get_narrower (op0, &unsignedp0);
+ tree primop1 = get_narrower (op1, &unsignedp1);
+
+ /* Avoid spurious warnings for comparison with enumerators. */
+ xop0 = orig_op0;
+ xop1 = orig_op1;
+ STRIP_TYPE_NOPS (xop0);
+ STRIP_TYPE_NOPS (xop1);
+
/* Give warnings for comparisons between signed and unsigned
- quantities that will fail. Do not warn if the signed quantity
- is an unsuffixed integer literal (or some static constant
- expression involving such literals) and it is positive.
- Do not warn if the width of the unsigned quantity is less
- than that of the signed quantity, since in this case all
- values of the unsigned quantity fit in the signed quantity.
- Do not warn if the signed type is the same size as the
- result_type since sign extension does not cause trouble in
- this case. */
+ quantities that may fail. */
/* Do the checking based on the original operand trees, so that
casts will be considered, but default promotions won't be. */
- if (op0_unsigned != op1_unsigned
- && ((op0_unsigned
- && TYPE_PRECISION (op0_type) >= TYPE_PRECISION (op1_type)
- && TYPE_PRECISION (op0_type) < TYPE_PRECISION (result_type)
- && (TREE_CODE (op1) != INTEGER_CST
- || (TREE_CODE (op1) == INTEGER_CST
- && INT_CST_LT (op1, integer_zero_node))))
- ||
- (op1_unsigned
- && TYPE_PRECISION (op1_type) >= TYPE_PRECISION (op0_type)
- && TYPE_PRECISION (op1_type) < TYPE_PRECISION (result_type)
- && (TREE_CODE (op0) != INTEGER_CST
- || (TREE_CODE (op0) == INTEGER_CST
- && INT_CST_LT (op0, integer_zero_node))))))
+
+ /* Do not warn if the comparison is being done in a signed type,
+ since the signed type will only be chosen if it can represent
+ all the values of the unsigned type. */
+ if (! TREE_UNSIGNED (result_type))
+ /* OK */;
+ /* Do not warn if both operands are unsigned. */
+ else if (op0_signed == op1_signed)
+ /* OK */;
+ /* Do not warn if the signed quantity is an unsuffixed
+ integer literal (or some static constant expression
+ involving such literals) and it is non-negative. */
+ else if ((op0_signed && TREE_CODE (xop0) == INTEGER_CST
+ && tree_int_cst_sgn (xop0) >= 0)
+ || (op1_signed && TREE_CODE (xop1) == INTEGER_CST
+ && tree_int_cst_sgn (xop1) >= 0))
+ /* OK */;
+ /* Do not warn if the comparison is an equality operation,
+ the unsigned quantity is an integral constant and it does
+ not use the most significant bit of result_type. */
+ else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
+ && ((op0_signed && TREE_CODE (xop1) == INTEGER_CST
+ && int_fits_type_p (xop1, signed_type (result_type))
+ || (op1_signed && TREE_CODE (xop0) == INTEGER_CST
+ && int_fits_type_p (xop0, signed_type (result_type))))))
+ /* OK */;
+ else
warning ("comparison between signed and unsigned");
+
+ /* Warn if two unsigned values are being compared in a size
+ larger than their original size, and one (and only one) is the
+ result of a `~' operator. This comparison will always fail.
+
+ Also warn if one operand is a constant, and the constant
+ does not have all bits set that are set in the ~ operand
+ when it is extended. */
+
+ if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
+ != (TREE_CODE (primop1) == BIT_NOT_EXPR))
+ {
+ if (TREE_CODE (primop0) == BIT_NOT_EXPR)
+ primop0 = get_narrower (TREE_OPERAND (primop0, 0),
+ &unsignedp0);
+ else
+ primop1 = get_narrower (TREE_OPERAND (primop1, 0),
+ &unsignedp1);
+
+ if (TREE_CODE (primop0) == INTEGER_CST
+ || TREE_CODE (primop1) == INTEGER_CST)
+ {
+ tree primop;
+ long constant, mask;
+ int unsignedp, bits;
+
+ if (TREE_CODE (primop0) == INTEGER_CST)
+ {
+ primop = primop1;
+ unsignedp = unsignedp1;
+ constant = TREE_INT_CST_LOW (primop0);
+ }
+ else
+ {
+ primop = primop0;
+ unsignedp = unsignedp0;
+ constant = TREE_INT_CST_LOW (primop1);
+ }
+
+ bits = TYPE_PRECISION (TREE_TYPE (primop));
+ if (bits < TYPE_PRECISION (result_type)
+ && bits < HOST_BITS_PER_LONG && unsignedp)
+ {
+ mask = (~0L) << bits;
+ if ((mask & constant) != mask)
+ warning ("comparison of promoted ~unsigned with constant");
+ }
+ }
+ else if (unsignedp0 && unsignedp1
+ && (TYPE_PRECISION (TREE_TYPE (primop0))
+ < TYPE_PRECISION (result_type))
+ && (TYPE_PRECISION (TREE_TYPE (primop1))
+ < TYPE_PRECISION (result_type)))
+ warning ("comparison of promoted ~unsigned with unsigned");
+ }
}
}
}
op1 = convert (result_type, op1);
}
+ if (build_type == NULL_TREE)
+ build_type = result_type;
+
{
- register tree result = build (resultcode, result_type, op0, op1);
+ register tree result = build (resultcode, build_type, op0, op1);
register tree folded;
folded = fold (result);
&& TREE_CONSTANT (size_exp)
/* If the constant comes from pointer subtraction,
skip this optimization--it would cause an error. */
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
+ /* If the constant is unsigned, and smaller than the pointer size,
+ then we must skip this optimization. This is because it could cause
+ an overflow error if the constant is negative but INTOP is not. */
+ && (! TREE_UNSIGNED (TREE_TYPE (intop))
+ || (TYPE_PRECISION (TREE_TYPE (intop))
+ == TYPE_PRECISION (TREE_TYPE (ptrop)))))
{
enum tree_code subcode = resultcode;
tree int_type = TREE_TYPE (intop);
if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
intop = convert (type_for_size (POINTER_SIZE, 0), intop);
- /* Replace the integer argument
- with a suitable product by the object size. */
+ /* Replace the integer argument with a suitable product by the object size.
+ Do this multiplication as signed, then convert to the appropriate
+ pointer type (actually unsigned integral). */
- intop = build_binary_op (MULT_EXPR, intop, size_exp, 1);
+ intop = convert (result_type,
+ build_binary_op (MULT_EXPR, intop,
+ convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
/* This generates an error if op1 is pointer to incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
error ("arithmetic on pointer to an incomplete type");
+
/* This generates an error if op0 is pointer to incomplete type. */
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- result = build (EXACT_DIV_EXPR, restype, op0, op1);
+ result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
folded = fold (result);
if (folded == result)
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"));
- inc = c_sizeof_nowarn (TREE_TYPE (result_type));
+ inc = c_size_in_bytes (TREE_TYPE (result_type));
}
else
inc = integer_one_node;
case ADDR_EXPR:
case COMPONENT_REF:
case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
x = TREE_OPERAND (x, 0);
break;
IDENTIFIER_POINTER (DECL_NAME (x)));
return 0;
}
+
+ /* If we are making this addressable due to its having
+ volatile components, give a different error message. Also
+ handle the case of an unnamed parameter by not trying
+ to give the name. */
+
+ else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
+ {
+ error ("cannot put object with volatile field into register");
+ return 0;
+ }
+
pedwarn ("address of register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
- /* When pedantic, a compound expression can be neither an lvalue
- nor an integer constant expression. */
- if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
- return rest;
+ if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+ {
+ /* The left-hand operand of a comma expression is like an expression
+ statement: with -W or -Wunused, we should warn if it doesn't have
+ any side-effects, unless it was explicitly cast to (void). */
+ if ((extra_warnings || warn_unused)
+ && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
+ && TREE_TYPE (TREE_VALUE (list)) == void_type_node))
+ warning ("left-hand operand of comma expression has no effect");
+
+ /* When pedantic, a compound expression can be neither an lvalue
+ nor an integer constant expression. */
+ if (! pedantic)
+ return rest;
+ }
+
+ /* With -Wunused, we should also warn if the left-hand operand does have
+ side-effects, but computes a value which is not used. For example, in
+ `foo() + bar(), baz()' the result of the `+' operator is not used,
+ so we should issue a warning. */
+ else if (warn_unused)
+ warn_if_unused_value (TREE_VALUE (list));
return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
}
if (field)
{
char *name;
- tree nvalue;
+ tree t;
if (pedantic)
pedwarn ("ANSI C forbids casts to union type");
}
else
name = "";
- return digest_init (type, build_nt (CONSTRUCTOR, NULL_TREE,
- build_tree_list (field, value)),
- 0, 0);
+ t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE,
+ build_tree_list (field, value)),
+ 0, 0);
+ TREE_CONSTANT (t) = TREE_CONSTANT (value);
+ return t;
}
error ("cast to union type from type not present in union");
return error_mark_node;
&& !TREE_CONSTANT (value))
warning ("cast from pointer to integer of different size");
+ if (warn_bad_function_cast
+ && TREE_CODE (value) == CALL_EXPR
+ && TREE_CODE (type) != TREE_CODE (otype))
+ warning ("cast does not match function type");
+
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
/* Handle (a, b) used as an "lvalue". */
case COMPOUND_EXPR:
pedantic_lvalue_warning (COMPOUND_EXPR);
+ newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
+ modifycode, rhs);
+ if (TREE_CODE (newrhs) == ERROR_MARK)
+ return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
- TREE_OPERAND (lhs, 0),
- build_modify_expr (TREE_OPERAND (lhs, 1),
- modifycode, rhs));
-
+ TREE_OPERAND (lhs, 0), newrhs);
+
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
pedantic_lvalue_warning (COND_EXPR);
modifycode, rhs),
build_modify_expr (TREE_OPERAND (lhs, 2),
modifycode, rhs));
+ if (TREE_CODE (cond) == ERROR_MARK)
+ return cond;
/* Make sure the code to compute the rhs comes out
before the split. */
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
result = build_modify_expr (inner_lhs, NOP_EXPR,
convert (TREE_TYPE (inner_lhs),
convert (lhstype, newrhs)));
+ if (TREE_CODE (result) == ERROR_MARK)
+ return result;
pedantic_lvalue_warning (CONVERT_EXPR);
return convert (TREE_TYPE (lhs), result);
}
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)
+ rhs = decl_constant_value (rhs);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
/* Arithmetic types all interconvert, and enum is treated like int. */
if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE
|| codel == COMPLEX_TYPE)
- &&
- (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
- || codel == COMPLEX_TYPE))
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
+ || coder == COMPLEX_TYPE))
return convert_and_check (type, rhs);
+
/* Conversion to a union from its member types. */
else if (codel == UNION_TYPE)
{
tree memb_types;
+
for (memb_types = TYPE_FIELDS (type); memb_types;
memb_types = TREE_CHAIN (memb_types))
{
pedwarn ("ANSI C prohibits argument conversion to union type");
return build1 (NOP_EXPR, type, rhs);
}
+
else if (coder == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
{
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
- Meanwhile, the lhs target must have all the qualifiers of the rhs. */
+ Meanwhile, the lhs target must have all the qualifiers of
+ the rhs. */
if (TYPE_MAIN_VARIANT (ttl) == void_type_node
|| TYPE_MAIN_VARIANT (ttr) == void_type_node
|| comp_target_types (memb_type, rhstype))
{
- /* Const and volatile mean something different for function types,
- so the usual warnings are not appropriate. */
+ /* Const and volatile mean something different for function
+ types, so the usual warnings are not appropriate. */
if (TREE_CODE (ttr) != FUNCTION_TYPE
|| TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
warn_for_assignment ("%s discards `const' from pointer target type",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
warn_for_assignment ("%s discards `volatile' from pointer target type",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
}
else
{
- /* Because const and volatile on functions are restrictions
- that say the function will not do certain things,
- it is okay to use a const or volatile function
- where an ordinary one is wanted, but not vice-versa. */
+ /* Because const and volatile on functions are
+ restrictions that say the function will not do
+ certain things, it is okay to use a const or volatile
+ function where an ordinary one is wanted, but not
+ vice-versa. */
if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
warn_for_assignment ("%s makes `const *' function pointer from non-const",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
- get_spelling (errtype), funname, parmnum);
+ get_spelling (errtype), funname,
+ parmnum);
}
+
if (pedantic
&& !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
pedwarn ("ANSI C prohibits argument conversion to union type");
return build1 (NOP_EXPR, type, rhs);
}
}
+
+ /* Can convert integer zero to any pointer type. */
+ else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE
+ && (integer_zerop (rhs)
+ || (TREE_CODE (rhs) == NOP_EXPR
+ && integer_zerop (TREE_OPERAND (rhs, 0)))))
+ return build1 (NOP_EXPR, type, null_pointer_node);
}
}
+
/* Conversions among pointers */
else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
{
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
else if (TREE_CODE (ttr) != FUNCTION_TYPE
- || TREE_CODE (ttl) != FUNCTION_TYPE)
+ && TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
warn_for_assignment ("%s discards `const' from pointer target type",
warn_for_assignment ("pointer targets in %s differ in signedness",
get_spelling (errtype), funname, parmnum);
}
- else
+ else if (TREE_CODE (ttl) == FUNCTION_TYPE
+ && TREE_CODE (ttr) == FUNCTION_TYPE)
{
/* Because const and volatile on functions are restrictions
that say the function will not do certain things,
else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
{
/* An explicit constant 0 can convert to a pointer,
- but not a 0 that results from casting or folding. */
- if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
+ or one that results from arithmetic, even including
+ a cast to integer type. */
+ if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
+ &&
+ ! (TREE_CODE (rhs) == NOP_EXPR
+ && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
+ && integer_zerop (TREE_OPERAND (rhs, 0))))
{
warn_for_assignment ("%s makes pointer from integer without a cast",
get_spelling (errtype), funname, parmnum);
therefore, we do not need to check for such things as
arithmetic-combinations of integers. */
-static tree
+tree
initializer_constant_valid_p (value, endtype)
tree value;
tree endtype;
switch (TREE_CODE (value))
{
case CONSTRUCTOR:
+ if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
+ && TREE_CONSTANT (value))
+ return
+ initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
+ endtype);
+
return TREE_STATIC (value) ? null_pointer_node : 0;
case INTEGER_CST:
if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
/* Allow conversions between real types. */
if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
/* Allow length-preserving conversions between integer types. */
if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
- && tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (value)),
- TYPE_SIZE (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
- /* Allow conversions between integer types only if explicit value. */
+
+ /* Allow conversions between other integer types only if
+ explicit value. */
if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
{
return null_pointer_node;
return 0;
}
+
/* Allow (int) &foo provided int is as wide as a pointer. */
if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
- && ! tree_int_cst_lt (TYPE_SIZE (TREE_TYPE (value)),
- TYPE_SIZE (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
+
+ /* Likewise conversions from int to pointers. */
+ if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+
/* Allow conversions to union types if the value inside is okay. */
if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
pedwarn (format, buffer);
}
+
+/* Issue a warning for a bad initializer component.
+ FORMAT describes the message. OFWHAT is the name for the component.
+ LOCAL is a format string for formatting the insertion of the name
+ into the message.
+
+ If OFWHAT is null, the component name is stored on the spelling stack.
+ If the component name is a null string, then LOCAL is omitted entirely. */
+
+static void
+warning_init (format, local, ofwhat)
+ char *format, *local, *ofwhat;
+{
+ char *buffer;
+
+ if (ofwhat == 0)
+ ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
+ buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2);
+
+ if (*ofwhat)
+ sprintf (buffer, local, ofwhat);
+ else
+ buffer[0] = 0;
+
+ warning (format, buffer);
+}
\f
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
|| typ1 == signed_wchar_type_node)
&& ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
{
- if (TREE_TYPE (inside_init) == type)
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+ TYPE_MAIN_VARIANT (type)))
return inside_init;
if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
return error_mark_node;
}
- if (optimize && TREE_READONLY (inside_init)
- && TREE_CODE (inside_init) == VAR_DECL)
+ if (optimize && TREE_CODE (inside_init) == VAR_DECL)
inside_init = decl_constant_value (inside_init);
/* Compound expressions can only occur here if -pedantic or
return error_mark_node;
}
+ /* Traditionally, you can write struct foo x = 0;
+ and it initializes the first element of x to 0. */
+ if (flag_traditional)
+ {
+ tree top = 0, prev = 0, otype = type;
+ while (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ {
+ tree temp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ if (prev == 0)
+ top = temp;
+ else
+ TREE_OPERAND (prev, 1) = build_tree_list (NULL_TREE, temp);
+ prev = temp;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+ else if (TYPE_FIELDS (type))
+ type = TREE_TYPE (TYPE_FIELDS (type));
+ else
+ {
+ error_init ("invalid initializer%s", " for `%s'", NULL);
+ return error_mark_node;
+ }
+ }
+
+ if (otype != type)
+ {
+ TREE_OPERAND (prev, 1)
+ = build_tree_list (NULL_TREE,
+ digest_init (type, init, require_constant,
+ constructor_constant));
+ return top;
+ }
+ else
+ return error_mark_node;
+ }
error_init ("invalid initializer%s", " for `%s'", NULL);
return error_mark_node;
}
\f
/* Handle initializers that use braces. */
-static void output_init_element ();
-static void output_pending_init_elements ();
-static void check_init_type_bitfields ();
-
/* Type of object we are accumulating a constructor for.
This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE. */
static tree constructor_type;
static tree constructor_index;
/* For an ARRAY_TYPE, this is the end index of the range
- to intitialize with the next element, or NULL in the ordinary case
+ to initialize with the next element, or NULL in the ordinary case
where the element is used just once. */
static tree constructor_range_end;
tree decl;
char *asmspec;
struct constructor_stack *constructor_stack;
+ tree elements;
struct spelling *spelling;
struct spelling *spelling_base;
int spelling_size;
p->require_constant_value = require_constant_value;
p->require_constant_elements = require_constant_elements;
p->constructor_stack = constructor_stack;
+ p->elements = constructor_elements;
p->spelling = spelling;
p->spelling_base = spelling_base;
p->spelling_size = spelling_size;
if (decl != 0)
{
require_constant_value = TREE_STATIC (decl);
- require_constant_elements = TREE_STATIC (decl) || pedantic;
+ require_constant_elements
+ = ((TREE_STATIC (decl) || pedantic)
+ /* For a scalar, you can always use any value to initialize,
+ even within braces. */
+ && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
locus = IDENTIFIER_POINTER (DECL_NAME (decl));
constructor_incremental |= TREE_STATIC (decl);
}
constructor_stack = 0;
+ missing_braces_mentioned = 0;
+
spelling_base = 0;
spelling_size = 0;
RESTORE_SPELLING_DEPTH (0);
require_constant_value = p->require_constant_value;
require_constant_elements = p->require_constant_elements;
constructor_stack = p->constructor_stack;
+ constructor_elements = p->elements;
spelling = p->spelling;
spelling_base = p->spelling_base;
spelling_size = p->spelling_size;
p->unfilled_index = constructor_unfilled_index;
p->unfilled_fields = constructor_unfilled_fields;
p->bit_index = constructor_bit_index;
- p->elements = 0;
+ p->elements = constructor_elements;
p->constant = constructor_constant;
p->simple = constructor_simple;
p->erroneous = constructor_erroneous;
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
constructor_fields = TYPE_FIELDS (constructor_type);
+ /* Skip any nameless bit fields at the beginning. */
+ while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ && DECL_NAME (constructor_fields) == 0)
+ constructor_fields = TREE_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = copy_node (integer_zero_node);
}
break;
}
+ /* Structure elements may require alignment. Do this now
+ if necessary for the subaggregate. */
+ if (constructor_incremental && constructor_type != 0
+ && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields)
+ {
+ /* Advance to offset of this element. */
+ if (! tree_int_cst_equal (constructor_bit_index,
+ DECL_FIELD_BITPOS (constructor_fields)))
+ {
+ int next = (TREE_INT_CST_LOW
+ (DECL_FIELD_BITPOS (constructor_fields))
+ / BITS_PER_UNIT);
+ int here = (TREE_INT_CST_LOW (constructor_bit_index)
+ / BITS_PER_UNIT);
+
+ assemble_zeros (next - here);
+ }
+ }
+
p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
p->type = constructor_type;
p->fields = constructor_fields;
{
constructor_type = TREE_TYPE (constructor_fields);
push_member_name (constructor_fields);
+ constructor_depth++;
+ if (constructor_fields != constructor_unfilled_fields)
+ constructor_incremental = 0;
}
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
constructor_type = TREE_TYPE (constructor_type);
push_array_bounds (TREE_INT_CST_LOW (constructor_index));
+ constructor_depth++;
+ if (! tree_int_cst_equal (constructor_index, constructor_unfilled_index)
+ || constructor_range_end != 0)
+ constructor_incremental = 0;
}
- /* Turn off constructor_incremental if type is a struct with bitfields. */
- if (constructor_type != 0)
- check_init_type_bitfields (constructor_type);
-
if (constructor_type == 0)
{
error_init ("extra brace group at end of initializer%s",
" for `%s'", NULL);
constructor_fields = 0;
constructor_unfilled_fields = 0;
+ return;
}
- else if (TREE_CODE (constructor_type) == RECORD_TYPE
+
+ /* Turn off constructor_incremental if type is a struct with bitfields. */
+ check_init_type_bitfields (constructor_type);
+
+ if (implicit && warn_missing_braces && !missing_braces_mentioned)
+ {
+ missing_braces_mentioned = 1;
+ warning_init ("missing braces around initializer%s", " for `%s'", NULL);
+ }
+
+ if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
constructor_fields = TYPE_FIELDS (constructor_type);
+ /* Skip any nameless bit fields at the beginning. */
+ while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ && DECL_NAME (constructor_fields) == 0)
+ constructor_fields = TREE_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = copy_node (integer_zero_node);
}
}
else
{
- warning ("braces around scalar initializer");
+ warning_init ("braces around scalar initializer%s", " for `%s'", NULL);
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
}
tree tail;
for (tail = TYPE_FIELDS (type); tail;
tail = TREE_CHAIN (tail))
- if (DECL_BIT_FIELD (tail)
- /* This catches cases like `int foo : 8;'. */
- || DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail)))
- {
- constructor_incremental = 0;
- break;
- }
+ {
+ if (DECL_BIT_FIELD (tail)
+ /* This catches cases like `int foo : 8;'. */
+ || DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail)))
+ {
+ constructor_incremental = 0;
+ break;
+ }
+
+ check_init_type_bitfields (TREE_TYPE (tail));
+ }
}
+
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ check_init_type_bitfields (TREE_TYPE (type));
}
/* At the end of an implicit or explicit brace level,
int implicit;
{
struct constructor_stack *p;
- int size;
+ int size = 0;
tree constructor = 0;
if (implicit == 0)
&& constructor_incremental)
{
constructor = digest_init (constructor_type, constructor,
- 0, 0);
+ require_constant_value,
+ require_constant_elements);
/* If initializing an array of unknown size,
determine the size now. */
&& TYPE_DOMAIN (constructor_type) == 0)
{
int failure;
+ int momentary_p;
push_obstacks_nochange ();
if (TREE_PERMANENT (constructor_type))
end_temporary_allocation ();
+ momentary_p = suspend_momentary ();
+
/* We shouldn't have an incomplete array type within
some other type. */
if (constructor_stack->next)
abort ();
size = int_size_in_bytes (constructor_type);
+ resume_momentary (momentary_p);
pop_obstacks ();
}
}
else if (constructor_type == 0)
;
+ else if (TREE_CODE (constructor_type) != RECORD_TYPE
+ && TREE_CODE (constructor_type) != UNION_TYPE
+ && TREE_CODE (constructor_type) != ARRAY_TYPE
+ && ! constructor_incremental)
+ {
+ /* A nonincremental scalar initializer--just return
+ the element, after verifying there is just one. */
+ if (constructor_elements == 0)
+ {
+ error_init ("empty scalar initializer%s",
+ " for `%s'", NULL);
+ constructor = error_mark_node;
+ }
+ else if (TREE_CHAIN (constructor_elements) != 0)
+ {
+ error_init ("extra elements in scalar initializer%s",
+ " for `%s'", NULL);
+ constructor = TREE_VALUE (constructor_elements);
+ }
+ else
+ constructor = TREE_VALUE (constructor_elements);
+ }
else if (! constructor_incremental)
{
if (constructor_erroneous)
TREE_CONSTANT (constructor) = 1;
if (constructor_constant && constructor_simple)
TREE_STATIC (constructor) = 1;
+
resume_momentary (momentary);
}
}
TYPE_DOMAIN (constructor_type) = build_index_type (maxindex);
TREE_TYPE (maxindex) = TYPE_DOMAIN (constructor_type);
- /* We shouldn't have an incomplete array type within
- some other type. */
- if (constructor_stack->next)
- abort ();
-
+ /* TYPE_MAX_VALUE is always one less than the number of elements
+ in the array, because we start counting at zero. Therefore,
+ warn only if the value is less than zero. */
if (pedantic
- && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)),
- integer_zero_node))
- error_with_decl (constructor_decl, "zero-size array `%s'");
+ && (tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+ < 0))
+ error_with_decl (constructor_decl,
+ "zero or negative array size `%s'");
layout_type (constructor_type);
size = int_size_in_bytes (constructor_type);
pop_obstacks ();
set_init_index (first, last)
tree first, last;
{
+ 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%s", " for `%s'", NULL);
else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
tree tail;
int passed = 0;
+ /* Don't die if an entire brace-pair level is superfluous
+ in the containing level. */
+ if (constructor_type == 0)
+ return;
+
for (tail = TYPE_FIELDS (constructor_type); tail;
tail = TREE_CHAIN (tail))
{
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
constructor_constant = 0;
- else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
+ else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
+ || ((TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == UNION_TYPE)
+ && DECL_BIT_FIELD (field) && TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
if (require_constant_value && ! TREE_CONSTANT (value))
constructor_index, which is modified in place. */
constructor_pending_elts
= tree_cons (copy_node (field),
- digest_init (type, value, 0, 0),
+ digest_init (type, value, require_constant_value,
+ require_constant_elements),
constructor_pending_elts);
}
- else if ((TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
+ else if (TREE_CODE (constructor_type) == RECORD_TYPE
&& field != constructor_unfilled_fields)
{
+ /* We do this for records but not for unions. In a union,
+ no matter which field is specified, it can be initialized
+ right away since it starts at the beginning of the union. */
if (!duplicate)
constructor_pending_elts
= tree_cons (field,
- digest_init (type, value, 0, 0),
+ digest_init (type, value, require_constant_value,
+ require_constant_elements),
constructor_pending_elts);
}
else
{
if (! constructor_incremental)
{
- if (TREE_CODE (field) == INTEGER_CST)
+ if (field && TREE_CODE (field) == INTEGER_CST)
field = copy_node (field);
constructor_elements
- = tree_cons (field, digest_init (type, value, 0, 0),
+ = tree_cons (field, digest_init (type, value,
+ require_constant_value,
+ require_constant_elements),
constructor_elements);
}
else
{
/* Advance to offset of this element. */
if (! tree_int_cst_equal (constructor_bit_index,
- DECL_FIELD_BITPOS (constructor_fields)))
+ DECL_FIELD_BITPOS (field)))
{
int next = (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
/ BITS_PER_UNIT);
assemble_zeros (next - here);
}
}
- output_constant (digest_init (type, value, 0, 0),
+ output_constant (digest_init (type, value,
+ require_constant_value,
+ require_constant_elements),
int_size_in_bytes (type));
/* For a record or union,
if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
- tree temp = size_binop (PLUS_EXPR,
- DECL_FIELD_BITPOS (constructor_fields),
- DECL_SIZE (constructor_fields));
+ tree temp = size_binop (PLUS_EXPR, DECL_FIELD_BITPOS (field),
+ DECL_SIZE (field));
TREE_INT_CST_LOW (constructor_bit_index)
= TREE_INT_CST_LOW (temp);
TREE_INT_CST_HIGH (constructor_bit_index)
if (tree_int_cst_equal (TREE_PURPOSE (tail),
constructor_unfilled_index))
{
- output_init_element (TREE_VALUE (tail), TREE_TYPE (constructor_type),
+ output_init_element (TREE_VALUE (tail),
+ TREE_TYPE (constructor_type),
constructor_unfilled_index, 0);
goto retry;
}
constructor_unfilled_index))
;
else if (next == 0
- || tree_int_cst_lt (TREE_PURPOSE (tail),
- next))
+ || tree_int_cst_lt (TREE_PURPOSE (tail), next))
next = TREE_PURPOSE (tail);
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
0);
goto retry;
}
- else if (tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
- DECL_FIELD_BITPOS (constructor_unfilled_fields)))
+ else if (constructor_unfilled_fields == 0
+ || tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
+ DECL_FIELD_BITPOS (constructor_unfilled_fields)))
;
else if (next == 0
|| tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
if (constructor_incremental)
{
tree filled;
- tree nextpos_tree;
+ tree nextpos_tree = size_int (0);
if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
- /* Find the last field written out. */
+ /* Find the last field written out, if any. */
for (tail = TYPE_FIELDS (constructor_type); tail;
tail = TREE_CHAIN (tail))
if (TREE_CHAIN (tail) == constructor_unfilled_fields)
break;
- /* Find the offset of the end of that field. */
- filled = size_binop (CEIL_DIV_EXPR,
- size_binop (PLUS_EXPR,
- DECL_FIELD_BITPOS (tail),
- DECL_SIZE (tail)),
- size_int (BITS_PER_UNIT));
+
+ if (tail)
+ /* Find the offset of the end of that field. */
+ filled = size_binop (CEIL_DIV_EXPR,
+ size_binop (PLUS_EXPR,
+ DECL_FIELD_BITPOS (tail),
+ DECL_SIZE (tail)),
+ size_int (BITS_PER_UNIT));
+ else
+ filled = size_int (0);
+
nextpos_tree = size_binop (CEIL_DIV_EXPR,
DECL_FIELD_BITPOS (next),
size_int (BITS_PER_UNIT));
+
+ TREE_INT_CST_HIGH (constructor_bit_index)
+ = TREE_INT_CST_HIGH (DECL_FIELD_BITPOS (next));
+ TREE_INT_CST_LOW (constructor_bit_index)
+ = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (next));
constructor_unfilled_fields = next;
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
/* Handle superfluous braces around string cst as in
char x[] = {"foo"}; */
if (string_flag
+ && constructor_type
&& TREE_CODE (constructor_type) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE
&& integer_zerop (constructor_unfilled_index))
break;
}
- fieldtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_fields));
+ fieldtype = TREE_TYPE (constructor_fields);
+ if (fieldtype != error_mark_node)
+ fieldtype = TYPE_MAIN_VARIANT (fieldtype);
fieldcode = TREE_CODE (fieldtype);
/* Accept a string constant to initialize a subarray. */
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
}
constructor_fields = TREE_CHAIN (constructor_fields);
+ /* Skip any nameless bit fields at the beginning. */
+ while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ && DECL_NAME (constructor_fields) == 0)
+ constructor_fields = TREE_CHAIN (constructor_fields);
break;
}
if (TREE_CODE (constructor_type) == UNION_TYPE)
break;
}
- fieldtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_fields));
+ fieldtype = TREE_TYPE (constructor_fields);
+ if (fieldtype != error_mark_node)
+ fieldtype = TYPE_MAIN_VARIANT (fieldtype);
fieldcode = TREE_CODE (fieldtype);
/* Accept a string constant to initialize a subarray. */
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE))
/* Otherwise, if we have come to a subaggregate,
and we don't have an element of its type, push into it. */
else if (value != 0 && !constructor_no_implicit
+ && value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
|| eltcode == UNION_TYPE))
break;
}
+ /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
+ if (constructor_range_end)
+ value = save_expr (value);
+
/* Now output the actual element.
Ordinarily, output once.
If there is a range, repeat it till we advance past the range. */
/* If the (lexically) previous elments are not now saved,
we can discard the storage for them. */
- if (constructor_incremental && constructor_pending_elts == 0 && value != 0)
+ if (constructor_incremental && constructor_pending_elts == 0 && value != 0
+ && constructor_stack == 0)
clear_momentary ();
}
\f
else
{
tree type = TREE_TYPE (o[i]);
- if (TYPE_READONLY (type)
+ if (TREE_READONLY (o[i])
+ || TYPE_READONLY (type)
|| ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (type)))
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared `volatile' has a `return' statement");
+ warning ("function declared `noreturn' has a `return' statement");
if (!retval)
{
tree t = convert_for_assignment (valtype, retval, "return",
NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
- t = build (MODIFY_EXPR, TREE_TYPE (res),
- res, convert (TREE_TYPE (res), t));
+ tree inner;
+
+ if (t == error_mark_node)
+ return;
+
+ inner = t = convert (TREE_TYPE (res), t);
+
+ /* Strip any conversions, additions, and subtractions, and see if
+ we are returning the address of a local variable. Warn if so. */
+ while (1)
+ {
+ switch (TREE_CODE (inner))
+ {
+ case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR:
+ case PLUS_EXPR:
+ inner = TREE_OPERAND (inner, 0);
+ continue;
+
+ case MINUS_EXPR:
+ /* If the second operand of the MINUS_EXPR has a pointer
+ type (or is converted from it), this may be valid, so
+ don't give a warning. */
+ {
+ tree op1 = TREE_OPERAND (inner, 1);
+
+ while (! POINTER_TYPE_P (TREE_TYPE (op1))
+ && (TREE_CODE (op1) == NOP_EXPR
+ || TREE_CODE (op1) == NON_LVALUE_EXPR
+ || TREE_CODE (op1) == CONVERT_EXPR))
+ op1 = TREE_OPERAND (op1, 0);
+
+ if (POINTER_TYPE_P (TREE_TYPE (op1)))
+ break;
+
+ inner = TREE_OPERAND (inner, 0);
+ continue;
+ }
+
+ case ADDR_EXPR:
+ inner = TREE_OPERAND (inner, 0);
+
+ while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
+ inner = TREE_OPERAND (inner, 0);
+
+ if (TREE_CODE (inner) == VAR_DECL
+ && ! DECL_EXTERNAL (inner)
+ && ! TREE_STATIC (inner)
+ && DECL_CONTEXT (inner) == current_function_decl)
+ warning ("function returns address of local variable");
+ break;
+ }
+
+ break;
+ }
+
+ t = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_return (t);
current_function_returns_value = 1;