c-common.c (FMT_FLAG_ARG_CONVERT, [...]): Define.
authorJoseph Myers <jsm28@cam.ac.uk>
Sun, 8 Oct 2000 21:12:33 +0000 (22:12 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Sun, 8 Oct 2000 21:12:33 +0000 (22:12 +0100)
* c-common.c (FMT_FLAG_ARG_CONVERT, FMT_FLAG_SCANF_A_KLUDGE,
FMT_FLAG_FANCY_PERCENT_OK): Define.
(format_char_info): Add flag "4" to comment.
(format_flag_spec, format_flag_pair): New structures.
(format_kind_info): Add additional fields to control format
checking.
(printf_flag_specs, printf_flag_pairs, scanf_flag_specs,
scanf_flag_pairs, strftime_flag_specs, strftime_flag_pairs): New
arrays.
(time_char_table): Use "4" flag to handle %Ey.
(format_types): Add entries for new fields.
(get_flag_spec): New function.
(check_format_info): Increase size of flag_chars[] to 256.
Control format checking using the new fields of a format_kind_info
and the new tables; remove all conditionals on printf_format_type,
scanf_format_type or strftime_format_type.  Handle all details of
bad combinations of flags (including width, precision and strftime
modifiers) through data rather than ad hoc code.  Handle all
details of standard versions in which flags appeared through
data.  Use the "4" flag.

testsuite:
* gcc.dg/c90-printf-1.c, gcc.dg/c90-scanf-1.c,
gcc.dg/c99-printf-1.c, gcc.dg/c99-scanf-1.c,
gcc.dg/c99-strftime-1.c, gcc.dg/format-ext-3.c: Adjust error
regexps and details of expected handling of some bad formats.
* gcc.dg/format-xopen-1.c: Add test for $ format with assignment
suppression.

From-SVN: r36790

gcc/ChangeLog
gcc/c-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c90-printf-1.c
gcc/testsuite/gcc.dg/c90-scanf-1.c
gcc/testsuite/gcc.dg/c99-printf-1.c
gcc/testsuite/gcc.dg/c99-scanf-1.c
gcc/testsuite/gcc.dg/c99-strftime-1.c
gcc/testsuite/gcc.dg/format-ext-3.c
gcc/testsuite/gcc.dg/format-xopen-1.c

index 8b65b6b67bd635327af9a7ee8bbf01aecc8a2ddc..6f1718fbe5adebe984552ba22ba3a8124e28e669 100644 (file)
@@ -1,3 +1,26 @@
+2000-10-08  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * c-common.c (FMT_FLAG_ARG_CONVERT, FMT_FLAG_SCANF_A_KLUDGE,
+       FMT_FLAG_FANCY_PERCENT_OK): Define.
+       (format_char_info): Add flag "4" to comment.
+       (format_flag_spec, format_flag_pair): New structures.
+       (format_kind_info): Add additional fields to control format
+       checking.
+       (printf_flag_specs, printf_flag_pairs, scanf_flag_specs,
+       scanf_flag_pairs, strftime_flag_specs, strftime_flag_pairs): New
+       arrays.
+       (time_char_table): Use "4" flag to handle %Ey.
+       (format_types): Add entries for new fields.
+       (get_flag_spec): New function.
+       (check_format_info): Increase size of flag_chars[] to 256.
+       Control format checking using the new fields of a format_kind_info
+       and the new tables; remove all conditionals on printf_format_type,
+       scanf_format_type or strftime_format_type.  Handle all details of
+       bad combinations of flags (including width, precision and strftime
+       modifiers) through data rather than ad hoc code.  Handle all
+       details of standard versions in which flags appeared through
+       data.  Use the "4" flag.
+
 2000-10-07  Will Cohen  <wcohen@redhat.com>, Kazu Hirata  <kazu@hxi.com>
 
        * config/h8300/h8300.md: Remove the memory alternative and correct
index 2d2ab4718cb140f2e75585a55faa701ff6298d66..6ad83f78d77d05dafe9864b4ba6231a212cf2266 100644 (file)
@@ -1246,6 +1246,26 @@ enum format_std_version
 };
 
 
+/* Flags that may apply to a particular kind of format checked by GCC.  */
+enum
+{
+  /* This format converts arguments of types determined by the
+     format string.  */
+  FMT_FLAG_ARG_CONVERT = 1,
+  /* The scanf allocation 'a' kludge applies to this format kind.  */
+  FMT_FLAG_SCANF_A_KLUDGE = 2,
+  /* A % during parsing a specifier is allowed to be a modified % rather
+     that indicating the format is broken and we are out-of-sync.  */
+  FMT_FLAG_FANCY_PERCENT_OK = 4
+  /* Not included here: details of whether width or precision may occur
+     (controlled by width_char and precision_char); details of whether
+     '*' can be used for these (width_type and precision_type); details
+     of whether length modifiers can occur (length_char_specs); details
+     of when $ operand numbers are allowed (always, for the formats
+     supported, if arguments are converted).  */
+};
+
+
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
@@ -1302,15 +1322,58 @@ typedef struct
   /* List of additional flags describing these conversion specifiers.
      "c" for generic character pointers being allowed, "2" for strftime
      two digit year formats, "3" for strftime formats giving two digit
-     years in some locales, "o" if use of strftime "O"
-     is a GNU extension beyond C99, "W" if the argument is a pointer
-     which is dereferenced and written into, "i" for printf integer
-     formats where the '0' flag is ignored with precision, and "["
-     for the starting character of a scanf scanset.  */
+     years in some locales, "4" for "2" which becomes "3" with an "E" modifier,
+     "o" if use of strftime "O" is a GNU extension beyond C99,
+     "W" if the argument is a pointer which is dereferenced and written into,
+     "i" for printf integer formats where the '0' flag is ignored with
+     precision, and "[" for the starting character of a scanf scanset.  */
   const char *flags2;
 } format_char_info;
 
 
