c-common.c (check_format_info): Properly save the argument number and parameter for...
authorJoseph Myers <jsm28@cam.ac.uk>
Mon, 18 Sep 2000 16:34:35 +0000 (17:34 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Mon, 18 Sep 2000 16:34:35 +0000 (17:34 +0100)
* 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

gcc/ChangeLog
gcc/c-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format-ext-1.c
gcc/testsuite/gcc.dg/format-xopen-1.c

index faaf564c2eec02ec9261a9e0dbad4de81842f54f..4a0d658e38fd7f0bb614a95c35d4da8454dfcb64 100644 (file)
@@ -1,3 +1,13 @@
+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.
index 7cdde8bd684bdbd9e7786717d5ee172d31a8f2e5..6a1e687f42ca48b71d772e120e6ced5effd8980f 100644 (file)
@@ -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;
index d688bf7e26e0c16a4d3d994000f1070283da1f71..1c1331087123ccc27b5c34472abf62aaddd2a86d 100644 (file)
@@ -1,3 +1,9 @@
+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.
index 459d114e67d2ee12503cd6993b0535edc713bd46..238a47802be5c40e17b2e22d18f3077c6b81a3bd 100644 (file)
@@ -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
index d5105eccf1472a2e1e820b378be10770772494e6..c57855a110a9cb1b1c8d09138987a1ec6c0f8713 100644 (file)
@@ -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" } */