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));
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
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;
/* 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)
{
/* Strip coercion. */
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 0), param_num);
+ TREE_OPERAND (param, 0), param_num,
+ opt);
return;
}
if (i == format_num)
{
check_function_arguments_recurse (callback, ctx,
- inner_arg, param_num);
+ inner_arg, param_num,
+ opt);
found_format_arg = true;
break;
}
/* 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;
}
}
(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<location_t>,
tree, tree, int, tree *);
extern void check_function_format (const_tree, tree, int, tree *,
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;
--- /dev/null
+/* 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 } */
+}