Commit fc6df7e1 by Joseph Myers Committed by Joseph Myers

c-common.c (check_format_info): Properly save the argument number and parameter…

c-common.c (check_format_info): Properly save the argument number and parameter for $ operand number formats in...

	* c-common.c (check_format_info): Properly save the argument
	number and parameter for $ operand number formats in case width
	and precision arguments are also used.  Allow printf width and
	precision arguments to have operand numbers even if none was
	specified for the main format, since this is OK for %*.*m.  Only
	object to missing $ operand number if the format used requires an
	argument.

testsuite:
	* gcc.dg/format-ext-1.c: Add tests for mixing %m with $ formats.
	* gcc.dg/format-xopen-1.c: Fix error in one $ format test.  Add
	more $ format tests.

From-SVN: r36493
parent effa5541
2000-09-18 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.c (check_format_info): Properly save the argument
number and parameter for $ operand number formats in case width
and precision arguments are also used. Allow printf width and
precision arguments to have operand numbers even if none was
specified for the main format, since this is OK for %*.*m. Only
object to missing $ operand number if the format used requires an
argument.
2000-09-18 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.c (format_char_info): Add 'W' flag to comment.
(print_char_table, scan_char_table): Use it.
(check_format_info): Use the 'W' flag to determine whether a
......
......@@ -1904,6 +1904,8 @@ check_format_info (info, params)
tree format_tree;
tree cur_param;
tree wanted_type;
int main_arg_num;
tree main_arg_params;
enum format_std_version wanted_type_std;
const char *wanted_type_name;
format_wanted_type width_wanted_type;
......@@ -2051,6 +2053,8 @@ check_format_info (info, params)
}
flag_chars[0] = 0;
suppressed = wide = precise = FALSE;
main_arg_num = 0;
main_arg_params = 0;
if (info->format_type == scanf_format_type)
{
int non_zero_width_char = FALSE;
......@@ -2062,13 +2066,14 @@ check_format_info (info, params)
int opnum;
opnum = maybe_read_dollar_number (&format_chars,
has_operand_number == 1,
first_fillin_param, &params);
first_fillin_param,
&main_arg_params);
if (opnum == -1)
return;
else if (opnum > 0)
{
has_operand_number = 1;
arg_num = opnum + info->first_arg_num - 1;
main_arg_num = opnum + info->first_arg_num - 1;
}
else
has_operand_number = 0;
......@@ -2129,17 +2134,15 @@ check_format_info (info, params)
{
int opnum;
opnum = maybe_read_dollar_number (&format_chars,
has_operand_number == 1,
first_fillin_param, &params);
0, first_fillin_param,
&main_arg_params);
if (opnum == -1)
return;
else if (opnum > 0)
{
has_operand_number = 1;
arg_num = opnum + info->first_arg_num - 1;
main_arg_num = opnum + info->first_arg_num - 1;
}
else
has_operand_number = 0;
}
while (*format_chars != 0 && index (" +#0-'I", *format_chars) != 0)
......@@ -2178,16 +2181,22 @@ check_format_info (info, params)
tfaff ();
return;
}
if (has_operand_number > 0)
if (has_operand_number != 0)
{
int opnum;
opnum = maybe_read_dollar_number (&format_chars, 1,
opnum = maybe_read_dollar_number (&format_chars,
has_operand_number == 1,
first_fillin_param,
&params);
if (opnum <= 0)
if (opnum == -1)
return;
else if (opnum > 0)
{
has_operand_number = 1;
arg_num = opnum + info->first_arg_num - 1;
}
else
arg_num = opnum + info->first_arg_num - 1;
has_operand_number = 0;
}
if (info->first_arg_num != 0)
{
......@@ -2230,16 +2239,22 @@ check_format_info (info, params)
if (*format_chars == '*')
{
++format_chars;
if (has_operand_number > 0)
if (has_operand_number != 0)
{
int opnum;
opnum = maybe_read_dollar_number (&format_chars, 1,
opnum = maybe_read_dollar_number (&format_chars,
has_operand_number == 1,
first_fillin_param,
&params);
if (opnum <= 0)
if (opnum == -1)
return;
else if (opnum > 0)
{
has_operand_number = 1;
arg_num = opnum + info->first_arg_num - 1;
}
else
arg_num = opnum + info->first_arg_num - 1;
has_operand_number = 0;
}
if (info->first_arg_num != 0)
{
......@@ -2466,16 +2481,36 @@ check_format_info (info, params)
/* Finally. . .check type of argument against desired type! */
if (info->first_arg_num == 0)
continue;
if (!(fci->pointer_count == 0 && wanted_type == void_type_node))
if (fci->pointer_count == 0 && wanted_type == void_type_node)
{
if (params == 0)
if (main_arg_num != 0)
warning ("operand number specified for format taking no argument");
}
else
{
if (main_arg_num != 0)
{
tfaff ();
return;
arg_num = main_arg_num;
params = main_arg_params;
}
else
{
++arg_num;
if (has_operand_number > 0)
{
warning ("missing $ operand number in format");
return;
}
else
has_operand_number = 0;
if (params == 0)
{
tfaff ();
return;
}
}
cur_param = TREE_VALUE (params);
params = TREE_CHAIN (params);
++arg_num;
main_wanted_type.wanted_type = wanted_type;
main_wanted_type.wanted_type_name = wanted_type_name;
main_wanted_type.pointer_count = fci->pointer_count + aflag;
......
2000-09-18 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/format-ext-1.c: Add tests for mixing %m with $ formats.
* gcc.dg/format-xopen-1.c: Fix error in one $ format test. Add
more $ format tests.
2000-09-18 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/format-errmk-1.c: New test.
2000-09-17 Greg McGary <greg@mcgary.org>
......
......@@ -18,7 +18,7 @@ extern int printf (const char *, ...);
void
foo (quad_t q, u_quad_t uq, quad_t *qn, size_t z, size_t *zn, long long int ll,
unsigned long long int ull, int i, unsigned int u, double d,
char *s, void *p, wchar_t *ls, wint_t lc, int *n)
char *s, void *p, wchar_t *ls, wint_t lc, int *n, long int l)
{
/* As an extension, GCC allows the BSD length "q" for integer formats.
This is largely obsoleted in C99 by %j, %ll and PRId64.
......@@ -93,6 +93,13 @@ foo (quad_t q, u_quad_t uq, quad_t *qn, size_t z, size_t *zn, long long int ll,
printf ("%Lm", i); /* { dg-warning "length" "bad %Lm" } */
printf ("%qm", i); /* { dg-warning "length" "bad %qm" } */
printf ("%Zm", i); /* { dg-warning "length" "bad %Zm" } */
/* It should be OK to mix %m formats with $ operand number formats. */
printf ("%2$ld%m%1$d", i, l);
/* Likewise, %m formats with width and precision should not have an
operand number for the %m itself.
*/
printf ("%*2$.*1$m", i, i);
printf ("%1$*2$.*1$m", i, i); /* { dg-warning "no argument" "printf %1\$m" } */
/* As an extension, glibc includes the "I" flag for decimal integer
formats, to output using the locale's digits (e.g. in Arabic).
In GCC, we require this to be in the standard place for flags, though
......
......@@ -103,13 +103,15 @@ foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d,
*/
scanf ("%1$d", ip);
printf ("%1$d", i);
printf ("%3$*2$.*1$d", i2, i, l);
printf ("%1$d", l); /* { dg-warning "arg 2" "mismatched args with $ format" } */
printf ("%3$*2$.*1$ld", i2, i, l);
printf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", i, i, i, l, i, i, l);
scanf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", ip, ip, ip, lp, ip, ip, lp);
printf ("%1$d%d", i, i); /* { dg-warning "missing" "mixing $ and non-$ formats" } */
printf ("%%%1$d%%%2$d", i, i);
printf ("%d%2$d", i); /* { dg-warning "type character" "mixing $ and non-$ formats" } */
printf ("%1$*d", i, i); /* { dg-warning "missing" "mixing $ and non-$ formats" } */
printf ("%*1$d", i); /* { dg-warning "missing" "mixing $ and non-$ formats" } */
scanf ("%1$d%d", ip, ip); /* { dg-warning "missing" "mixing $ and non-$ formats" } */
scanf ("%*f%%%1$d%%%2$d", ip, ip);
printf ("%2$d", i); /* { dg-warning "operand" "$ number too large" } */
......
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