+/* Structure describing a flag accepted by some kind of format.  */
+typedef struct
+{
+  /* The flag character in question (0 for end of array).  */
+  int flag_char;
+  /* Zero if this entry describes the flag character in general, or a
+     non-zero character that may be found in flags2 if it describes the
+     flag when used with certain formats only.  If the latter, only
+     the first such entry found that applies to the current conversion
+     specifier is used; the values of `name' and `long_name' it supplies
+     will be used, if non-NULL and the standard version is higher than
+     the unpredicated one, for any pedantic warning.  For example, 'o'
+     for strftime formats (meaning 'O' is an extension over C99).  */
+  int predicate;
+  /* The name to use for this flag in diagnostic messages.  For example,
+     N_("`0' flag"), N_("field width").  */
+  const char *name;
+  /* Long name for this flag in diagnostic messages; currently only used for
+     "ISO C does not support ...".  For example, N_("the `I' printf flag").  */
+  const char *long_name;
+  /* The standard version in which it appeared.  */
+  enum format_std_version std;
+} format_flag_spec;
+
+
+/* Structure describing a combination of flags that is bad for some kind
+   of format.  */
+typedef struct
+{
+  /* The first flag character in question (0 for end of array).  */
+  int flag_char1;
+  /* The second flag character.  */
+  int flag_char2;
+  /* Non-zero if the message should say that the first flag is ignored with
+     the second, zero if the combination should simply be objected to.  */
+  int ignored;
+  /* Zero if this entry applies whenever this flag combination occurs,
+     a non-zero character from flags2 if it only applies in some
+     circumstances (e.g. 'i' for printf formats ignoring 0 with precision).  */
+  int predicate;
+} format_flag_pair;
+
+
 /* Structure describing a particular kind of format processed by GCC.  */
 typedef struct
 {
@@ -1320,6 +1383,34 @@ typedef struct
   const format_length_info *length_char_specs;
   /* Details of the conversion specification characters accepted.  */
   const format_char_info *conversion_specs;
+  /* String listing the flag characters that are accepted.  */
+  const char *flag_chars;
+  /* String listing modifier characters (strftime) accepted.  May be NULL.  */
+  const char *modifier_chars;
+  /* Details of the flag characters, including pseudo-flags.  */
+  const format_flag_spec *flag_specs;
+  /* Details of bad combinations of flags.  */
+  const format_flag_pair *bad_flag_pairs;
+  /* Flags applicable to this kind of format.  */
+  int flags;
+  /* Flag character to treat a width as, or 0 if width not used.  */
+  int width_char;
+  /* Flag character to treat a precision as, or 0 if precision not used.  */
+  int precision_char;
+  /* If a flag character has the effect of suppressing the conversion of
+     an argument ('*' in scanf), that flag character, otherwise 0.  */
+  int suppression_char;
+  /* Flag character to treat a length modifier as (ignored if length
+     modifiers not used).  Need not be placed in flag_chars for conversion
+     specifiers, but is used to check for bad combinations such as length
+     modifier with assignment suppression in scanf.  */
+  int length_code_char;
+  /* Pointer to type of argument expected if '*' is used for a width,
+     or NULL if '*' not used for widths.  */
+  tree *width_type;
+  /* Pointer to type of argument expected if '*' is used for a precision,
+     or NULL if '*' not used for precisions.  */
+  tree *precision_type;
 } format_kind_info;
 
 
@@ -1383,6 +1474,70 @@ static const format_length_info scanf_length_specs[] =
 };
 
 
