This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch for X/Open %n$ format checking, and more testcases


This patch fixes the support for X/Open $ operand number formats (%n$
meaning to use the nth argument, and *n$ similarly for width and
precision) to work properly (previously only supported for printf %n$,
not for scanf or width or precision) and to follow the X/Open specs.
$ formats cannot be mixed with non-$ ones, except for those formats
(%% and scanf %*) that do not use arguments.  There must not be gaps
in the numbers of the arguments selected by the format (since the
implementation wouldn't know in such a case what types to pass to
va_arg).

It also fixes a bug in the checking of vprintf formats with precision
'*', and adds some additional testcases (mostly not relating to the
patch but simply providing more thorough testing of format checking).
With the patch applied, all these added tests pass except for the
xfails for lack of intmax_t.

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit?

gcc/ChangeLog:
2000-08-21  Joseph S. Myers  <jsm28@cam.ac.uk>

	* c-common.c (init_dollar_format_checking,
	maybe_read_dollar_number, finish_dollar_format_checking): New
	functions.
	(dollar_arguments_used, dollar_arguments_count,
	dollar_first_arg_num, dollar_max_arg_used, dollar_format_warned):
	New variables.
	(check_format_info): Support $ formats for scanf and printf width
	and precision.  Always increment format_chars to advance past the
	'*' of precision, not just when the format parameters are
	available to check.

gcc/testsuite/ChangeLog:
2000-08-21  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/c90-printf-3.c, gcc.dg/c90-scanf-2.c,
	gcc.dg/c90-scanf-3.c, gcc.dg/c90-scanf-4.c,
	gcc.dg/c90-strftime-1.c, gcc.dg/c99-printf-3.c,
	gcc.dg/c99-scanf-1.c, gcc.dg/c99-scanf-2.c, gcc.dg/c99-scanf-3.c,
	gcc.dg/format-xopen-1.c: New tests.

--- c-common.c.orig	Sun Aug 20 19:34:46 2000
+++ c-common.c	Sun Aug 20 22:15:15 2000
@@ -1324,6 +1324,11 @@ static international_format_info *intern
 
 static void check_format_info	PARAMS ((function_format_info *, tree));
 
