--- /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;