+static const format_flag_spec printf_flag_specs[] =
+{
+  { ' ',  0, N_("` ' flag"),        N_("the ` ' printf flag"),              STD_C89 },
+  { '+',  0, N_("`+' flag"),        N_("the `+' printf flag"),              STD_C89 },
+  { '#',  0, N_("`#' flag"),        N_("the `#' printf flag"),              STD_C89 },
+  { '0',  0, N_("`0' flag"),        N_("the `0' printf flag"),              STD_C89 },
+  { '-',  0, N_("`-' flag"),        N_("the `-' printf flag"),              STD_C89 },
+  { '\'', 0, N_("`'' flag"),        N_("the `'' printf flag"),              STD_EXT },
+  { 'I',  0, N_("`I' flag"),        N_("the `I' printf flag"),              STD_EXT },
+  { 'w',  0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+
+static const format_flag_spec scanf_flag_specs[] =
+{
+  { '*', 0, N_("assignment suppression"), N_("assignment suppression"),          STD_C89 },
+  { 'a', 0, N_("`a' flag"),               N_("the `a' scanf flag"),              STD_EXT },
+  { 'w', 0, N_("field width"),            N_("field width in scanf format"),     STD_C89 },
+  { 'L', 0, N_("length modifier"),        N_("length modifier in scanf format"), STD_C89 },
+  { 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+
+static const format_flag_spec strftime_flag_specs[] =
+{
+  { '_', 0,   N_("`_' flag"),     N_("the `_' strftime flag"),          STD_EXT },
+  { '-', 0,   N_("`-' flag"),     N_("the `-' strftime flag"),          STD_EXT },
+  { '0', 0,   N_("`0' flag"),     N_("the `0' strftime flag"),          STD_EXT },
+  { '^', 0,   N_("`^' flag"),     N_("the `^' strftime flag"),          STD_EXT },
+  { '#', 0,   N_("`#' flag"),     N_("the `#' strftime flag"),          STD_EXT },
+  { 'w', 0,   N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   N_("`E' modifier"), N_("the `E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   N_("`O' modifier"), N_("the `O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', NULL,               N_("the `O' modifier"),               STD_EXT },
+  { 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+
 #define T_I    &integer_type_node
 #define T89_I  { STD_C89, NULL, T_I }
 #define T99_I  { STD_C99, NULL, T_I }
@@ -1490,7 +1645,7 @@ static format_char_info time_char_table[] =
   { "j",               0, STD_C89, NOLENGTHS, "-_0Ow",  "o"  },
   { "p",               0, STD_C89, NOLENGTHS, "#",      ""   },
   { "X",               0, STD_C89, NOLENGTHS, "E",      ""   },
-  { "y",               0, STD_C89, NOLENGTHS, "EO-_0w", "2"  },
+  { "y",               0, STD_C89, NOLENGTHS, "EO-_0w", "4"  },
   { "Y",               0, STD_C89, NOLENGTHS, "-_0EOw", "o"  },
   { "%",               0, STD_C89, NOLENGTHS, "",       ""   },
   /* C99 conversion specifiers.  */
@@ -1512,9 +1667,21 @@ static format_char_info time_char_table[] =
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types[] =
 {
-  { "printf",   printf_length_specs, print_char_table },
-  { "scanf",    scanf_length_specs,  scan_char_table  },
-  { "strftime", NULL,                time_char_table  }
+  { "printf",   printf_length_specs, print_char_table, " +#0-'I", NULL, 
+    printf_flag_specs, printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT, 'w', 'p', 0, 'L',
+    &integer_type_node, &integer_type_node
+  },
+  { "scanf",    scanf_length_specs,  scan_char_table,  "*", NULL, 
+    scanf_flag_specs, scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE, 'w', 0, '*', 'L',
+    NULL, NULL
+  },
+  { "strftime", NULL,                time_char_table,  "_-0^#", "EO",
+    strftime_flag_specs, strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0,
+    NULL, NULL
+  }
 };
 
 
@@ -1549,6 +1716,9 @@ static int maybe_read_dollar_number               PARAMS ((int *, const char **, int,
                                                         tree, tree *));
 static void finish_dollar_format_checking      PARAMS ((int *));
 
+static const format_flag_spec *get_flag_spec   PARAMS ((const format_flag_spec *,
+                                                        int, const char *));
+
 static void check_format_types PARAMS ((int *, format_wanted_type *));
 static int is_valid_printf_arglist PARAMS ((tree));
 static rtx c_expand_builtin (tree, rtx, enum machine_mode, enum expand_modifier);
@@ -1928,6 +2098,41 @@ finish_dollar_format_checking (status)
 }
 
 
+/* Retrieve the specification for a format flag.  SPEC contains the
+   specifications for format flags for the applicable kind of format.
+   FLAG is the flag in question.  If PREDICATES is NULL, the basic
+   spec for that flag must be retrieved and this function aborts if
+   it cannot be found.  If PREDICATES is not NULL, it is a string listing
+   possible predicates for the spec entry; if an entry predicated on any
+   of these is found, it is returned, otherwise NULL is returned.  */
+
+static const format_flag_spec *
+get_flag_spec (spec, flag, predicates)
+     const format_flag_spec *spec;
+     int flag;
+     const char *predicates;
+{
+  int i;
+  for (i = 0; spec[i].flag_char != 0; i++)
+    {
+      if (spec[i].flag_char != flag)
+       continue;
+      if (predicates != NULL)
+       {
+         if (spec[i].predicate != 0
+             && index (predicates, spec[i].predicate) != 0)
+           return &spec[i];
+       }
+      else if (spec[i].predicate == 0)
+       return &spec[i];
+    }
+  if (predicates == NULL)
+    abort ();
+  else
+    return NULL;
+}
+
+
 /* Check the argument list of a call to printf, scanf, etc.
    INFO points to the function_format_info structure.
    PARAMS is the list of argument values.  */
@@ -1940,7 +2145,7 @@ check_format_info (status, info, params)
 {
   int i;
   int arg_num;
-  int suppressed, wide, precise;
+  int suppressed;
   const char *length_chars = NULL;
   enum format_lengths length_chars_val = FMT_LEN_none;
   enum format_std_version length_chars_std = STD_C89;
@@ -1961,9 +2166,11 @@ check_format_info (status, info, params)
   tree first_fillin_param;
   const char *format_chars;
   const format_kind_info *fki = NULL;
+  const format_flag_spec *flag_specs = NULL;
+  const format_flag_pair *bad_flag_pairs = NULL;
   const format_length_info *fli = NULL;
   const format_char_info *fci = NULL;
-  char flag_chars[8];
+  char flag_chars[256];
   /* -1 if no conversions taking an operand have been found; 0 if one has
      and it didn't use $; 1 if $ formats are in use.  */
   int has_operand_number = -1;
@@ -2073,6 +2280,8 @@ check_format_info (status, info, params)
   first_fillin_param = params;
   init_dollar_format_checking (info->first_arg_num, first_fillin_param);
   fki = &format_types[info->format_type];
+  flag_specs = fki->flag_specs;
+  bad_flag_pairs = fki->bad_flag_pairs;
   while (1)
     {
       int aflag;
@@ -2102,127 +2311,57 @@ check_format_info (status, info, params)
          continue;
        }
       flag_chars[0] = 0;
-      suppressed = wide = precise = FALSE;
+      suppressed = FALSE;
       main_arg_num = 0;
       main_arg_params = 0;
-      if (info->format_type == scanf_format_type)
+
+      if ((fki->flags & FMT_FLAG_ARG_CONVERT) && has_operand_number != 0)
        {
-         int non_zero_width_char = FALSE;
-         suppressed = *format_chars == '*';
-         if (suppressed)
-           ++format_chars;
-         else if (has_operand_number != 0)
+         /* Possibly read a $ operand number at the start of the format.
+            If one was previously used, one is required here.  If one
+            is not used here, we can't immediately conclude this is a
+            format without them, since it could be printf %m or scanf %*.  */
+         int opnum;
+         opnum = maybe_read_dollar_number (status, &format_chars, 0,
+                                           first_fillin_param,
+                                           &main_arg_params);
+         if (opnum == -1)
+           return;
+         else if (opnum > 0)
            {
-             int opnum;
-             opnum = maybe_read_dollar_number (status, &format_chars,
-                                               has_operand_number == 1,
-                                               first_fillin_param,
-                                               &main_arg_params);
-             if (opnum == -1)
-               return;
-             else if (opnum > 0)
-               {
-                 has_operand_number = 1;
-                 main_arg_num = opnum + info->first_arg_num - 1;
-               }
-             else
-               has_operand_number = 0;
-           }
-         while (ISDIGIT (*format_chars))
-           {
-             wide = TRUE;
-             if (*format_chars != '0')
-               non_zero_width_char = TRUE;
-             ++format_chars;
+             has_operand_number = 1;
+             main_arg_num = opnum + info->first_arg_num - 1;
            }
-         if (wide && !non_zero_width_char)
-           status_warning (status, "zero width in scanf format");
        }
-      else if (info->format_type == strftime_format_type)
-        {
-         while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0)
-           {
-             if (pedantic)
-               status_warning (status, "ISO C does not support the strftime `%c' flag",
-                        *format_chars);
-             if (index (flag_chars, *format_chars) != 0)
-               {
-                 status_warning (status, "repeated `%c' flag in format",
-                          *format_chars);
-                 ++format_chars;
-               }
-             else
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = *format_chars++;
-                 flag_chars[i] = 0;
-               }
-           }
-         while (ISDIGIT ((unsigned char) *format_chars))
+
+      /* Read any format flags, but do not yet validate them beyond removing
+        duplicates, since in general validation depends on the rest of
+        the format.  */
+      while (*format_chars != 0 && index (fki->flag_chars, *format_chars) != 0)
+       {
+         if (index (flag_chars, *format_chars) != 0)
            {
-             wide = TRUE;
-              ++format_chars;
+             const format_flag_spec *s = get_flag_spec (flag_specs,
+                                                        *format_chars, NULL);
+             status_warning (status, "repeated %s in format", _(s->name));
            }
-         if (wide && pedantic)
-           status_warning (status, "ISO C does not support strftime format width");
-         if (*format_chars == 'E' || *format_chars == 'O')
+         else
            {
              i = strlen (flag_chars);
-             flag_chars[i++] = *format_chars++;
+             flag_chars[i++] = *format_chars;
              flag_chars[i] = 0;
-             if (*format_chars == 'E' || *format_chars == 'O')
-               {
-                 status_warning (status, "multiple E/O modifiers in format");
-                 while (*format_chars == 'E' || *format_chars == 'O')
-                   ++format_chars;
-               }
            }
+         ++format_chars;
        }
-      else if (info->format_type == printf_format_type)
-       {
-         if (has_operand_number != 0)
-           {
-             int opnum;
-             opnum = maybe_read_dollar_number (status, &format_chars,
-                                               0, first_fillin_param,
-                                               &main_arg_params);
-             if (opnum == -1)
-               return;
-             else if (opnum > 0)
-               {
-                 has_operand_number = 1;
-                 main_arg_num = opnum + info->first_arg_num - 1;
-               }
-           }
 
-         while (*format_chars != 0 && index (" +#0-'I", *format_chars) != 0)
-           {
-             if (index (flag_chars, *format_chars) != 0)
-               status_warning (status, "repeated `%c' flag in format", *format_chars++);
-             else
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = *format_chars++;
-                 flag_chars[i] = 0;
-               }
-           }
-         /* "If the space and + flags both appear,
-            the space flag will be ignored."  */
-         if (index (flag_chars, ' ') != 0
-             && index (flag_chars, '+') != 0)
-           status_warning (status, "use of both ` ' and `+' flags in format");
-         /* "If the 0 and - flags both appear,
-            the 0 flag will be ignored."  */
-         if (index (flag_chars, '0') != 0
-             && index (flag_chars, '-') != 0)
-           status_warning (status, "use of both `0' and `-' flags in format");
-         if (index (flag_chars, '\'') && pedantic)
-           status_warning (status, "ISO C does not support the `'' format flag");
-         if (index (flag_chars, 'I') && pedantic)
-           status_warning (status, "ISO C does not support the `I' format flag");
-         if (*format_chars == '*')
+      /* Read any format width, possibly * or *m$.  */
+      if (fki->width_char != 0)
+       {
+         if (fki->width_type != NULL && *format_chars == '*')
            {
-             wide = TRUE;
+             i = strlen (flag_chars);
+             flag_chars[i++] = fki->width_char;
+             flag_chars[i] = 0;
              /* "...a field width...may be indicated by an asterisk.
                 In this case, an int argument supplies the field width..."  */
              ++format_chars;
@@ -2256,7 +2395,7 @@ check_format_info (status, info, params)
                      params = TREE_CHAIN (params);
                      ++arg_num;
                    }
-                 width_wanted_type.wanted_type = integer_type_node;
+                 width_wanted_type.wanted_type = *fki->width_type;
                  width_wanted_type.wanted_type_name = NULL;
                  width_wanted_type.pointer_count = 0;
                  width_wanted_type.char_lenient_flag = 0;
@@ -2274,78 +2413,100 @@ check_format_info (status, info, params)
            }
          else
            {
+             /* Possibly read a numeric width.  If the width is zero,
+                we complain; for scanf this is bad according to the
+                standard, and for printf and strftime it cannot occur
+                because 0 is a flag.  */
+             int non_zero_width_char = FALSE;
+             int found_width = FALSE;
              while (ISDIGIT (*format_chars))
                {
-                 wide = TRUE;
+                 found_width = TRUE;
+                 if (*format_chars != '0')
+                   non_zero_width_char = TRUE;
                  ++format_chars;
                }
+             if (found_width && !non_zero_width_char)
+               status_warning (status, "zero width in scanf format");
+             if (found_width)
+               {
+                 i = strlen (flag_chars);
+                 flag_chars[i++] = fki->width_char;
+                 flag_chars[i] = 0;
+               }
            }
-         if (*format_chars == '.')
+       }
+
+      /* Read any format precision, possibly * or *m$.  */
+      if (fki->precision_char != 0 && *format_chars == '.')
+       {
+         ++format_chars;
+         i = strlen (flag_chars);
+         flag_chars[i++] = fki->precision_char;
+         flag_chars[i] = 0;
+         if (fki->precision_type != NULL && *format_chars == '*')
            {
-             precise = TRUE;
-             ++format_chars;
              /* "...a...precision...may be indicated by an asterisk.
                 In this case, an int argument supplies the...precision."  */
-             if (*format_chars == '*')
+             ++format_chars;
+             if (has_operand_number != 0)
                {
-                 ++format_chars;
-                 if (has_operand_number != 0)
-                   {
-                     int opnum;
-                     opnum = maybe_read_dollar_number (status, &format_chars,
-                                                       has_operand_number == 1,
-                                                       first_fillin_param,
-                                                       &params);
-                     if (opnum == -1)
-                       return;
-                     else if (opnum > 0)
-                       {
-                         has_operand_number = 1;
-                         arg_num = opnum + info->first_arg_num - 1;
-                       }
-                     else
-                       has_operand_number = 0;
-                   }
-                 if (info->first_arg_num != 0)
+                 int opnum;
+                 opnum = maybe_read_dollar_number (status, &format_chars,
+                                                   has_operand_number == 1,
+                                                   first_fillin_param,
+                                                   &params);
+                 if (opnum == -1)
+                   return;
+                 else if (opnum > 0)
                    {
-                     if (params == 0)
-                       {
-                         status_warning (status, "too few arguments for format");
-                         return;
-                       }
-                     cur_param = TREE_VALUE (params);
-                     if (has_operand_number <= 0)
-                       {
-                         params = TREE_CHAIN (params);
-                         ++arg_num;
-                       }
-                     precision_wanted_type.wanted_type = integer_type_node;
-                     precision_wanted_type.wanted_type_name = NULL;
-                     precision_wanted_type.pointer_count = 0;
-                     precision_wanted_type.char_lenient_flag = 0;
-                     precision_wanted_type.writing_in_flag = 0;
-                     precision_wanted_type.name = _("field precision");
-                     precision_wanted_type.param = cur_param;
-                     precision_wanted_type.arg_num = arg_num;
-                     precision_wanted_type.next = NULL;
-                     if (last_wanted_type != 0)
-                       last_wanted_type->next = &precision_wanted_type;
-                     if (first_wanted_type == 0)
-                       first_wanted_type = &precision_wanted_type;
-                     last_wanted_type = &precision_wanted_type;
+                     has_operand_number = 1;
+                     arg_num = opnum + info->first_arg_num - 1;
                    }
+                 else
+                   has_operand_number = 0;
                }
-             else
+             if (info->first_arg_num != 0)
                {
-                 while (ISDIGIT (*format_chars))
-                   ++format_chars;
+                 if (params == 0)
+                   {
+                     status_warning (status, "too few arguments for format");
+                     return;
+                   }
+                 cur_param = TREE_VALUE (params);
+                 if (has_operand_number <= 0)
+                   {
+                     params = TREE_CHAIN (params);
+                     ++arg_num;
+                   }
+                 precision_wanted_type.wanted_type = *fki->precision_type;
+                 precision_wanted_type.wanted_type_name = NULL;
+                 precision_wanted_type.pointer_count = 0;
+                 precision_wanted_type.char_lenient_flag = 0;
+                 precision_wanted_type.writing_in_flag = 0;
+                 precision_wanted_type.name = _("field precision");
+                 precision_wanted_type.param = cur_param;
+                 precision_wanted_type.arg_num = arg_num;
+                 precision_wanted_type.next = NULL;
+                 if (last_wanted_type != 0)
+                   last_wanted_type->next = &precision_wanted_type;
+                 if (first_wanted_type == 0)
+                   first_wanted_type = &precision_wanted_type;
+                 last_wanted_type = &precision_wanted_type;
                }
            }
+         else
+           {
+             while (ISDIGIT (*format_chars))
+               ++format_chars;
+           }
        }
 
-      aflag = 0;
-
+      /* Read any length modifier, if this kind of format has them.  */
       fli = fki->length_char_specs;
+      length_chars = NULL;
+      length_chars_val = FMT_LEN_none;
+      length_chars_std = STD_C89;
       if (fli)
        {
          while (fli->name != 0 && fli->name[0] != *format_chars)
@@ -2366,12 +2527,9 @@ check_format_info (status, info, params)
                  length_chars_val = fli->index;
                  length_chars_std = fli->std;
                }
-           }
-         else
-           {
-             length_chars = NULL;
-             length_chars_val = FMT_LEN_none;
-             length_chars_std = STD_C89;
+             i = strlen (flag_chars);
+             flag_chars[i++] = fki->length_code_char;
+             flag_chars[i] = 0;
            }
          if (pedantic)
            {
@@ -2384,23 +2542,50 @@ check_format_info (status, info, params)
                status_warning (status, "ISO C89 does not support the `%s' %s length modifier",
                         length_chars, fki->name);
            }
-         if (*format_chars == 'a' && info->format_type == scanf_format_type
-             && !flag_isoc99)
+       }
+
+      /* Read any modifier (strftime E/O).  */
+      if (fki->modifier_chars != NULL)
+       {
+         while (*format_chars != 0
+                && index (fki->modifier_chars, *format_chars) != 0)
+           {
+             if (index (flag_chars, *format_chars) != 0)
+               {
+                 const format_flag_spec *s = get_flag_spec (flag_specs,
+                                                            *format_chars, NULL);
+                 status_warning (status, "repeated %s in format", _(s->name));
+               }
+             else
+               {
+                 i = strlen (flag_chars);
+                 flag_chars[i++] = *format_chars;
+                 flag_chars[i] = 0;
+               }
+             ++format_chars;
+           }
+       }
+
+      /* Handle the scanf allocation kludge.  */
+      if (fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
+       {
+         if (*format_chars == 'a' && !flag_isoc99)
            {
              if (format_chars[1] == 's' || format_chars[1] == 'S'
                  || format_chars[1] == '[')
                {
                  /* `a' is used as a flag.  */
-                 aflag = 1;
+                 i = strlen (flag_chars);
+                 flag_chars[i++] = 'a';
+                 flag_chars[i] = 0;
                  format_chars++;
                }
            }
-         if (suppressed && length_chars_val != FMT_LEN_none)
-           status_warning (status, "use of `*' and `%s' together in format", length_chars);
        }
+
       format_char = *format_chars;
       if (format_char == 0
-         || (info->format_type != strftime_format_type && format_char == '%'))
+         || (!(fki->flags & FMT_FLAG_FANCY_PERCENT_OK) && format_char == '%'))
        {
          status_warning (status, "conversion lacks type at end of format");
          continue;
@@ -2429,35 +2614,117 @@ check_format_info (status, info, params)
                   || (fci->std == STD_C94 && !flag_isoc94))
            status_warning (status, "ISO C89 does not support the `%%%c' %s format",
                     format_char, fki->name);
-         if (index (flag_chars, 'O') != 0)
-           {
-             if (index (fci->flags2, 'o') != 0)
-               status_warning (status, "ISO C does not support `%%O%c'", format_char);
-             else if (!flag_isoc99 && index (fci->flag_chars, 'O') != 0)
-               status_warning (status, "ISO C89 does not support `%%O%c'", format_char);
-           }
-         if (!flag_isoc99 && index (flag_chars, 'E'))
-           status_warning (status, "ISO C89 does not support `%%E%c'", format_char);
        }
-      if (wide && index (fci->flag_chars, 'w') == 0)
-       status_warning (status, "width used with `%c' format", format_char);
-      if (index (fci->flags2, '3') != 0
-         || (format_char == 'y' && index (flag_chars, 'E')))
-       status_warning (status, "`%%%c' yields only last 2 digits of year in some locales",
-                format_char);
-      else if (index (fci->flags2, '2') != 0)
-       status_warning (status, "`%%%c' yields only last 2 digits of year", format_char);
-      if (precise && index (fci->flag_chars, 'p') == 0)
-       status_warning (status, "precision used with `%c' format", format_char);
-      if (aflag && index (fci->flag_chars, 'a') == 0)
+
+      /* Validate the individual flags used, removing any that are invalid.  */
+      {
+       int d = 0;
+       for (i = 0; flag_chars[i] != 0; i++)
+         {
+           const format_flag_spec *s = get_flag_spec (flag_specs,
+                                                      flag_chars[i], NULL);
+           flag_chars[i - d] = flag_chars[i];
+           if (flag_chars[i] == fki->length_code_char)
+             continue;
+           if (index (fci->flag_chars, flag_chars[i]) == 0)
+             {
+               status_warning (status, "%s used with `%%%c' %s format",
+                               _(s->name), format_char, fki->name);
+               d++;
+               continue;
+             }
+           if (pedantic)
+             {
+               const format_flag_spec *t;
+               if (s->std == STD_EXT)
+                 status_warning (status, "ISO C does not support %s",
+                                 _(s->long_name));
+               else if ((s->std == STD_C99 && !flag_isoc99)
+                        || (s->std == STD_C94 && !flag_isoc94))
+                 status_warning (status, "ISO C89 does not support %s",
+                                 _(s->long_name));
+               t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
+               if (t != NULL && t->std > s->std)
+                 {
+                   const char *long_name = (t->long_name != NULL
+                                            ? t->long_name
+                                            : s->long_name);
+                   if (t->std == STD_EXT)
+                     status_warning (status, "ISO C does not support %s with the `%%%c' %s format",
+                                     _(long_name), format_char, fki->name);
+                   else if ((t->std == STD_C99 && !flag_isoc99)
+                            || (t->std == STD_C94 && !flag_isoc94))
+                     status_warning (status, "ISO C89 does not support %s with the `%%%c' %s format",
+                                     _(long_name), format_char, fki->name);
+                 }
+             }
+         }
+       flag_chars[i - d] = 0;
+      }
+
+      aflag = 0;
+      if ((fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
+         && index (flag_chars, 'a') != 0)
+       aflag = 1;
+
+      if (fki->suppression_char
+         && index (flag_chars, fki->suppression_char) != 0)
+       suppressed = 1;
+
+      /* Validate the pairs of flags used.  */
+      for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
        {
-         status_warning (status, "`a' flag used with `%c' format", format_char);
-         /* To simplify the following code.  */
-         aflag = 0;
+         const format_flag_spec *s, *t;
+         if (index (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
+           continue;
+         if (index (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
+           continue;
+         if (bad_flag_pairs[i].predicate != 0
+             && index (fci->flags2, bad_flag_pairs[i].predicate) == 0)
+           continue;
+         s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
+         t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
+         if (bad_flag_pairs[i].ignored)
+           {
+             if (bad_flag_pairs[i].predicate != 0)
+               status_warning (status, "%s ignored with %s and `%%%c' %s format",
+                               _(s->name), _(t->name), format_char,
+                               fki->name);
+             else
+               status_warning (status, "%s ignored with %s in %s format",
+                               _(s->name), _(t->name), fki->name);
+           }
+         else
+           {
+             if (bad_flag_pairs[i].predicate != 0)
+               status_warning (status, "use of %s and %s together with `%%%c' %s format",
+                               _(s->name), _(t->name), format_char,
+                               fki->name);
+             else
+               status_warning (status, "use of %s and %s together in %s format",
+                               _(s->name), _(t->name), fki->name);
+           }
        }
-      /* The a flag is a GNU extension.  */
-      else if (pedantic && aflag)
-       status_warning (status, "ISO C does not support the `a' flag");
+
+      /* Give Y2K warnings.  */
+      {
+       int y2k_level = 0;
+       if (index (fci->flags2, '4') != 0)
+         if (index (flag_chars, 'E') != 0)
+           y2k_level = 3;
+         else
+           y2k_level = 2;
+       else if (index (fci->flags2, '3') != 0)
+         y2k_level = 3;
+       else if (index (fci->flags2, '2') != 0)
+         y2k_level = 2;
+       if (y2k_level == 3)
+         status_warning (status, "`%%%c' yields only last 2 digits of year in some locales",
+                         format_char);
+       else if (y2k_level == 2)
+         status_warning (status, "`%%%c' yields only last 2 digits of year", format_char);
+      }
+
       if (index (fci->flags2, '[') != 0)
        {
          /* Skip over scan set, in case it happens to have '%' in it.  */
@@ -2473,66 +2740,58 @@ check_format_info (status, info, params)
            /* The end of the format string was reached.  */
            status_warning (status, "no closing `]' for `%%[' format");
        }
-      if (suppressed)
-       {
-         if (index (fci->flag_chars, '*') == 0)
-           status_warning (status, "suppression of `%c' conversion in format", format_char);
-         continue;
-       }
-      for (i = 0; flag_chars[i] != 0; ++i)
-       {
-         if (index (fci->flag_chars, flag_chars[i]) == 0)
-           status_warning (status, "flag `%c' used with type `%c'",
-                    flag_chars[i], format_char);
-       }
-      if (info->format_type == strftime_format_type)
-       continue;
-      if (precise && index (flag_chars, '0') != 0
-         && (index (fci->flags2, 'i') != 0))
-       status_warning (status, "`0' flag ignored with precision specifier and `%c' format",
-                format_char);
-      wanted_type = (fci->types[length_chars_val].type
-                    ? *fci->types[length_chars_val].type : 0);
-      wanted_type_name = fci->types[length_chars_val].name;
-      wanted_type_std = fci->types[length_chars_val].std;
-      if (wanted_type == 0)
+
+      if (fki->flags & FMT_FLAG_ARG_CONVERT)
        {
-         status_warning (status, "use of `%s' length modifier with `%c' type character",
-                  length_chars, format_char);
-         /* Heuristic: skip one argument when an invalid length/type
-            combination is encountered.  */
-         arg_num++;
-         if (params == 0)
+         wanted_type = (fci->types[length_chars_val].type
+                        ? *fci->types[length_chars_val].type : 0);
+         wanted_type_name = fci->types[length_chars_val].name;
+         wanted_type_std = fci->types[length_chars_val].std;
+         if (wanted_type == 0)
+           {
+             status_warning (status, "use of `%s' length modifier with `%c' type character",
+                             length_chars, format_char);
+             /* Heuristic: skip one argument when an invalid length/type
+                combination is encountered.  */
+             arg_num++;
+             if (params == 0)
+               {
+                 status_warning (status, "too few arguments for format");
+                 return;
+               }
+             params = TREE_CHAIN (params);
+             continue;
+           }
+         else if (pedantic
+                  /* Warn if non-standard, provided it is more non-standard
+                     than the length and type characters that may already
+                     have been warned for.  */
+                  && wanted_type_std > length_chars_std
+                  && wanted_type_std > fci->std)
            {
-             status_warning (status, "too few arguments for format");
-             return;
+             if (wanted_type_std == STD_EXT)
+               status_warning (status, "ISO C does not support the `%%%s%c' %s format",
+                               length_chars, format_char, fki->name);
+             else if ((wanted_type_std == STD_C99 && !flag_isoc99)
+                      || (wanted_type_std == STD_C94 && !flag_isoc94))
+               status_warning (status, "ISO C89 does not support the `%%%s%c' %s format",
+                               length_chars, format_char, fki->name);
            }
-         params = TREE_CHAIN (params);
-         continue;
-       }
-      else if (pedantic
-              /* Warn if non-standard, provided it is more non-standard
-                 than the length and type characters that may already
-                 have been warned for.  */
-              && wanted_type_std > length_chars_std
-              && wanted_type_std > fci->std)
-       {
-         if (wanted_type_std == STD_EXT)
-           status_warning (status, "ISO C does not support the `%%%s%c' %s format",
-                    length_chars, format_char, fki->name);
-         else if ((wanted_type_std == STD_C99 && !flag_isoc99)
-                  || (wanted_type_std == STD_C94 && !flag_isoc94))
-           status_warning (status, "ISO C89 does not support the `%%%s%c' %s format",
-                    length_chars, format_char, fki->name);
        }
 
       /* 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)
+         || suppressed)
        {
          if (main_arg_num != 0)
-           status_warning (status, "operand number specified for format taking no argument");
+           {
+             if (suppressed)
+               status_warning (status, "operand number specified with suppressed assignment");
+             else
+               status_warning (status, "operand number specified for format taking no argument");
+           }
        }
       else
        {
index 65a149d228df273f28b80be4b054430856791842..990a4df578819a09e6034876b33951e0bb6c806c 100644 (file)
@@ -1,3 +1,12 @@
+2000-10-08  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * gcc.dg/c90-printf-1.c, gcc.dg/c90-scanf-1.c,
+       gcc.dg/c99-printf-1.c, gcc.dg/c99-scanf-1.c,
+       gcc.dg/c99-strftime-1.c, gcc.dg/format-ext-3.c: Adjust error
+       regexps and details of expected handling of some bad formats.
+       * gcc.dg/format-xopen-1.c: Add test for $ format with assignment
+       suppression.
+
 2000-10-07  Joseph S. Myers  <jsm28@cam.ac.uk>
 
        * g++.old-deja/g++.eh/cond1.C, g++.old-deja/g++.other/bitfld3.C,
index 4c5a6e360884ec78b8a9f0a49d316454ebbe1b8a..ef9e498e5bce0a42d2ce1df9a50397cb049e825a 100644 (file)
@@ -140,8 +140,8 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
   /* Uses of the space flag (valid on signed conversions only, and ignored
      with +).
   */
-  printf ("% +d", i); /* { dg-warning "use of both" "use of space and + flags" } */
-  printf ("%+ d", i); /* { dg-warning "use of both" "use of space and + flags" } */
+  printf ("% +d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
+  printf ("%+ d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
   printf ("% d% i% f% e% E% g% G\n", i, i, d, d, d, d, d);
   printf ("% o", u); /* { dg-warning "flag" "bad use of space flag" } */
   printf ("% u", u); /* { dg-warning "flag" "bad use of space flag" } */
@@ -176,17 +176,17 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
   printf ("%08.5X", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
   printf ("%08.5f%08.5e%08.5E%08.5g%08.5G", d, d, d, d, d);
   /* 0 flag ignored with - flag.  */
-  printf ("%-08d", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08i", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08o", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08u", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08x", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08X", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08e", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08E", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08f", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08g", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08G", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
+  printf ("%-08d", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08i", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08o", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08u", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08x", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08X", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08e", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08E", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08f", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08g", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08G", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
   /* Various tests of bad argument types.  */
   printf ("%d", l); /* { dg-warning "format" "bad argument types" } */
   printf ("%*.*d", l, i2, i); /* { dg-warning "field" "bad * argument types" } */
index f175ba8630b678522340b788da26cf09385dfb2e..f1da57aff88f1f53a8d288e15c4f775f5ccd4d89 100644 (file)
@@ -44,7 +44,7 @@ foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
   /* Valid, invalid and silly assignment-suppression constructions.  */
   scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
   scanf ("%*2d%*8s%*3c");
-  scanf ("%*n"); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
   scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
   /* Valid, invalid and silly width constructions.  */
   scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
index d03e798b1edb5cc4d7487e8b272dde5e26777683..304be531657466e2424e9563efdf80a996c3cc08 100644 (file)
@@ -155,8 +155,8 @@ foo (int i, unsigned int u, double d, char *s, void *p, int *n,
   /* Uses of the space flag (valid on signed conversions only, and ignored
      with +).
   */
-  printf ("% +d", i); /* { dg-warning "use of both" "use of space and + flags" } */
-  printf ("%+ d", i); /* { dg-warning "use of both" "use of space and + flags" } */
+  printf ("% +d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
+  printf ("%+ d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
   printf ("% d% i% f% F% e% E% g% G% a% A\n", i, i, d, d, d, d, d, d, d, d);
   printf ("% o", u); /* { dg-warning "flag" "bad use of space flag" } */
   printf ("% u", u); /* { dg-warning "flag" "bad use of space flag" } */
@@ -193,20 +193,20 @@ foo (int i, unsigned int u, double d, char *s, void *p, int *n,
   printf ("%08.5f%08.5F%08.5e%08.5E%08.5g%08.5G%08.5a%08.5A",
          d, d, d, d, d, d, d, d);
   /* 0 flag ignored with - flag.  */
-  printf ("%-08d", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08i", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08o", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08u", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08x", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08X", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08e", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08E", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08f", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08F", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08g", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08G", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08a", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
-  printf ("%-08A", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
+  printf ("%-08d", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08i", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08o", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08u", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08x", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08X", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08e", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08E", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08f", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08F", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08g", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08G", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08a", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
   /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
      here just test for pointer target sign with %hhn.  (Probably allowed
      by the standard, but a bad idea, so GCC should diagnose if what
index fec05869a6d451f747ed5abbf82b1e3ac8dbd285..447d51eaed80d622e933e65dcb0ae9213c05fc0f 100644 (file)
@@ -47,7 +47,7 @@ foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
   */
   scanf ("%*d%*i%*o%*u%*x%*X%*a%*A%*e%*E%*f%*F%*g%*G%*s%*[abc]%*c%*p");
   scanf ("%*2d%*8s%*3c");
-  scanf ("%*n"); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
   scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
   scanf ("%2d%3i%4o%5u%6x%7X%8a%9A%10e%11E%12f%13F%14g%15G%16s%3[abc]%4c%5p",
         ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, fp, fp, fp,
index 4ab0a4190a7df39c8e3cbc9eea2e2138365c46aa..187fc7ceb492866415f66518e0bb1c25097fb2f0 100644 (file)
@@ -31,69 +31,71 @@ foo (char *s, size_t m, const struct tm *tp)
   */
   strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
   /* Bad uses of %E and %O.  */
-  strftime (s, m, "%EEY", tp); /* { dg-warning "multiple" "multiple %E/%O" } */
-  strftime (s, m, "%EOY", tp); /* { dg-warning "multiple" "multiple %E/%O" } */
-  strftime (s, m, "%OEV", tp); /* { dg-warning "multiple" "multiple %E/%O" } */
-  strftime (s, m, "%OOV", tp); /* { dg-warning "multiple" "multiple %E/%O" } */
-  strftime (s, m, "%Ea", tp); /* { dg-warning "flag" "bad %Ea" } */
-  strftime (s, m, "%EA", tp); /* { dg-warning "flag" "bad %EA" } */
-  strftime (s, m, "%Eb", tp); /* { dg-warning "flag" "bad %Eb" } */
-  strftime (s, m, "%EB", tp); /* { dg-warning "flag" "bad %EB" } */
-  strftime (s, m, "%Ed", tp); /* { dg-warning "flag" "bad %Ed" } */
-  strftime (s, m, "%ED", tp); /* { dg-warning "flag" "bad %ED" } */
-  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 43 } */
-  strftime (s, m, "%Ee", tp); /* { dg-warning "flag" "bad %Ee" } */
-  strftime (s, m, "%EF", tp); /* { dg-warning "flag" "bad %EF" } */
-  strftime (s, m, "%Eg", tp); /* { dg-warning "flag" "bad %Eg" } */
-  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 47 } */
-  strftime (s, m, "%EG", tp); /* { dg-warning "flag" "bad %EG" } */
-  strftime (s, m, "%Eh", tp); /* { dg-warning "flag" "bad %Eh" } */
-  strftime (s, m, "%EH", tp); /* { dg-warning "flag" "bad %EH" } */
-  strftime (s, m, "%EI", tp); /* { dg-warning "flag" "bad %EI" } */
-  strftime (s, m, "%Ej", tp); /* { dg-warning "flag" "bad %Ej" } */
-  strftime (s, m, "%Em", tp); /* { dg-warning "flag" "bad %Em" } */
-  strftime (s, m, "%EM", tp); /* { dg-warning "flag" "bad %EM" } */
-  strftime (s, m, "%En", tp); /* { dg-warning "flag" "bad %En" } */
-  strftime (s, m, "%Ep", tp); /* { dg-warning "flag" "bad %Ep" } */
-  strftime (s, m, "%Er", tp); /* { dg-warning "flag" "bad %Er" } */
-  strftime (s, m, "%ER", tp); /* { dg-warning "flag" "bad %ER" } */
-  strftime (s, m, "%ES", tp); /* { dg-warning "flag" "bad %ES" } */
-  strftime (s, m, "%Et", tp); /* { dg-warning "flag" "bad %Et" } */
-  strftime (s, m, "%ET", tp); /* { dg-warning "flag" "bad %ET" } */
-  strftime (s, m, "%Eu", tp); /* { dg-warning "flag" "bad %Eu" } */
-  strftime (s, m, "%EU", tp); /* { dg-warning "flag" "bad %EU" } */
-  strftime (s, m, "%EV", tp); /* { dg-warning "flag" "bad %EV" } */
-  strftime (s, m, "%Ew", tp); /* { dg-warning "flag" "bad %Ew" } */
-  strftime (s, m, "%EW", tp); /* { dg-warning "flag" "bad %EW" } */
-  strftime (s, m, "%Ez", tp); /* { dg-warning "flag" "bad %Ez" } */
-  strftime (s, m, "%EZ", tp); /* { dg-warning "flag" "bad %EZ" } */
-  strftime (s, m, "%E%", tp); /* { dg-warning "flag" "bad %E%" } */
-  strftime (s, m, "%Oa", tp); /* { dg-warning "flag" "bad %Oa" } */
-  strftime (s, m, "%OA", tp); /* { dg-warning "flag" "bad %OA" } */
-  strftime (s, m, "%Ob", tp); /* { dg-warning "flag" "bad %Ob" } */
-  strftime (s, m, "%OB", tp); /* { dg-warning "flag" "bad %OB" } */
-  strftime (s, m, "%Oc", tp); /* { dg-warning "flag" "bad %Oc" } */
-  /* { dg-warning "in some locales" "2-digit year" { target *-*-* } 75 } */
-  strftime (s, m, "%OC", tp); /* { dg-warning "flag|C" "bad %OC" } */
-  strftime (s, m, "%OD", tp); /* { dg-warning "flag" "bad %OD" } */
-  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 78 } */
-  strftime (s, m, "%OF", tp); /* { dg-warning "flag" "bad %OF" } */
-  strftime (s, m, "%Og", tp); /* { dg-warning "flag|C" "bad %Og" } */
-  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 81 } */
-  strftime (s, m, "%OG", tp); /* { dg-warning "flag|C" "bad %OG" } */
-  strftime (s, m, "%Oh", tp); /* { dg-warning "flag" "bad %Oh" } */
-  strftime (s, m, "%Oj", tp); /* { dg-warning "flag|C" "bad %Oj" } */
-  strftime (s, m, "%On", tp); /* { dg-warning "flag" "bad %On" } */
-  strftime (s, m, "%Op", tp); /* { dg-warning "flag" "bad %Op" } */
-  strftime (s, m, "%Or", tp); /* { dg-warning "flag" "bad %Or" } */
-  strftime (s, m, "%OR", tp); /* { dg-warning "flag" "bad %OR" } */
-  strftime (s, m, "%Ot", tp); /* { dg-warning "flag" "bad %Ot" } */
-  strftime (s, m, "%OT", tp); /* { dg-warning "flag" "bad %OT" } */
-  strftime (s, m, "%Ox", tp); /* { dg-warning "flag" "bad %Ox" } */
-  /* { dg-warning "in some locales" "2-digit year" { target *-*-* } 92 } */
-  strftime (s, m, "%OX", tp); /* { dg-warning "flag" "bad %OX" } */
-  strftime (s, m, "%OY", tp); /* { dg-warning "flag|C" "bad %OY" } */
-  strftime (s, m, "%Oz", tp); /* { dg-warning "flag|C" "bad %Oz" } */
-  strftime (s, m, "%OZ", tp); /* { dg-warning "flag" "bad %OZ" } */
-  strftime (s, m, "%O%", tp); /* { dg-warning "flag" "bad %O%" } */
+  strftime (s, m, "%EEY", tp); /* { dg-warning "multiple|repeated" "multiple %E/%O" } */
+  strftime (s, m, "%EOy", tp); /* { dg-warning "multiple|together" "multiple %E/%O" } */
+  strftime (s, m, "%OEy", tp); /* { dg-warning "multiple|together" "multiple %E/%O" } */
+  strftime (s, m, "%OOV", tp); /* { dg-warning "multiple|repeated" "multiple %E/%O" } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 35 } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 36 } */
+  strftime (s, m, "%Ea", tp); /* { dg-warning "flag|modifier" "bad %Ea" } */
+  strftime (s, m, "%EA", tp); /* { dg-warning "flag|modifier" "bad %EA" } */
+  strftime (s, m, "%Eb", tp); /* { dg-warning "flag|modifier" "bad %Eb" } */
+  strftime (s, m, "%EB", tp); /* { dg-warning "flag|modifier" "bad %EB" } */
+  strftime (s, m, "%Ed", tp); /* { dg-warning "flag|modifier" "bad %Ed" } */
+  strftime (s, m, "%ED", tp); /* { dg-warning "flag|modifier" "bad %ED" } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 45 } */
+  strftime (s, m, "%Ee", tp); /* { dg-warning "flag|modifier" "bad %Ee" } */
+  strftime (s, m, "%EF", tp); /* { dg-warning "flag|modifier" "bad %EF" } */
+  strftime (s, m, "%Eg", tp); /* { dg-warning "flag|modifier" "bad %Eg" } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 49 } */
+  strftime (s, m, "%EG", tp); /* { dg-warning "flag|modifier" "bad %EG" } */
+  strftime (s, m, "%Eh", tp); /* { dg-warning "flag|modifier" "bad %Eh" } */
+  strftime (s, m, "%EH", tp); /* { dg-warning "flag|modifier" "bad %EH" } */
+  strftime (s, m, "%EI", tp); /* { dg-warning "flag|modifier" "bad %EI" } */
+  strftime (s, m, "%Ej", tp); /* { dg-warning "flag|modifier" "bad %Ej" } */
+  strftime (s, m, "%Em", tp); /* { dg-warning "flag|modifier" "bad %Em" } */
+  strftime (s, m, "%EM", tp); /* { dg-warning "flag|modifier" "bad %EM" } */
+  strftime (s, m, "%En", tp); /* { dg-warning "flag|modifier" "bad %En" } */
+  strftime (s, m, "%Ep", tp); /* { dg-warning "flag|modifier" "bad %Ep" } */
+  strftime (s, m, "%Er", tp); /* { dg-warning "flag|modifier" "bad %Er" } */
+  strftime (s, m, "%ER", tp); /* { dg-warning "flag|modifier" "bad %ER" } */
+  strftime (s, m, "%ES", tp); /* { dg-warning "flag|modifier" "bad %ES" } */
+  strftime (s, m, "%Et", tp); /* { dg-warning "flag|modifier" "bad %Et" } */
+  strftime (s, m, "%ET", tp); /* { dg-warning "flag|modifier" "bad %ET" } */
+  strftime (s, m, "%Eu", tp); /* { dg-warning "flag|modifier" "bad %Eu" } */
+  strftime (s, m, "%EU", tp); /* { dg-warning "flag|modifier" "bad %EU" } */
+  strftime (s, m, "%EV", tp); /* { dg-warning "flag|modifier" "bad %EV" } */
+  strftime (s, m, "%Ew", tp); /* { dg-warning "flag|modifier" "bad %Ew" } */
+  strftime (s, m, "%EW", tp); /* { dg-warning "flag|modifier" "bad %EW" } */
+  strftime (s, m, "%Ez", tp); /* { dg-warning "flag|modifier" "bad %Ez" } */
+  strftime (s, m, "%EZ", tp); /* { dg-warning "flag|modifier" "bad %EZ" } */
+  strftime (s, m, "%E%", tp); /* { dg-warning "flag|modifier" "bad %E%" } */
+  strftime (s, m, "%Oa", tp); /* { dg-warning "flag|modifier" "bad %Oa" } */
+  strftime (s, m, "%OA", tp); /* { dg-warning "flag|modifier" "bad %OA" } */
+  strftime (s, m, "%Ob", tp); /* { dg-warning "flag|modifier" "bad %Ob" } */
+  strftime (s, m, "%OB", tp); /* { dg-warning "flag|modifier" "bad %OB" } */
+  strftime (s, m, "%Oc", tp); /* { dg-warning "flag|modifier" "bad %Oc" } */
+  /* { dg-warning "in some locales" "2-digit year" { target *-*-* } 77 } */
+  strftime (s, m, "%OC", tp); /* { dg-warning "flag|modifier|C" "bad %OC" } */
+  strftime (s, m, "%OD", tp); /* { dg-warning "flag|modifier" "bad %OD" } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 80 } */
+  strftime (s, m, "%OF", tp); /* { dg-warning "flag|modifier" "bad %OF" } */
+  strftime (s, m, "%Og", tp); /* { dg-warning "flag|modifier|C" "bad %Og" } */
+  /* { dg-warning "only last 2" "2-digit year" { target *-*-* } 83 } */
+  strftime (s, m, "%OG", tp); /* { dg-warning "flag|modifier|C" "bad %OG" } */
+  strftime (s, m, "%Oh", tp); /* { dg-warning "flag|modifier" "bad %Oh" } */
+  strftime (s, m, "%Oj", tp); /* { dg-warning "flag|modifier|C" "bad %Oj" } */
+  strftime (s, m, "%On", tp); /* { dg-warning "flag|modifier" "bad %On" } */
+  strftime (s, m, "%Op", tp); /* { dg-warning "flag|modifier" "bad %Op" } */
+  strftime (s, m, "%Or", tp); /* { dg-warning "flag|modifier" "bad %Or" } */
+  strftime (s, m, "%OR", tp); /* { dg-warning "flag|modifier" "bad %OR" } */
+  strftime (s, m, "%Ot", tp); /* { dg-warning "flag|modifier" "bad %Ot" } */
+  strftime (s, m, "%OT", tp); /* { dg-warning "flag|modifier" "bad %OT" } */
+  strftime (s, m, "%Ox", tp); /* { dg-warning "flag|modifier" "bad %Ox" } */
+  /* { dg-warning "in some locales" "2-digit year" { target *-*-* } 94 } */
+  strftime (s, m, "%OX", tp); /* { dg-warning "flag|modifier" "bad %OX" } */
+  strftime (s, m, "%OY", tp); /* { dg-warning "flag|modifier|C" "bad %OY" } */
+  strftime (s, m, "%Oz", tp); /* { dg-warning "flag|modifier|C" "bad %Oz" } */
+  strftime (s, m, "%OZ", tp); /* { dg-warning "flag|modifier" "bad %OZ" } */
+  strftime (s, m, "%O%", tp); /* { dg-warning "flag|modifier" "bad %O%" } */
 }
index 27f2f7ed65ddeaa5a2c5531bc57d8ad78752a0ce..26d13249a992f1d64009bb58da777f84d8ed5882 100644 (file)
@@ -210,5 +210,5 @@ foo (char *s, size_t m, const struct tm *tp)
      covered in c99-strftime-1.c, except for the extension %P.
   */
   strftime (s, m, "%OC%Og%OG%Oj%OY%Oz%Ok%Ol%Os", tp); /* { dg-warning "only last 2" "2-digit year" } */
-  strftime (s, m, "%OP", tp); /* { dg-warning "flag" "bad %OP" } */
+  strftime (s, m, "%OP", tp); /* { dg-warning "flag|modifier" "bad %OP" } */
 }
index c57855a110a9cb1b1c8d09138987a1ec6c0f8713..0eb8d70eaa740542b3a380499d2607c2d5a061ba 100644 (file)
@@ -119,4 +119,5 @@ 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 ("%2$d%1$d", i, i, i); /* { dg-warning "unused" "unused $ operand" } */
   vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  scanf ("%1$*d%1$d", ip); /* { dg-warning "operand" "operand number with suppression" } */
 }