+static void init_dollar_format_checking		PARAMS ((int, tree));
+static int maybe_read_dollar_number		PARAMS ((const char **, int,
+							 tree, tree *));
+static void finish_dollar_format_checking	PARAMS ((void));
+
 /* Initialize the table of functions to perform format checking on.
    The ISO C functions are always checked (whether <stdio.h> is
    included or not), since it is common to call printf without
@@ -1501,6 +1506,169 @@ check_function_format (name, assembler_n
     }
 }
 
+
+/* Variables used by the checking of $ operand number formats.  */
+static char *dollar_arguments_used = NULL;
+static int dollar_arguments_alloc = 0;
+static int dollar_arguments_count;
+static int dollar_first_arg_num;
+static int dollar_max_arg_used;
+static int dollar_format_warned;
+
+/* Initialize the checking for a format string that may contain $
+   parameter number specifications; we will need to keep track of whether
+   each parameter has been used.  FIRST_ARG_NUM is the number of the first
+   argument that is a parameter to the format, or 0 for a vprintf-style
+   function; PARAMS is the list of arguments starting at this argument.  */
+
+static void
+init_dollar_format_checking (first_arg_num, params)
+     int first_arg_num;
+     tree params;
+{
+  dollar_first_arg_num = first_arg_num;
+  dollar_arguments_count = 0;
+  dollar_max_arg_used = 0;
+  dollar_format_warned = 0;
+  if (first_arg_num > 0)
+    {
+      while (params)
+	{
+	  dollar_arguments_count++;
+	  params = TREE_CHAIN (params);
+	}
+    }
+  if (dollar_arguments_alloc < dollar_arguments_count)
+    {
+      if (dollar_arguments_used)
+	free (dollar_arguments_used);
+      dollar_arguments_alloc = dollar_arguments_count;
+      dollar_arguments_used = xmalloc (dollar_arguments_alloc);
+    }
+  if (dollar_arguments_alloc)
+    memset (dollar_arguments_used, 0, dollar_arguments_alloc);
+}
+
+
+/* Look for a decimal number followed by a $ in *FORMAT.  If DOLLAR_NEEDED
+   is set, it is an error if one is not found; otherwise, it is OK.  If
+   such a number is found, check whether it is within range and mark that
+   numbered operand as being used for later checking.  Returns the operand
+   number if found and within range, zero if no such number was found and
+   this is OK, or -1 on error.  PARAMS points to the first operand of the
+   format; PARAM_PTR is made to point to the parameter referred to.  If
+   a $ format is found, *FORMAT is updated to point just after it.  */
+
+static int
+maybe_read_dollar_number (format, dollar_needed, params, param_ptr)
+     const char **format;
+     int dollar_needed;
+     tree params;
+     tree *param_ptr;
+{
+  int argnum;
+  int overflow_flag;
+  const char *fcp = *format;
+  if (*fcp < '0' || *fcp > '9')
+    {
+      if (dollar_needed)
+	{
+	  warning ("missing $ operand number in format");
+	  return -1;
+	}
+      else
+	return 0;
+    }
+  argnum = 0;
+  overflow_flag = 0;
+  while (*fcp >= '0' && *fcp <= '9')
+    {
+      int nargnum;
+      nargnum = 10 * argnum + (*fcp - '0');
+      if (nargnum < 0 || nargnum / 10 != argnum)
+	overflow_flag = 1;
+      argnum = nargnum;
+      fcp++;
+    }
+  if (*fcp != '$')
+    {
+      if (dollar_needed)
+	{
+	  warning ("missing $ operand number in format");
+	  return -1;
+	}
+      else
+	return 0;
+    }
+  *format = fcp + 1;
+  if (pedantic && !dollar_format_warned)
+    {
+      warning ("ISO C does not support %%n$ operand number formats");
+      dollar_format_warned = 1;
+    }
+  if (overflow_flag || argnum == 0
+      || (dollar_first_arg_num && argnum > dollar_arguments_count))
+    {
+      warning ("operand number out of range in format");
+      return -1;
+    }
+  if (argnum > dollar_max_arg_used)
+    dollar_max_arg_used = argnum;
+  /* For vprintf-style functions we may need to allocate more memory to
+     track which arguments are used.  */
+  while (dollar_arguments_alloc < dollar_max_arg_used)
+    {
+      int nalloc;
+      nalloc = 2 * dollar_arguments_alloc + 16;
+      dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc);
+      memset (dollar_arguments_used + dollar_arguments_alloc, 0,
+	      nalloc - dollar_arguments_alloc);
+      dollar_arguments_alloc = nalloc;
+    }
+  dollar_arguments_used[argnum - 1] = 1;
+  if (dollar_first_arg_num)
+    {
+      int i;
+      *param_ptr = params;
+      for (i = 1; i < argnum && *param_ptr != 0; i++)
+	*param_ptr = TREE_CHAIN (*param_ptr);
+
+      if (*param_ptr == 0)
+	{
+	  /* This case shouldn't be caught here.  */
+	  abort ();
+	}
+    }
+  else
+    *param_ptr = 0;
+  return argnum;
+}
+
+
+/* Finish the checking for a format string that used $ operand number formats
+   instead of non-$ formats.  We check for unused operands before used ones
+   (a serious error, since the implementation of the format function
+   can't know what types to pass to va_arg to find the later arguments).
+   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
+   numbers out of range on a non-vprintf-style format, we won't have reached
+   here.  */
+
+static void
+finish_dollar_format_checking ()
+{
+  int i;
+  for (i = 0; i < dollar_max_arg_used; i++)
+    {
+      if (!dollar_arguments_used[i])
+	warning ("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)
+    warning ("unused arguments in $-style format");
+}
+
+
 /* 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.  */
@@ -1524,7 +1692,9 @@ check_format_info (info, params)
   const char *format_chars;
   format_char_info *fci = NULL;
   char flag_chars[8];
-  int has_operand_number = 0;
+  /* -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;
 
   /* Skip to format argument.  If the argument isn't available, there's
      no work for us to do; prototype checking will catch the problem.  */
@@ -1624,6 +1794,7 @@ check_format_info (info, params)
     }
 
   first_fillin_param = params;
+  init_dollar_format_checking (info->first_arg_num, first_fillin_param);
   while (1)
     {
       int aflag;
@@ -1633,8 +1804,11 @@ check_format_info (info, params)
 	{
 	  if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
 	    warning ("embedded `\\0' in format");
-	  if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
+	  if (info->first_arg_num != 0 && params != 0
+	      && has_operand_number <= 0)
 	    warning ("too many arguments for format");
+	  if (has_operand_number > 0)
+	    finish_dollar_format_checking ();
 	  return;
 	}
       if (*format_chars++ != '%')
@@ -1657,6 +1831,22 @@ check_format_info (info, params)
 	  suppressed = *format_chars == '*';
 	  if (suppressed)
 	    ++format_chars;
+	  else if (has_operand_number != 0)
+	    {
+	      int opnum;
+	      opnum = maybe_read_dollar_number (&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;
+	    }
 	  while (ISDIGIT (*format_chars))
 	    {
 	      wide = TRUE;
@@ -1709,35 +1899,21 @@ check_format_info (info, params)
 	}
       else if (info->format_type == printf_format_type)
 	{
-	  /* See if we have a number followed by a dollar sign.  If we do,
-	     it is an operand number, so set PARAMS to that operand.  */
-	  if (*format_chars >= '0' && *format_chars <= '9')
+	  if (has_operand_number != 0)
 	    {
-	      const char *p = format_chars;
-
-	      while (*p >= '0' && *p++ <= '9')
-		;
-
-	      if (*p == '$')
+	      int opnum;
+	      opnum = maybe_read_dollar_number (&format_chars,
+						has_operand_number == 1,
+						first_fillin_param, &params);
+	      if (opnum == -1)
+		return;
+	      else if (opnum > 0)
 		{
-		  int opnum = atoi (format_chars);
-
-		  if (pedantic)
-		    warning ("ISO C does not support printf %%n$");
-
-		  params = first_fillin_param;
-		  format_chars = p + 1;
 		  has_operand_number = 1;
-
-		  for (i = 1; i < opnum && params != 0; i++)
-		    params = TREE_CHAIN (params);
-
-		  if (opnum == 0 || params == 0)
-		    {
-		      warning ("operand number out of range in format");
-		      return;
-		    }
+		  arg_num = opnum + info->first_arg_num - 1;
 		}
+	      else
+		has_operand_number = 0;
 	    }
 
 	  while (*format_chars != 0 && index (" +#0-'", *format_chars) != 0)
@@ -1774,11 +1950,25 @@ check_format_info (info, params)
 		  tfaff ();
 		  return;
 		}
+	      if (has_operand_number > 0)
+		{
+		  int opnum;
+		  opnum = maybe_read_dollar_number (&format_chars, 1,
+						    first_fillin_param,
+						    &params);
+		  if (opnum <= 0)
+		    return;
+		  else
+		    arg_num = opnum + info->first_arg_num - 1;
+		}
 	      if (info->first_arg_num != 0)
 		{
 		  cur_param = TREE_VALUE (params);
-		  params = TREE_CHAIN (params);
-		  ++arg_num;
+		  if (has_operand_number <= 0)
+		    {
+		      params = TREE_CHAIN (params);
+		      ++arg_num;
+		    }
 		  /* size_t is generally not valid here.
 		     It will work on most machines, because size_t and int
 		     have the same mode.  But might as well warn anyway,
@@ -1807,17 +1997,31 @@ check_format_info (info, params)
 		 In this case, an int argument supplies the...precision."  */
 	      if (*format_chars == '*')
 		{
+		  ++format_chars;
+		  if (has_operand_number > 0)
+		    {
+		      int opnum;
+		      opnum = maybe_read_dollar_number (&format_chars, 1,
+							first_fillin_param,
+							&params);
+		      if (opnum <= 0)
+			return;
+		      else
+			arg_num = opnum + info->first_arg_num - 1;
+		    }
 		  if (info->first_arg_num != 0)
 		    {
-		      ++format_chars;
 		      if (params == 0)
 		        {
 			  tfaff ();
 			  return;
 			}
 		      cur_param = TREE_VALUE (params);
-		      params = TREE_CHAIN (params);
-		      ++arg_num;
+		      if (has_operand_number <= 0)
+			{
+			  params = TREE_CHAIN (params);
+			  ++arg_num;
+			}
 		      if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
 			   != integer_type_node)
 			  &&
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c90-printf-3.c	Sun Aug 20 21:24:20 2000
@@ -0,0 +1,60 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+/* This may not be correct in the particular case, but allows the
+   prototypes to be declared, and we don't try to link.
+*/
+typedef struct _FILE FILE;
+extern FILE *stdout;
+
+typedef __SIZE_TYPE__ size_t;
+typedef __builtin_va_list va_list;
+
+extern int fprintf (FILE *, const char *, ...);
+extern int printf (const char *, ...);
+extern int sprintf (char *, const char *, ...);
+extern int vfprintf (FILE *, const char *, va_list);
+extern int vprintf (const char *, va_list);
+extern int vsprintf (char *, const char *, va_list);
+
+extern int snprintf (char *, size_t, const char *, ...);
+extern int vsnprintf (char *, size_t, const char *, va_list);
+
+extern char *gettext (const char *);
+extern char *dgettext (const char *, const char *);
+extern char *dcgettext (const char *, const char *, int);
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "vsprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c90-scanf-2.c	Fri Aug 18 22:02:24 2000
@@ -0,0 +1,37 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+__extension__ typedef long long int llong;
+
+/* This next definition is broken.  When GCC has a <stdint.h> and
+   an internal understanding of intmax_t, it should be
+   replaced by an include of <stdint.h> or by a definition for internal
+   macros or typedefs.
+*/
+__extension__ typedef long long int intmax_t;
+
+extern int scanf (const char *, ...);
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "length character|C" "%hh in C90" } */
+  scanf ("%lld", llp); /* { dg-warning "length character|C" "%ll in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "length character|C" "%j in C90" } */
+  scanf ("%zu", zp); /* { dg-warning "length character|C" "%z in C90" } */
+  scanf ("%td", tp); /* { dg-warning "length character|C" "%t in C90" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "C" "%F in C90" } */
+  scanf ("%a", fp); /* { dg-warning "C" "%a in C90" } */
+  scanf ("%A", fp); /* { dg-warning "C" "%A in C90" } */
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c90-scanf-3.c	Sat Aug 19 18:50:07 2000
@@ -0,0 +1,21 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+typedef __WCHAR_TYPE__ wchar_t;
+
+extern int scanf (const char *, ...);
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognised in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "C" "%as" } */
+  scanf ("%aS", lsp); /* { dg-warning "C" "%aS" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "C" "%a[]" } */
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c90-scanf-4.c	Sun Aug 20 01:26:02 2000
@@ -0,0 +1,51 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+/* This may not be correct in the particular case, but allows the
+   prototypes to be declared, and we don't try to link.
+*/
+typedef struct _FILE FILE;
+extern FILE *stdin;
+
+typedef __builtin_va_list va_list;
+
+extern int fscanf (FILE *, const char *, ...);
+extern int scanf (const char *, ...);
+extern int sscanf (const char *, const char *, ...);
+
+extern int vfscanf (FILE *, const char *, va_list);
+extern int vscanf (const char *, va_list);
+extern int vsscanf (const char *, const char *, va_list);
+
+extern char *gettext (const char *);
+extern char *dgettext (const char *, const char *);
+extern char *dcgettext (const char *, const char *, int);
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1);
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3);
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c90-strftime-1.c	Mon Aug 21 01:36:03 2000
@@ -0,0 +1,23 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct tm;
+
+extern size_t strftime (char *, size_t, const char *, const struct tm *);
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c99-printf-3.c	Sun Aug 20 01:28:08 2000
@@ -0,0 +1,56 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+/* This may not be correct in the particular case, but allows the
+   prototypes to be declared, and we don't try to link.
+*/
+typedef struct _FILE FILE;
+extern FILE *stdout;
+
+typedef __SIZE_TYPE__ size_t;
+typedef __builtin_va_list va_list;
+
+extern int fprintf (FILE *restrict, const char *restrict, ...);
+extern int printf (const char *restrict, ...);
+extern int sprintf (char *restrict, const char *restrict, ...);
+extern int vfprintf (FILE *restrict, const char *restrict, va_list);
+extern int vprintf (const char *restrict, va_list);
+extern int vsprintf (char *restrict, const char *restrict, va_list);
+extern int snprintf (char *restrict, size_t, const char *restrict, ...);
+extern int vsnprintf (char *restrict, size_t, const char *restrict, va_list);
+
+extern char *gettext (const char *);
+extern char *dgettext (const char *, const char *);
+extern char *dcgettext (const char *, const char *, int);
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c99-scanf-1.c	Sat Aug 19 18:47:19 2000
@@ -0,0 +1,165 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behaviour is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef __SIZE_TYPE__ signed_size_t;
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned __PTRDIFF_TYPE__ unsigned_ptrdiff_t;
+#undef signed
+
+/* These next definitions are broken.  When GCC has a <stdint.h> and
+   an internal understanding of intmax_t and uintmax_t, they should be
+   replaced by an include of <stdint.h> or by definitions for internal
+   macros or typedefs, and the corresponding xfails removed.
+*/
+typedef long long int intmax_t;
+typedef unsigned long long int uintmax_t;
+
+extern int scanf (const char *, ...);
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  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 ("%*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,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %ll, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%ha", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hA", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%he", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hF", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hs", s); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%h[ac]", s); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hc", s); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hp", pp); /* { dg-warning "length character" "bad use of %h" } */
+  scanf ("%hhd%hhi%hho%hhu%hhx%hhX%hhn", hhp, hhp, uhhp, uhhp, uhhp, uhhp,
+	 hhn);
+  scanf ("%hha", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhA", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhe", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhE", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhf", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhF", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhg", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhG", fp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhs", s); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hh[ac]", s); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhc", s); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%hhp", pp); /* { dg-warning "length character" "bad use of %hh" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%la%lA%le%lE%lf%lF%lg%lG", dp, dp, dp, dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length character" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%lld%lli%llo%llu%llx%llX%lln", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%lla", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llA", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%lle", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llE", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llf", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llF", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llg", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llG", fp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%lls", s); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%ll[ac]", s); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llc", s); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%llp", pp); /* { dg-warning "length character" "bad use of %ll" } */
+  scanf ("%jd%ji%jo%ju%jx%jX%jn", jp, jp, ujp, ujp, ujp, ujp, jn); /* { dg-bogus "length character" "bogus %j warning" { xfail *-*-* } } */
+  scanf ("%ja", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jA", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%je", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jE", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jf", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jF", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jg", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jG", fp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%js", s); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%j[ac]", s); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jc", s); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%jp", pp); /* { dg-warning "length character" "bad use of %j" } */
+  scanf ("%zd%zi%zo%zu%zx%zX%zn", szp, szp, zp, zp, zp, zp, zn);
+  scanf ("%za", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zA", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%ze", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zE", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zf", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zF", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zg", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zG", fp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zs", s); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%z[ac]", s); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zc", s); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%zp", pp); /* { dg-warning "length character" "bad use of %z" } */
+  scanf ("%td%ti%to%tu%tx%tX%tn", tp, tp, utp, utp, utp, utp, tn);
+  scanf ("%ta", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tA", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%te", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tE", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tf", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tF", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tg", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tG", fp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%ts", s); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%t[ac]", s); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tc", s); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%tp", pp); /* { dg-warning "length character" "bad use of %t" } */
+  scanf ("%La%LA%Le%LE%Lf%LF%Lg%LG", ldp, ldp, ldp, ldp, ldp, ldp, ldp, ldp);
+  scanf ("%Ld", llp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%Li", llp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%Lo", ullp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%Lu", ullp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%Lx", ullp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%LX", ullp); /* { dg-warning "does not support" "bad use of %L" } */
+  scanf ("%Ls", s); /* { dg-warning "length character" "bad use of %L" } */
+  scanf ("%L[ac]", s); /* { dg-warning "length character" "bad use of %L" } */
+  scanf ("%Lc", s); /* { dg-warning "length character" "bad use of %L" } */
+  scanf ("%Lp", pp); /* { dg-warning "length character" "bad use of %L" } */
+  scanf ("%Ln", n); /* { dg-warning "length character" "bad use of %L" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%a%A%e%E%f%F%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Assert that %as is not treated as an extension in C99 mode.  */
+  scanf ("%as", fp);
+  scanf ("%a[", fp);
+  /* Tests for bad argument types: pointer target sign with %hh.  */
+  scanf ("%hhd", uhhp); /* { dg-warning "format" "%hhd sign" } */
+  scanf ("%hhu", hhp); /* { dg-warning "format" "%hhu sign" } */
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c99-scanf-2.c	Sat Aug 19 18:46:52 2000
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+
+extern int scanf (const char *, ...);
+
+void
+foo (int *ip, long long int *llp, size_t *zp, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "C" "%q length" } */
+  scanf ("%Ld", llp); /* { dg-warning "C" "%L length" } */
+  scanf ("%Zu", zp); /* { dg-warning "C" "%Z length" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ c99-scanf-3.c	Sun Aug 20 01:32:43 2000
@@ -0,0 +1,49 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+/* This may not be correct in the particular case, but allows the
+   prototypes to be declared, and we don't try to link.
+*/
+typedef struct _FILE FILE;
+extern FILE *stdin;
+
+typedef __builtin_va_list va_list;
+
+extern int fscanf (FILE *restrict, const char *restrict, ...);
+extern int scanf (const char *restrict, ...);
+extern int sscanf (const char *restrict, const char *restrict, ...);
+extern int vfscanf (FILE *restrict, const char *restrict, va_list);
+extern int vscanf (const char *restrict, va_list);
+extern int vsscanf (const char *restrict, const char *restrict, va_list);
+
+extern char *gettext (const char *);
+extern char *dgettext (const char *, const char *);
+extern char *dcgettext (const char *, const char *, int);
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ format-xopen-1.c	Mon Aug 21 17:53:08 2000
@@ -0,0 +1,118 @@
+/* Test for X/Open format extensions, as found in the
+   Single Unix Specification and in Austin Group draft 4, subject to some
+   Aardvark problem reports submitted.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __WINT_TYPE__ wint_t;
+typedef __builtin_va_list va_list;
+
+extern int printf (const char *, ...);
+extern int vprintf (const char *, va_list);
+extern int scanf (const char *, ...);
+
+void
+foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d,
+     char *s, void *p, int *n, long int l, int i2, float *fp, long int *lp,
+     va_list va)
+{
+  /* The conversion specifiers C and S, for both printf and scanf,
+     are X/Open extensions.
+  */
+  printf ("%C", lc);
+  printf ("%3C", lc);
+  printf ("%.3C", lc); /* { dg-warning "precision" "precision with %C" } */
+  printf ("%hC", lc); /* { dg-warning "length character" "bad %hC" } */
+  printf ("%hhC", lc); /* { dg-warning "length character" "bad %hhC" } */
+  printf ("%lC", lc); /* { dg-warning "length character" "bad %lC" } */
+  printf ("%llC", lc); /* { dg-warning "length character" "bad %llC" } */
+  printf ("%jC", lc); /* { dg-warning "length character" "bad %jC" } */
+  printf ("%zC", lc); /* { dg-warning "length character" "bad %zC" } */
+  printf ("%tC", lc); /* { dg-warning "length character" "bad %tC" } */
+  printf ("%LC", lc); /* { dg-warning "length character" "bad %LC" } */
+  printf ("%-C", lc);
+  printf ("%+C", lc); /* { dg-warning "flag" "bad %+C" } */
+  printf ("% C", lc); /* { dg-warning "flag" "bad % C" } */
+  printf ("%#C", lc); /* { dg-warning "flag" "bad %#C" } */
+  printf ("%0C", lc); /* { dg-warning "flag" "bad %0C" } */
+  printf ("%S", ls);
+  printf ("%3S", ls);
+  printf ("%.3S", ls);
+  printf ("%hS", ls); /* { dg-warning "length character" "bad %hS" } */
+  printf ("%hhS", ls); /* { dg-warning "length character" "bad %hhS" } */
+  printf ("%lS", ls); /* { dg-warning "length character" "bad %lS" } */
+  printf ("%llS", ls); /* { dg-warning "length character" "bad %llS" } */
+  printf ("%jS", ls); /* { dg-warning "length character" "bad %jS" } */
+  printf ("%zS", ls); /* { dg-warning "length character" "bad %zS" } */
+  printf ("%tS", ls); /* { dg-warning "length character" "bad %tS" } */
+  printf ("%LS", ls); /* { dg-warning "length character" "bad %LS" } */
+  printf ("%-S", ls);
+  printf ("%+S", ls); /* { dg-warning "flag" "bad %+S" } */
+  printf ("% S", ls); /* { dg-warning "flag" "bad % S" } */
+  printf ("%#S", ls); /* { dg-warning "flag" "bad %#S" } */
+  printf ("%0S", ls); /* { dg-warning "flag" "bad %0S" } */
+  scanf ("%C", ls);
+  scanf ("%S", ls);
+  scanf ("%*C%*S");
+  scanf ("%2C%3S", ls, ls);
+  scanf ("%hC", ls); /* { dg-warning "length character" "bad %hC" } */
+  scanf ("%hhC", ls); /* { dg-warning "length character" "bad %hhC" } */
+  scanf ("%lC", ls); /* { dg-warning "length character" "bad %lC" } */
+  scanf ("%llC", ls); /* { dg-warning "length character" "bad %llC" } */
+  scanf ("%jC", ls); /* { dg-warning "length character" "bad %jC" } */
+  scanf ("%zC", ls); /* { dg-warning "length character" "bad %zC" } */
+  scanf ("%tC", ls); /* { dg-warning "length character" "bad %tC" } */
+  scanf ("%LC", ls); /* { dg-warning "length character" "bad %LC" } */
+  scanf ("%hS", ls); /* { dg-warning "length character" "bad %hS" } */
+  scanf ("%hhS", ls); /* { dg-warning "length character" "bad %hhS" } */
+  scanf ("%lS", ls); /* { dg-warning "length character" "bad %lS" } */
+  scanf ("%llS", ls); /* { dg-warning "length character" "bad %llS" } */
+  scanf ("%jS", ls); /* { dg-warning "length character" "bad %jS" } */
+  scanf ("%zS", ls); /* { dg-warning "length character" "bad %zS" } */
+  scanf ("%tS", ls); /* { dg-warning "length character" "bad %tS" } */
+  scanf ("%LS", ls); /* { dg-warning "length character" "bad %LS" } */
+  /* In C99 mode (even with extensions), %aS is a floating point
+     format followed by an S.
+  */
+  scanf ("%aS", fp);
+  /* The printf flag character ' is an X/Open extension.  */
+  /* Allowing %'F here presumes acceptance of the corresponding Aardvark
+     report.
+  */
+  printf ("%'d%'i%'u%'f%'F%'g%'G", i, i, u, d, d, d, d);
+  printf ("%'o", u); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'x", u); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'X", u); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'e", d); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'E", d); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'a", d); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'A", d); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'c", i); /* { dg-warning "flag" "bad use of ' flag" } */
+  printf ("%'s", s); /* { 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" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  /* Banning gaps in the arguments used with scanf, and not objecting to
+     multiple use of an argument with scanf, presumes acceptance of the
+     corresponding Aardvark reports.
+  */
+  scanf ("%1$d", ip);
+  printf ("%1$d", i);
+  printf ("%3$*2$.*1$d", 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" } */
+  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" } */
+  printf ("%0$d", i); /* { dg-warning "operand" "$ number too small" } */
+  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" } */
+}

-- 
Joseph S. Myers
jsm28@cam.ac.uk


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]