diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index f56f6df8fe3..bf0749bf498 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -5592,7 +5592,7 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) firstarg = 1; if (!closure) check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[0], - firstarg); + firstarg, OPT_Wnonnull); } tree attrs = lookup_attribute ("nonnull", TYPE_ATTRIBUTES (ctx.fntype)); @@ -5611,7 +5611,7 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) if (a != NULL_TREE) for (int i = firstarg; i < nargs; i++) check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[i], - i + 1); + i + 1, OPT_Wnonnull); else { /* Walk the argument list. If we encounter an argument number we @@ -5627,7 +5627,8 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) if (a != NULL_TREE) check_function_arguments_recurse (check_nonnull_arg, &ctx, - argarray[i], i + 1); + argarray[i], i + 1, + OPT_Wnonnull); } } return ctx.warned_p; @@ -6095,14 +6096,16 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, /* Generic argument checking recursion routine. PARAM is the argument to be checked. PARAM_NUM is the number of the argument. CALLBACK is invoked - once the argument is resolved. CTX is context for the callback. */ + once the argument is resolved. CTX is context for the callback. + OPT is the warning for which this is done. */ void check_function_arguments_recurse (void (*callback) (void *, tree, unsigned HOST_WIDE_INT), void *ctx, tree param, - unsigned HOST_WIDE_INT param_num) + unsigned HOST_WIDE_INT param_num, + opt_code opt) { - if (warning_suppressed_p (param)) + if (opt != OPT_Wformat_ && warning_suppressed_p (param)) return; if (CONVERT_EXPR_P (param) @@ -6111,7 +6114,8 @@ check_function_arguments_recurse (void (*callback) { /* Strip coercion. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 0), param_num); + TREE_OPERAND (param, 0), param_num, + opt); return; } @@ -6148,7 +6152,8 @@ check_function_arguments_recurse (void (*callback) if (i == format_num) { check_function_arguments_recurse (callback, ctx, - inner_arg, param_num); + inner_arg, param_num, + opt); found_format_arg = true; break; } @@ -6170,10 +6175,10 @@ check_function_arguments_recurse (void (*callback) /* Check both halves of the conditional expression. */ check_function_arguments_recurse (callback, ctx, TREE_OPERAND (param, 1), - param_num); + param_num, opt); check_function_arguments_recurse (callback, ctx, TREE_OPERAND (param, 2), - param_num); + param_num, opt); return; } } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 28c73fe2847..a8d6f82bb2c 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -853,7 +853,8 @@ extern void check_function_arguments_recurse (void (*) (void *, tree, unsigned HOST_WIDE_INT), void *, tree, - unsigned HOST_WIDE_INT); + unsigned HOST_WIDE_INT, + opt_code); extern bool check_builtin_function_arguments (location_t, vec, tree, tree, int, tree *); extern void check_function_format (const_tree, tree, int, tree *, diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc index a2affdacd7c..98f28c0dcc6 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -1531,7 +1531,7 @@ check_format_info (function_format_info *info, tree params, format_ctx.arglocs = arglocs; check_function_arguments_recurse (check_format_arg, &format_ctx, - format_tree, arg_num); + format_tree, arg_num, OPT_Wformat_); location_t loc = format_ctx.res->format_string_loc; diff --git a/gcc/testsuite/c-c++-common/Wformat-pr104148.c b/gcc/testsuite/c-c++-common/Wformat-pr104148.c new file mode 100644 index 00000000000..6786463bf66 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wformat-pr104148.c @@ -0,0 +1,33 @@ +/* PR c++/104148 */ +/* { dg-do compile } */ +/* { dg-options "-Wformat" } */ + +char *foo (const char *) __attribute__((format_arg(1))); +void bar (const char *, ...) __attribute__((format(printf, 1, 2))); + +void +baz (int x) +{ + bar ("%ld", x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar (x ? "%ld" : "%ld", x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar (x ? "%ld" : "%lld", x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ + bar (foo ("%ld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar (x ? foo ("%ld") : "%ld", x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar (x ? foo ("%ld") : "%lld", x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ + bar (foo (x ? "%ld" : "%ld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar (foo (x ? "%ld" : "%lld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ + bar (("%ld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar ((x ? "%ld" : "%ld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar ((x ? "%ld" : "%lld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ + bar ((foo ("%ld")), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar ((x ? foo ("%ld") : "%ld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar ((x ? foo ("%ld") : "%lld"), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ + bar ((foo (x ? "%ld" : "%ld")), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + bar ((foo (x ? "%ld" : "%lld")), x); /* { dg-warning "format '%ld' expects argument of type 'long int', but argument 2 has type 'int'" } */ + /* { dg-warning "format '%lld' expects argument of type 'long long int', but argument 2 has type 'int'" "" { target *-*-* } .-1 } */ +}