Commit 7e5fb12f by Joseph Myers Committed by Joseph Myers

c-format.c (FMT_FLAG_DOLLAR_GAP_POINTER_OK): New.

	* c-format.c (FMT_FLAG_DOLLAR_GAP_POINTER_OK): New.
	(format_types): Use it for scanf.
	(dollar_arguments_pointer_p): New.
	(init_dollar_format_checking): Store details of which arguments
	are pointers.
	(maybe_read_dollar_number): Reallocate dollar_arguments_pointer_p.
	(finish_dollar_format_checking): Take extra parameter
	pointer_gap_ok.  Treat unused arguments differently if
	pointer_gap_ok and the unused arguments are pointers.
	(check_format_info_main): Pass extra argument to
	finish_dollar_format_checking.
	* doc/invoke.texi (-Wno-format-extra-args): Document behavior when
	unused arguments are present between used arguments with operand
	numbers.

testsuite:
	* gcc.dg/format/strfmon-1.c: Update comments.  Adjust examples
	from Austin Group draft 7.
	* gcc.dg/format/xopen-1.c: Update comments.  Add tests for gaps in
	scanf format arguments.
	* gcc.dg/format/no-exargs-2.c: New test.

From-SVN: r47327
parent a6253d46
2001-11-25 Joseph S. Myers <jsm28@cam.ac.uk>
* c-format.c (FMT_FLAG_DOLLAR_GAP_POINTER_OK): New.
(format_types): Use it for scanf.
(dollar_arguments_pointer_p): New.
(init_dollar_format_checking): Store details of which arguments
are pointers.
(maybe_read_dollar_number): Reallocate dollar_arguments_pointer_p.
(finish_dollar_format_checking): Take extra parameter
pointer_gap_ok. Treat unused arguments differently if
pointer_gap_ok and the unused arguments are pointers.
(check_format_info_main): Pass extra argument to
finish_dollar_format_checking.
* doc/invoke.texi (-Wno-format-extra-args): Document behavior when
unused arguments are present between used arguments with operand
numbers.
2001-11-25 Daniel Berlin <dan@cgsoftware.com> 2001-11-25 Daniel Berlin <dan@cgsoftware.com>
* df.c: Add prototypes for hybrid_search_bitmap and * df.c: Add prototypes for hybrid_search_bitmap and
......
...@@ -374,7 +374,10 @@ enum ...@@ -374,7 +374,10 @@ enum
/* Zero width is bad in this type of format (scanf). */ /* Zero width is bad in this type of format (scanf). */
FMT_FLAG_ZERO_WIDTH_BAD = 32, FMT_FLAG_ZERO_WIDTH_BAD = 32,
/* Empty precision specification is OK in this type of format (printf). */ /* Empty precision specification is OK in this type of format (printf). */
FMT_FLAG_EMPTY_PREC_OK = 64 FMT_FLAG_EMPTY_PREC_OK = 64,
/* Gaps are allowed in the arguments with $ operand numbers if all
arguments are pointers (scanf). */
FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128
/* Not included here: details of whether width or precision may occur /* Not included here: details of whether width or precision may occur
(controlled by width_char and precision_char); details of whether (controlled by width_char and precision_char); details of whether
'*' can be used for these (width_type and precision_type); details '*' can be used for these (width_type and precision_type); details
...@@ -848,7 +851,7 @@ static const format_kind_info format_types[] = ...@@ -848,7 +851,7 @@ static const format_kind_info format_types[] =
}, },
{ "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
scanf_flag_specs, scanf_flag_pairs, scanf_flag_specs, scanf_flag_pairs,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD, FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
'w', 0, 0, '*', 'L', 'w', 0, 0, '*', 'L',
NULL, NULL NULL, NULL
}, },
...@@ -907,7 +910,7 @@ static void init_dollar_format_checking PARAMS ((int, tree)); ...@@ -907,7 +910,7 @@ static void init_dollar_format_checking PARAMS ((int, tree));
static int maybe_read_dollar_number PARAMS ((int *, const char **, int, static int maybe_read_dollar_number PARAMS ((int *, const char **, int,
tree, tree *, tree, tree *,
const format_kind_info *)); const format_kind_info *));
static void finish_dollar_format_checking PARAMS ((int *, format_check_results *)); static void finish_dollar_format_checking PARAMS ((int *, format_check_results *, int));
static const format_flag_spec *get_flag_spec PARAMS ((const format_flag_spec *, static const format_flag_spec *get_flag_spec PARAMS ((const format_flag_spec *,
int, const char *)); int, const char *));
...@@ -1029,6 +1032,7 @@ status_warning VPARAMS ((int *status, const char *msgid, ...)) ...@@ -1029,6 +1032,7 @@ status_warning VPARAMS ((int *status, const char *msgid, ...))
/* Variables used by the checking of $ operand number formats. */ /* Variables used by the checking of $ operand number formats. */
static char *dollar_arguments_used = NULL; static char *dollar_arguments_used = NULL;
static char *dollar_arguments_pointer_p = NULL;
static int dollar_arguments_alloc = 0; static int dollar_arguments_alloc = 0;
static int dollar_arguments_count; static int dollar_arguments_count;
static int dollar_first_arg_num; static int dollar_first_arg_num;
...@@ -1046,6 +1050,8 @@ init_dollar_format_checking (first_arg_num, params) ...@@ -1046,6 +1050,8 @@ init_dollar_format_checking (first_arg_num, params)
int first_arg_num; int first_arg_num;
tree params; tree params;
{ {
tree oparams = params;
dollar_first_arg_num = first_arg_num; dollar_first_arg_num = first_arg_num;
dollar_arguments_count = 0; dollar_arguments_count = 0;
dollar_max_arg_used = 0; dollar_max_arg_used = 0;
...@@ -1062,11 +1068,28 @@ init_dollar_format_checking (first_arg_num, params) ...@@ -1062,11 +1068,28 @@ init_dollar_format_checking (first_arg_num, params)
{ {
if (dollar_arguments_used) if (dollar_arguments_used)
free (dollar_arguments_used); free (dollar_arguments_used);
if (dollar_arguments_pointer_p)
free (dollar_arguments_pointer_p);
dollar_arguments_alloc = dollar_arguments_count; dollar_arguments_alloc = dollar_arguments_count;
dollar_arguments_used = xmalloc (dollar_arguments_alloc); dollar_arguments_used = xmalloc (dollar_arguments_alloc);
dollar_arguments_pointer_p = xmalloc (dollar_arguments_alloc);
} }
if (dollar_arguments_alloc) if (dollar_arguments_alloc)
memset (dollar_arguments_used, 0, dollar_arguments_alloc); {
memset (dollar_arguments_used, 0, dollar_arguments_alloc);
if (first_arg_num > 0)
{
int i = 0;
params = oparams;
while (params)
{
dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
== POINTER_TYPE);
params = TREE_CHAIN (params);
i++;
}
}
}
} }
...@@ -1146,6 +1169,8 @@ maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr, ...@@ -1146,6 +1169,8 @@ maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr,
int nalloc; int nalloc;
nalloc = 2 * dollar_arguments_alloc + 16; nalloc = 2 * dollar_arguments_alloc + 16;
dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc); dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc);
dollar_arguments_pointer_p = xrealloc (dollar_arguments_pointer_p,
nalloc);
memset (dollar_arguments_used + dollar_arguments_alloc, 0, memset (dollar_arguments_used + dollar_arguments_alloc, 0,
nalloc - dollar_arguments_alloc); nalloc - dollar_arguments_alloc);
dollar_arguments_alloc = nalloc; dollar_arguments_alloc = nalloc;
...@@ -1186,21 +1211,32 @@ maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr, ...@@ -1186,21 +1211,32 @@ maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr,
and for unused operands at the end of the format (if we know how many and for unused operands at the end of the format (if we know how many
arguments the format had, so not for vprintf). If there were operand arguments the format had, so not for vprintf). If there were operand
numbers out of range on a non-vprintf-style format, we won't have reached numbers out of range on a non-vprintf-style format, we won't have reached
here. */ here. If POINTER_GAP_OK, unused arguments are OK if all arguments are
pointers. */
static void static void
finish_dollar_format_checking (status, res) finish_dollar_format_checking (status, res, pointer_gap_ok)
int *status; int *status;
format_check_results *res; format_check_results *res;
int pointer_gap_ok;
{ {
int i; int i;
bool found_pointer_gap = false;
for (i = 0; i < dollar_max_arg_used; i++) for (i = 0; i < dollar_max_arg_used; i++)
{ {
if (!dollar_arguments_used[i]) if (!dollar_arguments_used[i])
status_warning (status, "format argument %d unused before used argument %d in $-style format", {
i + 1, dollar_max_arg_used); if (pointer_gap_ok && (dollar_first_arg_num == 0
|| dollar_arguments_pointer_p[i]))
found_pointer_gap = true;
else
status_warning (status, "format argument %d unused before used argument %d in $-style format",
i + 1, dollar_max_arg_used);
}
} }
if (dollar_first_arg_num && dollar_max_arg_used < dollar_arguments_count) if (found_pointer_gap
|| (dollar_first_arg_num
&& dollar_max_arg_used < dollar_arguments_count))
{ {
res->number_other--; res->number_other--;
res->number_dollar_extra_args++; res->number_dollar_extra_args++;
...@@ -1639,7 +1675,7 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -1639,7 +1675,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
res->number_extra_args++; res->number_extra_args++;
} }
if (has_operand_number > 0) if (has_operand_number > 0)
finish_dollar_format_checking (status, res); finish_dollar_format_checking (status, res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
return; return;
} }
if (*format_chars++ != '%') if (*format_chars++ != '%')
......
...@@ -1849,6 +1849,14 @@ If @option{-Wformat} is specified, do not warn about excess arguments to a ...@@ -1849,6 +1849,14 @@ If @option{-Wformat} is specified, do not warn about excess arguments to a
@code{printf} or @code{scanf} format function. The C standard specifies @code{printf} or @code{scanf} format function. The C standard specifies
that such arguments are ignored. that such arguments are ignored.
Where the unused arguments lie between used arguments that are
specified with @samp{$} operand number specifications, normally
warnings are still given, since the implementation could not know what
type to pass to @code{va_arg} to skip the unused arguments. However,
in the case of @code{scanf} formats, this option will suppress the
warning if the unused arguments are all pointers, since the Single
Unix Specification says that such unused arguments are allowed.
@item -Wformat-nonliteral @item -Wformat-nonliteral
@opindex Wformat-nonliteral @opindex Wformat-nonliteral
If @option{-Wformat} is specified, also warn if the format string is not a If @option{-Wformat} is specified, also warn if the format string is not a
......
2001-11-25 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/format/strfmon-1.c: Update comments. Adjust examples
from Austin Group draft 7.
* gcc.dg/format/xopen-1.c: Update comments. Add tests for gaps in
scanf format arguments.
* gcc.dg/format/no-exargs-2.c: New test.
2001-11-25 Nathan Sidwell <nathan@codesourcery.com> 2001-11-25 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/abi/vbase8-4.C: New test. * g++.dg/abi/vbase8-4.C: New test.
......
/* Test for warnings for extra format arguments being disabled by
-Wno-format-extra-args. Test which warnings still apply with $
operand numbers. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
#include "format.h"
void
foo (int i, int *ip, va_list va)
{
printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
printf ("%2$d%1$d", i, i, i);
vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
/* With scanf formats, gaps in the used arguments are allowed only if the
arguments are all pointers. In such a case, should only give the lesser
warning about unused arguments rather than the more serious one about
argument gaps. */
scanf ("%3$d%1$d", ip, ip, ip);
/* If there are non-pointer arguments unused at the end, this is also OK. */
scanf ("%3$d%1$d", ip, ip, ip, i);
scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
/* Can't check the arguments in the vscanf case, so should suppose the
lesser problem. */
vscanf ("%3$d%1$d", va);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
void void
foo (char *s, size_t m, double d, long double ld) foo (char *s, size_t m, double d, long double ld)
{ {
/* Examples of valid formats from Austin Group draft 5. */ /* Examples of valid formats from Austin Group draft 7. */
strfmon (s, m, "%n", d); strfmon (s, m, "%n", d);
strfmon (s, m, "%11n", d); strfmon (s, m, "%11n", d);
strfmon (s, m, "%#5n", d); strfmon (s, m, "%#5n", d);
...@@ -18,7 +18,9 @@ foo (char *s, size_t m, double d, long double ld) ...@@ -18,7 +18,9 @@ foo (char *s, size_t m, double d, long double ld)
strfmon (s, m, "%^#5.0n", d); strfmon (s, m, "%^#5.0n", d);
strfmon (s, m, "%^#5.4n", d); strfmon (s, m, "%^#5.4n", d);
strfmon (s, m, "%(#5n", d); strfmon (s, m, "%(#5n", d);
strfmon (s, m, "%(!#5n", d); strfmon (s, m, "%!(#5n", d);
strfmon (s, m, "%-14#5.4n", d);
strfmon (s, m, "%14#5.4n", d);
/* Some more valid formats, including the GNU L length extension. */ /* Some more valid formats, including the GNU L length extension. */
strfmon (s, m, "abc%-11ndef%==i%%", d, d); strfmon (s, m, "abc%-11ndef%==i%%", d, d);
strfmon (s, m, "%%abc%-11ndef%==Li%=%i", d, ld, d); strfmon (s, m, "%%abc%-11ndef%==Li%=%i", d, ld, d);
...@@ -31,7 +33,9 @@ foo (char *s, size_t m, double d, long double ld) ...@@ -31,7 +33,9 @@ foo (char *s, size_t m, double d, long double ld)
strfmon (s, m, "%^#5.0Li", ld); strfmon (s, m, "%^#5.0Li", ld);
strfmon (s, m, "%^#5.4Li", ld); strfmon (s, m, "%^#5.4Li", ld);
strfmon (s, m, "%(#5Li", ld); strfmon (s, m, "%(#5Li", ld);
strfmon (s, m, "%(!#5Li", ld); strfmon (s, m, "%!(#5Li", ld);
strfmon (s, m, "%-14#5.4Li", ld);
strfmon (s, m, "%14#5.4Li", ld);
/* Formats with the wrong types used. */ /* Formats with the wrong types used. */
strfmon (s, m, "%Ln", d); /* { dg-warning "format" "wrong type" } */ strfmon (s, m, "%Ln", d); /* { dg-warning "format" "wrong type" } */
strfmon (s, m, "%n", ld); /* { dg-warning "format" "wrong type" } */ strfmon (s, m, "%n", ld); /* { dg-warning "format" "wrong type" } */
......
/* Test for X/Open format extensions, as found in the /* Test for X/Open format extensions, as found in the
Single Unix Specification and in Austin Group draft 4, subject to some Single Unix Specification and in Austin Group draft 7.
Aardvark problem reports approved as changes.
*/ */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */ /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */ /* { dg-do compile } */
...@@ -88,10 +87,6 @@ foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d, ...@@ -88,10 +87,6 @@ foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d,
printf ("%'p", p); /* { dg-warning "flag" "bad use of ' flag" } */ printf ("%'p", p); /* { dg-warning "flag" "bad use of ' flag" } */
printf ("%'n", n); /* { dg-warning "flag" "bad use of ' flag" } */ printf ("%'n", n); /* { dg-warning "flag" "bad use of ' flag" } */
/* The use of operand number $ formats is an X/Open extension. */ /* The use of operand number $ formats is an X/Open extension. */
/* Banning gaps in the arguments used with scanf was covered in Aardvark
report XSHd4 ERN 164, which was rejected, but implementation without
such a ban still isn't possible within ISO C.
*/
scanf ("%1$d", ip); scanf ("%1$d", ip);
printf ("%1$d", i); printf ("%1$d", i);
printf ("%1$d", l); /* { dg-warning "arg 2" "mismatched args with $ format" } */ printf ("%1$d", l); /* { dg-warning "arg 2" "mismatched args with $ format" } */
...@@ -110,6 +105,20 @@ foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d, ...@@ -110,6 +105,20 @@ foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d,
printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */ printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
printf ("%2$d%1$d", i, i, i); /* { dg-warning "unused" "unused $ operand" } */ printf ("%2$d%1$d", i, i, i); /* { dg-warning "unused" "unused $ operand" } */
vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */ vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
/* With scanf formats, gaps in the used arguments are allowed only if the
arguments are all pointers. In such a case, should only give the lesser
warning about unused arguments rather than the more serious one about
argument gaps. */
scanf ("%3$d%1$d", ip, ip, ip); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
/* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 112 } */
/* If there are non-pointer arguments unused at the end, this is also OK. */
scanf ("%3$d%1$d", ip, ip, ip, i); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
/* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 115 } */
scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
/* Can't check the arguments in the vscanf case, so should suppose the
lesser problem. */
vscanf ("%3$d%1$d", va); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
/* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 120 } */
scanf ("%2$*d%1$d", ip, ip); /* { dg-warning "operand" "operand number with suppression" } */ scanf ("%2$*d%1$d", ip, ip); /* { dg-warning "operand" "operand number with suppression" } */
printf ("%1$d%1$d", i); printf ("%1$d%1$d", i);
scanf ("%1$d%1$d", ip); /* { dg-warning "more than once" "multiple use of scanf argument" } */ scanf ("%1$d%1$d", ip); /* { dg-warning "more than once" "multiple use of scanf argument" } */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment