--- /usr/src/contrib/gcc/c-common.c Wed Jul 28 05:40:54 2004 +++ /usr/src/contrib/gcc/c-common.c Fri Apr 1 13:40:08 2005 @@ -330,6 +330,10 @@ int warn_format; +/* Warn about printf/scanf/strftime/strfmon format string anomalies before implicit varargs promotion */ + +bool warn_format_pre_promo; + /* Warn about Y2K problems with strftime formats. */ int warn_format_y2k; @@ -777,8 +781,8 @@ bool *); static tree vector_size_helper (tree, tree); -static void check_function_nonnull (tree, tree); -static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); +static void check_function_nonnull (tree, tree, int); +static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT, int); static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); static int resort_field_decl_cmp (const void *, const void *); @@ -5378,7 +5382,7 @@ that are marked as requiring a non-null pointer argument. */ static void -check_function_nonnull (tree attrs, tree params) +check_function_nonnull (tree attrs, tree params, int pre_promo) { tree a, args, param; int param_num; @@ -5401,7 +5405,7 @@ if (! args || nonnull_check_p (args, param_num)) check_function_arguments_recurse (check_nonnull_arg, NULL, TREE_VALUE (param), - param_num); + param_num, pre_promo); } } } @@ -5433,7 +5437,7 @@ static void check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param, - unsigned HOST_WIDE_INT param_num) + unsigned HOST_WIDE_INT param_num, int pre_promo) { /* Just skip checking the argument if it's not a pointer. This can happen if the "nonnull" attribute was given without an operand @@ -5551,18 +5555,18 @@ /* Check for valid arguments being passed to a function. */ void -check_function_arguments (tree attrs, tree params) +check_function_arguments (tree attrs, tree params, int pre_promo) { /* Check for null being passed in a pointer argument that must be non-null. We also need to do this if format checking is enabled. */ if (warn_nonnull) - check_function_nonnull (attrs, params); + check_function_nonnull (attrs, params, pre_promo); /* Check for errors in format strings. */ if (warn_format) - check_function_format (NULL, attrs, params); + check_function_format (NULL, attrs, params, pre_promo); } /* Generic argument checking recursion routine. PARAM is the argument to @@ -5570,15 +5574,16 @@ once the argument is resolved. CTX is context for the callback. */ void check_function_arguments_recurse (void (*callback) - (void *, tree, unsigned HOST_WIDE_INT), + (void *, tree, unsigned HOST_WIDE_INT, int), void *ctx, tree param, - unsigned HOST_WIDE_INT param_num) + unsigned HOST_WIDE_INT param_num, + int pre_promo) { if (TREE_CODE (param) == NOP_EXPR) { /* Strip coercion. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 0), param_num); + TREE_OPERAND (param, 0), param_num, pre_promo); return; } @@ -5623,7 +5628,7 @@ { check_function_arguments_recurse (callback, ctx, TREE_VALUE (inner_args), - param_num); + param_num, pre_promo); found_format_arg = true; break; } @@ -5640,13 +5645,13 @@ { /* Check both halves of the conditional expression. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 1), param_num); + TREE_OPERAND (param, 1), param_num, pre_promo); check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 2), param_num); + TREE_OPERAND (param, 2), param_num, pre_promo); return; } - (*callback) (ctx, param, param_num); + (*callback) (ctx, param, param_num, pre_promo); } /* Function to help qsort sort FIELD_DECLs by name order. */ --- /usr/src/contrib/gcc/c-common.h Wed Jul 28 05:46:02 2004 +++ /usr/src/contrib/gcc/c-common.h Fri Apr 1 13:40:44 2005 @@ -881,14 +881,15 @@ extern const char *fname_as_string (int); extern tree fname_decl (unsigned, tree); -extern void check_function_arguments (tree, tree); +extern void check_function_arguments (tree, tree, int); extern void check_function_arguments_recurse (void (*) (void *, tree, - unsigned HOST_WIDE_INT), + unsigned HOST_WIDE_INT, int), void *, tree, - unsigned HOST_WIDE_INT); -extern void check_function_format (int *, tree, tree); + unsigned HOST_WIDE_INT, int); +extern void check_function_format (int *, tree, tree, int); extern void set_Wformat (int); +extern void set_Wformat_pre_promo (int); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); extern int c_common_handle_option (size_t code, const char *arg, int value); @@ -1239,6 +1240,7 @@ extern tree build_binary_op (enum tree_code, tree, tree, int); extern int lvalue_p (tree); extern tree default_conversion (tree); +extern tree default_conversion_no_promo (tree); /* Given two integer or real types, return the type for their sum. Given two compatible ANSI C types, returns the merged type. */ --- /usr/src/contrib/gcc/c-format.c Thu Mar 31 12:01:22 2005 +++ /usr/src/contrib/gcc/c-format.c Fri Apr 1 13:00:30 2005 @@ -32,6 +32,7 @@ #include "intl.h" #include "diagnostic.h" #include "langhooks.h" + /* Set format warning options according to a -Wformat=n option. */ @@ -62,6 +63,7 @@ gcc_cxxdiag_format_type, scanf_format_type, strftime_format_type, strfmon_format_type, rintf0_format_type, + printf_pre_promo_type, format_type_error }; typedef struct function_format_info @@ -71,8 +73,8 @@ unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ } function_format_info; -static bool decode_format_attr (tree, function_format_info *, int); -static enum format_type decode_format_type (const char *); +static bool decode_format_attr (tree, function_format_info *, int, int); +static enum format_type decode_format_type (const char *, int pre_promo); static bool check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, @@ -179,7 +181,7 @@ successfully decoded, false otherwise. */ static bool -decode_format_attr (tree args, function_format_info *info, int validated_p) +decode_format_attr (tree args, function_format_info *info, int validated_p, int pre_promo) { tree format_type_id = TREE_VALUE (args); tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); @@ -197,7 +199,7 @@ { const char *p = IDENTIFIER_POINTER (format_type_id); - info->format_type = decode_format_type (p); + info->format_type = decode_format_type (p, pre_promo); if (info->format_type == format_type_error) { @@ -791,6 +793,41 @@ { NULL, 0, 0, NOLENGTHS, NULL, NULL } }; +static const format_char_info pre_promo_print_char_table[] = +{ + /* C89 conversion specifiers. */ + { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-wp0 +'I", "i" }, + { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i" }, + { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i" }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "" }, + { "c", 0, STD_C89, { T89_C, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c" }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, + /* C99 conversion specifiers. */ + { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" }, + /* X/Open conversion specifiers. */ + { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R" }, + /* GNU conversion specifiers. */ + { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" }, + /* BSD conversion specifiers. */ + /* FreeBSD kernel extensions (src/sys/kern/subr_prf.c). + The format %b is supported to decode error registers. + Its usage is: printf("reg=%b\n", regval, "*"); + which produces: reg=3 + The format %D provides a hexdump given a pointer and separator string: + ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + ("%*D", len, ptr, " ") -> XX XX XX XX ... + */ + { "D", 1, STD_EXT, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, + { "b", 1, STD_EXT, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" }, + { "ry", 0, STD_EXT, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "i" }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL } +}; + static const format_char_info asm_fprintf_char_table[] = { /* C89 conversion specifiers. */ @@ -988,7 +1025,13 @@ FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, 'w', 0, 'p', 0, 'L', &integer_type_node, &integer_type_node, 1 - } + }, + { "printf_pre_promo", printf_length_specs, pre_promo_print_char_table, " +#0-'I", NULL, + printf_flag_specs, printf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 'p', 0, 'L', + &integer_type_node, &integer_type_node, 0 + }, }; /* This layer of indirection allows GCC to reassign format_types with @@ -1033,12 +1076,12 @@ int *status; } format_check_context; -static void check_format_info (int *, function_format_info *, tree); -static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); +static void check_format_info (int *, function_format_info *, tree, int); +static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT, int); static void check_format_info_main (int *, format_check_results *, function_format_info *, const char *, int, tree, - unsigned HOST_WIDE_INT); + unsigned HOST_WIDE_INT, int); static void status_warning (int *, const char *, ...) ATTRIBUTE_PRINTF_2; @@ -1050,13 +1093,13 @@ static const format_flag_spec *get_flag_spec (const format_flag_spec *, int, const char *); -static void check_format_types (int *, format_wanted_type *); +static void check_format_types (int *, format_wanted_type *, int); /* Decode a format type from a string, returning the type, or format_type_error if not valid, in which case the caller should print an error message. */ static enum format_type -decode_format_type (const char *s) +decode_format_type (const char *s, int pre_promo) { int i; int slen; @@ -1064,6 +1107,11 @@ for (i = 0; i < (int) format_type_error; i++) { int alen; + if (pre_promo && !strcmp (s, "printf")) + { + if (!strcmp(format_types[i].name, "printf_pre_promo")) + break; + } if (!strcmp (s, format_types[i].name)) break; alen = strlen (format_types[i].name); @@ -1083,7 +1131,7 @@ attribute themselves. */ void -check_function_format (int *status, tree attrs, tree params) +check_function_format (int *status, tree attrs, tree params, int pre_promo) { tree a; @@ -1094,8 +1142,8 @@ { /* Yup; check it. */ function_format_info info; - decode_format_attr (TREE_VALUE (a), &info, 1); - check_format_info (status, &info, params); + decode_format_attr (TREE_VALUE (a), &info, 1, pre_promo); + check_format_info (status, &info, params, pre_promo); if (warn_missing_format_attribute && info.first_arg_num == 0 && (format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) @@ -1106,7 +1154,8 @@ c = TREE_CHAIN (c)) if (is_attribute_p ("format", TREE_PURPOSE (c)) && (decode_format_type (IDENTIFIER_POINTER - (TREE_VALUE (TREE_VALUE (c)))) + (TREE_VALUE (TREE_VALUE (c))), + pre_promo) == info.format_type)) break; if (c == NULL_TREE) @@ -1401,8 +1450,9 @@ PARAMS is the list of argument values. */ static void -check_format_info (int *status, function_format_info *info, tree params) +check_format_info (int *status, function_format_info *info, tree params, int pre_promo) { + format_check_context format_ctx; unsigned HOST_WIDE_INT arg_num; tree format_tree; @@ -1436,7 +1486,7 @@ format_ctx.status = status; check_function_arguments_recurse (check_format_arg, &format_ctx, - format_tree, arg_num); + format_tree, arg_num, pre_promo); if (res.number_non_literal > 0) { @@ -1500,7 +1550,7 @@ static void check_format_arg (void *ctx, tree format_tree, - unsigned HOST_WIDE_INT arg_num) + unsigned HOST_WIDE_INT arg_num, int pre_promo) { format_check_context *format_ctx = ctx; format_check_results *res = format_ctx->res; @@ -1653,7 +1703,7 @@ need not adjust it for every return. */ res->number_other++; check_format_info_main (status, res, info, format_chars, format_length, - params, arg_num); + params, arg_num, pre_promo); } @@ -1668,7 +1718,8 @@ check_format_info_main (int *status, format_check_results *res, function_format_info *info, const char *format_chars, int format_length, tree params, - unsigned HOST_WIDE_INT arg_num) + unsigned HOST_WIDE_INT arg_num, + int pre_promo) { const char *orig_format_chars = format_chars; tree first_fillin_param = params; @@ -1681,6 +1732,11 @@ and it didn't use $; 1 if $ formats are in use. */ int has_operand_number = -1; + if (pre_promo && info->format_type == printf_format_type) + { + fki = &format_types[printf_pre_promo_type]; + } + init_dollar_format_checking (info->first_arg_num, first_fillin_param); while (1) @@ -2333,7 +2389,7 @@ } if (first_wanted_type != 0) - check_format_types (status, first_wanted_type); + check_format_types (status, first_wanted_type, pre_promo); } } @@ -2342,14 +2398,14 @@ /* Check the argument types from a single format conversion (possibly including width and precision arguments). */ static void -check_format_types (int *status, format_wanted_type *types) +check_format_types (int *status, format_wanted_type *types, int pre_promo) { for (; types != 0; types = types->next) { tree cur_param; tree cur_type; tree orig_cur_type; - tree wanted_type; + tree wanted_type, wanted_type_promot; int arg_num; int i; int char_type_flag; @@ -2368,7 +2424,14 @@ abort (); if (types->pointer_count == 0) - wanted_type = (*lang_hooks.types.type_promotes_to) (wanted_type); + { + wanted_type_promot = (*lang_hooks.types.type_promotes_to) (wanted_type); + if (!pre_promo) + { + wanted_type = wanted_type_promot; + } + } else + wanted_type_promot = wanted_type; STRIP_NOPS (cur_param); @@ -2469,29 +2532,100 @@ -pedantic. With -pedantic, warn if the type is a pointer target and not a character type, and for character types at a second level of indirection. */ - if (TREE_CODE (wanted_type) == INTEGER_TYPE +#if 0 + if ((1 || !pre_promo) && + TREE_CODE (wanted_type) == INTEGER_TYPE && TREE_CODE (cur_type) == INTEGER_TYPE && (! pedantic || i == 0 || (i == 1 && char_type_flag)) && (TREE_UNSIGNED (wanted_type) ? wanted_type == c_common_unsigned_type (cur_type) - : wanted_type == c_common_signed_type (cur_type))) + : wanted_type == c_common_signed_type (cur_type)) + && !pre_promo) continue; /* Likewise, "signed char", "unsigned char" and "char" are equivalent but the above test won't consider them equivalent. */ - if (wanted_type == char_type_node + if ((1 || !pre_promo) + && wanted_type == char_type_node && (! pedantic || i < 2) - && char_type_flag) + && char_type_flag && !pre_promo) continue; +#else + if (TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (cur_type) == INTEGER_TYPE + && (!pre_promo || i == 0 || (i == 1 && char_type_flag)) + && (TREE_UNSIGNED (wanted_type) + ? wanted_type == c_common_unsigned_type (cur_type) + : wanted_type == c_common_signed_type (cur_type))) + + { + if (!pre_promo) + continue; + else + if ((wanted_type == char_type_node || wanted_type == signed_char_type_node) + && (cur_type == char_type_node || cur_type == signed_char_type_node)) + continue; +#ifdef PRE_PROMO_DEBUG + else + status_warning (status, "Would've OK'd 1 if not pre_promo here"); +#endif /* PRE_PROMO_DEBUG */ + } + /* Likewise, "signed char", "unsigned char" and "char" are + equivalent but the above test won't consider them equivalent. */ + if (wanted_type == char_type_node + && (!pre_promo || i < 2) + && char_type_flag) + { + if (!pre_promo) + continue; +#ifdef PRE_PROMO_DEBUG + else + status_warning (status, "Would've OK'd 2 if not pre_promo here"); +#endif /* PRE_PROMO_DEBUG */ + } +#endif /* Now we have a type mismatch. */ { - const char *this; - const char *that; + const char *this = "undetermined type"; + const char *that = this; + const char *wtps = this; + const char *cts = this; tree tmp; + tmp = TYPE_NAME (wanted_type_promot); + if (tmp) + { + if (TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + wtps = IDENTIFIER_POINTER (tmp); + } + else if (TREE_CODE (wanted_type_promot) == POINTER_TYPE) + wtps = "undetermined pointer type"; + else if (TREE_CODE (wanted_type_promot) == ENUMERAL_TYPE) + wtps = "undetermined enumeral type"; + + tmp = TYPE_NAME (cur_type); + if (tmp) + { + if (TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + cts = IDENTIFIER_POINTER (tmp); + } + else if (TREE_CODE (cur_type) == POINTER_TYPE) + cts = "undetermined pointer type"; + else if (TREE_CODE (cur_type) == ENUMERAL_TYPE) + cts = "undetermined enumeral type"; + tmp = TYPE_NAME (wanted_type); - if (TREE_CODE (tmp) == TYPE_DECL) - tmp = DECL_NAME (tmp); - this = IDENTIFIER_POINTER (tmp); + if (tmp) + { + if (TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + this = IDENTIFIER_POINTER (tmp); + } + else if (TREE_CODE (wanted_type) == POINTER_TYPE) + this = "undetermined pointer type"; + else if (TREE_CODE (wanted_type) == ENUMERAL_TYPE) + this = "undetermined enumeral type"; that = 0; if (TYPE_NAME (orig_cur_type) != 0 @@ -2534,11 +2668,25 @@ if (types->wanted_type_name != 0 && strcmp (types->wanted_type_name, that) != 0) this = types->wanted_type_name; +#ifndef PRE_PROMO_DEBUG if (types->name != 0) - status_warning (status, "%s is not type %s (arg %d)", types->name, this, - arg_num); + status_warning (status, "%s is not type %s (arg %d)%s", + types->name, this, arg_num, (pre_promo) ? " (1st pass)" : " (2nd pass)"); else - status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num); + status_warning (status, "%s format, %s arg (arg %d)%s", + this, (pre_promo) ? cts : that, arg_num, (pre_promo) ? " (1st pass)" : " (2nd pass)"); +#else /* ! PRE_PROMO_DEBUG */ + if (types->name != 0) + status_warning (status, "%s is not type %s (arg %d) (pp: %d)", types->name, this, + arg_num, pre_promo); + else + status_warning (status, "%s format, %s arg (arg %d) (pp: %d)", this, (pre_promo) ? cts : that, arg_num, pre_promo); + + status_warning (status, "cur_type <%s>, origcurtype <%s> (pp: %d)", + cts, that, pre_promo); + status_warning (status, "wanted_type_prom <%s>, wanted_type <%s> (pp: %d)", + wtps, this, pre_promo); +#endif /* ! PRE_PROMO_DEBUG */ } } } @@ -2758,7 +2906,7 @@ function_format_info info; tree argument; - if (!decode_format_attr (args, &info, 0)) + if (!decode_format_attr (args, &info, 0, 0)) { *no_add_attrs = true; return NULL_TREE; --- /usr/src/contrib/gcc/c-opts.c Mon Mar 28 14:32:42 2005 +++ /usr/src/contrib/gcc/c-opts.c Fri Apr 1 13:41:47 2005 @@ -454,6 +454,10 @@ set_Wformat (value); break; + case OPT_Wformat_pre_promo: + warn_format_pre_promo = value; + break; + case OPT_Wformat_: set_Wformat (atoi (arg)); break; --- /usr/src/contrib/gcc/c-typeck.c Wed Jul 28 05:11:33 2004 +++ /usr/src/contrib/gcc/c-typeck.c Fri Apr 1 13:25:42 2005 @@ -61,7 +61,7 @@ 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 convert_arguments (tree, tree, tree, tree, int); static tree pointer_diff (tree, tree); static tree unary_complex_lvalue (enum tree_code, tree, int); static void pedantic_lvalue_warning (enum tree_code); @@ -1134,6 +1134,78 @@ /* Perform default promotions for C data used in expressions. Arrays and functions are converted to pointers; + enumeral types to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion_no_promo (tree exp) +{ + tree orig_exp; + tree type = TREE_TYPE (exp); + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE || code == ARRAY_TYPE) + return default_function_array_conversion (exp); + + /* Constants can be used directly unless they're not loadable. */ + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + + /* Replace a nonvolatile const static variable with its value unless + it is an array, in which case we must be sure that taking the + address of the array produces consistent results. */ + else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE) + { + exp = decl_constant_value_for_broken_optimization (exp); + type = TREE_TYPE (exp); + } + + /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as + an lvalue. + + Do not use STRIP_NOPS here! It will remove conversions from pointer + to integer and cause infinite recursion. */ + orig_exp = exp; + while (TREE_CODE (exp) == NON_LVALUE_EXPR + || (TREE_CODE (exp) == NOP_EXPR + && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp))) + exp = TREE_OPERAND (exp, 0); + + /* Preserve the original expression code. */ + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp)))) + C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp)); + + /* Normally convert enums to int, + but convert wide enums to something wider. */ + if (code == ENUMERAL_TYPE) + { + type = c_common_type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node)) + && TREE_UNSIGNED (type))); + + return convert (type, exp); + } + + if (TREE_CODE (exp) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)) + /* If it's thinner than an int, promote it like a + c_promoting_integer_type_p, otherwise leave it alone. */ + && 0 > compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), + TYPE_PRECISION (integer_type_node))) + return convert (integer_type_node, exp); + + if (code == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + return exp; +} + +/* Perform default promotions for C data used in expressions. + Arrays and functions are converted to pointers; enumeral types or short or char, to int. In addition, manifest constants symbols are replaced by their values. */ @@ -1749,15 +1821,28 @@ } } + if (warn_format_pre_promo) + { + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + coerced_params + = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl, 1); + + /* Check that the arguments to the function are valid. (pre_promo=1) */ + + check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params, 1); + } + /* Convert the parameters to the types declared in the function prototype, or apply default promotions. */ coerced_params - = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl); + = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl, 0); - /* Check that the arguments to the function are valid. */ + /* Check that the arguments to the function are valid. (pre_promo=0) */ - check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params); + check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params, 0); /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c @@ -1813,7 +1898,7 @@ with the elements of the list in the TREE_VALUE slots of those nodes. */ static tree -convert_arguments (tree typelist, tree values, tree name, tree fundecl) +convert_arguments (tree typelist, tree values, tree name, tree fundecl, int pre_promo) { tree typetail, valtail; tree result = NULL; @@ -1955,14 +2040,19 @@ } result = tree_cons (NULL_TREE, parmval, result); } - else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE - && (TYPE_PRECISION (TREE_TYPE (val)) - < TYPE_PRECISION (double_type_node))) - /* Convert `float' to `double'. */ - result = tree_cons (NULL_TREE, convert (double_type_node, val), result); + else if (!pre_promo && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (val)) + < TYPE_PRECISION (double_type_node))) + /* Convert `float' to `double'. */ + result = tree_cons (NULL_TREE, convert (double_type_node, val), result); else - /* Convert `short' and `char' to full-size `int'. */ - result = tree_cons (NULL_TREE, default_conversion (val), result); + { + /* Convert `short' and `char' to full-size `int'. */ + if (pre_promo) + result = tree_cons (NULL_TREE, default_conversion_no_promo (val), result); + else + result = tree_cons (NULL_TREE, default_conversion (val), result); + } if (typetail) typetail = TREE_CHAIN (typetail); --- /usr/src/contrib/gcc/c.opt Fri Apr 1 13:16:45 2005 +++ /usr/src/contrib/gcc/c.opt Fri Apr 1 13:16:49 2005 @@ -218,6 +218,10 @@ C ObjC C++ ObjC++ Warn about printf/scanf/strftime/strfmon format string anomalies +Wformat-pre-promo +C +Warn about printf/scanf/strftime/strfmon format string anomalies before implicit varargs promotion + Wformat-extra-args C ObjC C++ ObjC++ Warn if passing too many arguments to a function for its format string --- /usr/src/contrib/gcc/cp/call.c Wed Jul 28 05:11:34 2004 +++ /usr/src/contrib/gcc/cp/call.c Fri Apr 1 13:00:30 2005 @@ -4516,7 +4516,7 @@ if (warn_format) check_function_format (NULL, TYPE_ATTRIBUTES (TREE_TYPE (fn)), - converted_args); + converted_args, 0); /* Avoid actually calling copy constructors and copy assignment operators, if possible. */ --- /usr/src/contrib/gcc/cp/typeck.c Wed Jul 28 05:11:34 2004 +++ /usr/src/contrib/gcc/cp/typeck.c Fri Apr 1 13:00:30 2005 @@ -2484,7 +2484,7 @@ /* Check for errors in format strings. */ if (warn_format) - check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params); + check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params, 0); /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c --- /usr/src/contrib/gcc/flags.h Thu Jul 29 11:31:21 2004 +++ /usr/src/contrib/gcc/flags.h Fri Apr 1 13:40:23 2005 @@ -115,6 +115,10 @@ extern bool warn_inline; +/* Warn about printf/scanf/strftime/strfmon format string anomalies before implicit varargs promotion */ + +extern bool warn_format_pre_promo; + /* Nonzero to warn about variables used before they are initialized. */ extern int warn_uninitialized;