More C99 format checking patches

Joseph S. Myers jsm28@cam.ac.uk
Sat Aug 5 15:55:00 GMT 2000


This patch makes some more C99-related printf/scanf format checking
changes.

Tree nodes are added for the signed type corresponding to size_t and
the unsigned type corresponding to ptrdiff_t, since those are the
types used by some C99 formats.  (The C language signed type
corresponding to size_t need not be the same as GCC's ssizetype, nor
the same as ptrdiff_t; nor need the unsigned version of ptrdiff_t be
the same as size_t, though size_t and ptrdiff_t do usually
correspond.)

Many miscellaneous fixes are made as detailed in the ChangeLog entry.
A thorough testcase is added.  The XFAILs relate to lack of genuine
support for %j; I'll submit a PR for this for completeness.

The pedantic checking is improved so that different signednesses of
char are not accepted as pointer targets for formats such as %hhn
(where the signedness is explicitly stated by the standard; %s may be
any character type).  While representations must agree, the programmer
should use the correct type in these cases.  This is the same
principle as GCC having always warned (not just with -pedantic) for
passing void * to %s even through the representations of the types are
the same and char * to %p is OK.

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

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

	* c-common.h (enum c_tree_index): Add CTI_SIGNED_SIZE_TYPE and
	CTI_UNSIGNED_PTRDIFF_TYPE.
	(signed_size_type_node): Define.
	(unsigned_ptrdiff_type_node): Define.
	* c-decl.c (init_decl_processing): Create the
	signed_size_type_node and unsigned_ptrdiff_type_node types.
	* c-common.c (T_SC): Define.
	(T_SST): Define.
	(T_UPD): Define.
	(print_char_table): Use T_SST for %zd, %zi, %zn.  Use T_UPD for
	%to, %tu, %tx, %tX.  Allow %hhn (T_SC).  Add "c" to the flags for
	%s and %p.
	(scan_char_table): Use T_SC for %hhd, %hhi, %hhn.  Use T_SST for
	%zd, %zi, %zn.  Use T_UPD for %to, %tu, %tx, %tX.  Add "c" to the
	flags for %c, %s and %[.
	(check_format_info): Only allow leniency for signedness of targets
	of character pointers (when pedantic) for formats flagged with
	"c", so for strings but not for %hh formats.  When pedantic, don't
	allow character pointers to substitute for void pointers if a
	second level of indirection is present.

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

	* gcc.dg/c99-printf-1.c: New test.

--- c-common.h.orig	Sat Aug  5 20:36:33 2000
+++ c-common.h	Sat Aug  5 20:36:56 2000
@@ -92,6 +92,8 @@ enum c_tree_index
     CTI_SIGNED_WCHAR_TYPE,
     CTI_UNSIGNED_WCHAR_TYPE,
     CTI_WINT_TYPE,
+    CTI_SIGNED_SIZE_TYPE, /* For format checking only.  */
+    CTI_UNSIGNED_PTRDIFF_TYPE, /* For format checking only.  */
     CTI_WIDEST_INT_LIT_TYPE,
     CTI_WIDEST_UINT_LIT_TYPE,
 
@@ -124,6 +126,8 @@ enum c_tree_index
 #define signed_wchar_type_node		c_global_trees[CTI_SIGNED_WCHAR_TYPE]
 #define unsigned_wchar_type_node	c_global_trees[CTI_UNSIGNED_WCHAR_TYPE]
 #define wint_type_node			c_global_trees[CTI_WINT_TYPE]
+#define signed_size_type_node		c_global_trees[CTI_SIGNED_SIZE_TYPE]
+#define unsigned_ptrdiff_type_node	c_global_trees[CTI_UNSIGNED_PTRDIFF_TYPE]
 #define widest_integer_literal_type_node c_global_trees[CTI_WIDEST_INT_LIT_TYPE]
 #define widest_unsigned_literal_type_node c_global_trees[CTI_WIDEST_UINT_LIT_TYPE]
 
--- c-decl.c.orig	Sat Aug  5 20:36:35 2000
+++ c-decl.c	Sat Aug  5 20:36:56 2000
@@ -3003,6 +3003,7 @@ init_decl_processing ()
      Note that stddef.h uses `unsigned long',
      and this must agree, even if long and int are the same size.  */
   t = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
+  signed_size_type_node = signed_type (t);
   if (flag_traditional && TREE_UNSIGNED (t))
     t = signed_type (t);
     
@@ -3086,6 +3087,7 @@ init_decl_processing ()
     = build_function_type (integer_type_node, NULL_TREE);
   ptrdiff_type_node
     = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
+  unsigned_ptrdiff_type_node = unsigned_type (ptrdiff_type_node);
 
   c_common_nodes_and_builtins (0, flag_no_builtin, flag_no_nonansi_builtin);
 
--- c-common.c.orig	Sat Aug  5 20:36:33 2000
+++ c-common.c	Sat Aug  5 20:38:01 2000
@@ -1190,12 +1190,15 @@ strip_attrs (specs_attrs)
 #define T_D	&double_type_node
 #define T_LD	&long_double_type_node
 #define T_C	&char_type_node
+#define T_SC	&signed_char_type_node
 #define T_UC	&unsigned_char_type_node
 #define T_V	&void_type_node
 #define T_W	&wchar_type_node
 #define T_WI	&wint_type_node
 #define T_ST    &sizetype
+#define T_SST   &signed_size_type_node
 #define T_PD    &ptrdiff_type_node
+#define T_UPD   &unsigned_ptrdiff_type_node
 #define T_IM    NULL /* intmax_t not yet implemented.  */
 #define T_UIM   NULL /* uintmax_t not yet implemented.  */
 
@@ -1233,33 +1236,33 @@ typedef struct {
 } format_char_info;
 
 static format_char_info print_char_table[] = {
-  { "di",	0,	T_I,	T_I,	T_I,	T_L,	T_LL,	T_LL,	T_ST,	T_PD,	T_IM,	"-wp0 +'"	},
-  { "oxX",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_PD,	T_UIM,	"-wp0#"		},
-  { "u",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_PD,	T_UIM,	"-wp0'"		},
+  { "di",	0,	T_I,	T_I,	T_I,	T_L,	T_LL,	T_LL,	T_SST,	T_PD,	T_IM,	"-wp0 +'"	},
+  { "oxX",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_UPD,	T_UIM,	"-wp0#"		},
+  { "u",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_UPD,	T_UIM,	"-wp0'"		},
 /* A GNU extension.  */
   { "m",	0,	T_V,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wp"		},
   { "fFgG",	0,	T_D,	NULL,	NULL,	T_D,	NULL,	T_LD,	NULL,	NULL,	NULL,	"-wp0 +#'"	},
   { "eEaA",	0,	T_D,	NULL,	NULL,	T_D,	NULL,	T_LD,	NULL,	NULL,	NULL,	"-wp0 +#"	},
   { "c",	0,	T_I,	NULL,	NULL,	T_WI,	NULL,	NULL,	NULL,	NULL,	NULL,	"-w"		},
   { "C",	0,	T_WI,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"-w"		},
-  { "s",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wp"		},
+  { "s",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wpc"		},
   { "S",	1,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wp"		},
-  { "p",	1,	T_V,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"-w"		},
-  { "n",	1,	T_I,	NULL,	T_S,	T_L,	T_LL,	NULL,	T_ST,	T_PD,	T_IM,	""		},
+  { "p",	1,	T_V,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wc"		},
+  { "n",	1,	T_I,	T_SC,	T_S,	T_L,	T_LL,	NULL,	T_SST,	T_PD,	T_IM,	""		},
   { NULL,	0,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL		}
 };
 
 static format_char_info scan_char_table[] = {
-  { "di",	1,	T_I,	T_C,	T_S,	T_L,	T_LL,	T_LL,	T_ST,	T_PD,	T_IM,	"*"	},
-  { "ouxX",	1,	T_UI,	T_UC,	T_US,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_PD,	T_UIM,	"*"	},
+  { "di",	1,	T_I,	T_SC,	T_S,	T_L,	T_LL,	T_LL,	T_SST,	T_PD,	T_IM,	"*"	},
+  { "ouxX",	1,	T_UI,	T_UC,	T_US,	T_UL,	T_ULL,	T_ULL,	T_ST,	T_UPD,	T_UIM,	"*"	},
   { "efFgEGaA",	1,	T_F,	NULL,	NULL,	T_D,	NULL,	T_LD,	NULL,	NULL,	NULL,	"*"	},
-  { "c",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*"	},
-  { "s",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*a"	},
-  { "[",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*a"	},
+  { "c",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*c"	},
+  { "s",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*ac"	},
+  { "[",	1,	T_C,	NULL,	NULL,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	"*ac"	},
   { "C",	1,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"*"	},
   { "S",	1,	T_W,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"*a"	},
   { "p",	2,	T_V,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"*"	},
-  { "n",	1,	T_I,	T_C,	T_S,	T_L,	T_LL,	NULL,	T_ST,	T_PD,	T_IM,	""	},
+  { "n",	1,	T_I,	T_SC,	T_S,	T_L,	T_LL,	NULL,	T_SST,	T_PD,	T_IM,	""	},
   { NULL,	0,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL	}
 };
 
@@ -2074,8 +2077,10 @@ check_format_info (info, params)
 		      || (DECL_P (cur_param) && TREE_READONLY (cur_param))))))
 	warning ("writing into constant object (arg %d)", arg_num);
 
-      /* Check whether the argument type is a character type.  */
-      if (TREE_CODE (cur_type) != ERROR_MARK)
+      /* Check whether the argument type is a character type.  This leniency
+	 only applies to certain formats, flagged with 'c'.
+      */
+      if (TREE_CODE (cur_type) != ERROR_MARK && index (fci->flag_chars, 'c') != 0)
 	char_type_flag = (TYPE_MAIN_VARIANT (cur_type) == char_type_node
 			  || TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
 			  || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node);
@@ -2093,7 +2098,7 @@ check_format_info (info, params)
 		&& fci->pointer_count > 0
 		&& (! pedantic
 		    || TYPE_MAIN_VARIANT (cur_type) == void_type_node
-		    || char_type_flag))
+		    || (i == 1 && char_type_flag)))
 	  /* Don't warn about differences merely in signedness, unless
 	     -pedantic.  With -pedantic, warn if the type is a pointer
 	     target and not a character type, and for character types at
@@ -2109,8 +2114,7 @@ check_format_info (info, params)
 	     equivalent but the above test won't consider them equivalent.  */
 	  && ! (wanted_type == char_type_node
 		&& (! pedantic || i < 2)
-		&& (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
-		    || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node)))
+		&& char_type_flag))
 	{
 	  register const char *this;
 	  register const char *that;
--- testsuite/gcc.dg/c99-printf-1.c.orig	Thu Jan  1 00:00:00 1970
+++ testsuite/gcc.dg/c99-printf-1.c	Sat Aug  5 22:37:13 2000
@@ -0,0 +1,217 @@
+/* Test for printf 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 __WINT_TYPE__ wint_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+/* Kludge to get signed type corresponding to size_t.  */
+#define unsigned signed
+typedef __SIZE_TYPE__ signed_size_t;
+#undef unsigned
+
+/* 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 printf (const char *, ...);
+
+#define NULL ((void *)0)
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %ll, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%he", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hE", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hg", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hG", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%ha", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hA", d); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hc", i); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hs", s); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hp", p); /* { dg-warning "length character" "bad use of %h" } */
+  printf ("%hhd%hhi%hho%hhu%hhx%hhX", i, i, u, u, u, u);
+  printf ("%hhn", ss);
+  printf ("%hhf", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhF", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhe", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhE", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhg", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhG", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hha", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhA", d); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhc", i); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhs", s); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%hhp", p); /* { dg-warning "length character" "bad use of %hh" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lf%lF%le%lE%lg%lG%la%lA", d, d, d, d, d, d, d, d);
+  printf ("%lp", p); /* { dg-warning "length character|C" "bad use of %l" } */
+  printf ("%lld%lli%llo%llu%llx%llX", ll, ll, ull, ull, ull, ull);
+  printf ("%lln", lln);
+  printf ("%llf", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llF", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%lle", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llE", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llg", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llG", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%lla", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llA", d); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llc", i); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%lls", s); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%llp", p); /* { dg-warning "length character" "bad use of %ll" } */
+  printf ("%jd%ji%jo%ju%jx%jX", j, j, uj, uj, uj, uj); /* { dg-bogus "length character" "bogus %j warning" { xfail *-*-* } } */
+  printf ("%jn", jn); /* { dg-bogus "length character" "bogus %j warning" { xfail *-*-* } } */
+  printf ("%jf", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jF", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%je", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jE", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jg", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jG", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%ja", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jA", d); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jc", i); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%js", s); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%jp", p); /* { dg-warning "length character" "bad use of %j" } */
+  printf ("%zd%zi%zo%zu%zx%zX", sz, sz, z, z, z, z);
+  printf ("%zn", zn);
+  printf ("%zf", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zF", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%ze", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zE", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zg", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zG", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%za", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zA", d); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zc", i); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zs", s); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%zp", p); /* { dg-warning "length character" "bad use of %z" } */
+  printf ("%td%ti%to%tu%tx%tX", t, t, t, t, t, t);
+  printf ("%tn", tn);
+  printf ("%tf", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tF", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%te", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tE", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tg", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tG", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%ta", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tA", d); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tc", i); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%ts", s); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%tp", p); /* { dg-warning "length character" "bad use of %t" } */
+  printf ("%Le%LE%Lf%LF%Lg%LG%La%LA", ld, ld, ld, ld, ld, ld, ld, ld);
+  /* These next six are accepted by GCC as referring to long long,
+     but -pedantic correctly warns.
+  */
+  printf ("%Ld", ll); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%Li", ll); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%Lo", ull); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%Lu", ull); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%Lx", ull); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%LX", ull); /* { dg-warning "does not support" "bad use of %L" } */
+  printf ("%Lc", i); /* { dg-warning "length character" "bad use of %L" } */
+  printf ("%Ls", s); /* { dg-warning "length character" "bad use of %L" } */
+  printf ("%Lp", p); /* { dg-warning "length character" "bad use of %L" } */
+  printf ("%Ln", n); /* { dg-warning "length character" "bad use of %L" } */
+  /* Valid uses of each bare conversion.  */
+  printf ("%d%i%o%u%x%X%f%F%e%E%g%G%a%A%c%s%p%n%%", i, i, u, u, u, u,
+	  d, d, d, d, d, d, d, d, i, s, p, n);
+  /* Uses of the - flag (valid on all non-%, non-n conversions).  */
+  printf ("%-d%-i%-o%-u%-x%-X%-f%-F%-e%-E%-g%-G%-a%-A%-c%-s%-p", i, i,
+	  u, u, u, u, d, d, d, d, d, d, d, d, i, s, p);
+  printf ("%-n", n); /* { dg-warning "flag" "bad use of %-n" } */
+  /* Uses of the + flag (valid on signed conversions only).  */
+  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 + flag" } */
+  printf ("%+u", 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 ("%+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" } */
+  /* 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% 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" } */
+  printf ("% x", u); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% X", u); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% c", i); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% s", s); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% p", p); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% n", n); /* { dg-warning "flag" "bad use of space flag" } */
+  /* Uses of the # flag.  */
+  printf ("%#o%#x%#X%#e%#E%#f%#F%#g%#G%#a%#A", u, u, u, d, d, d, d,
+	  d, d, d, d);
+  printf ("%#d", i); /* { dg-warning "flag" "bad use of # flag" } */
+  printf ("%#i", i); /* { dg-warning "flag" "bad use of # flag" } */
+  printf ("%#u", u); /* { 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" } */
+  /* Uses of the 0 flag.  */
+  printf ("%08d%08i%08o%08u%08x%08X%08e%08E%08f%08F%08g%08G%08a%08A", i, i,
+	  u, u, u, u, d, d, d, d, d, d, d, d);
+  printf ("%0c", i); /* { dg-warning "flag" "bad use of 0 flag" } */
+  printf ("%0s", s); /* { dg-warning "flag" "bad use of 0 flag" } */
+  printf ("%0p", p); /* { dg-warning "flag" "bad use of 0 flag" } */
+  printf ("%0n", n); /* { dg-warning "flag" "bad use of 0 flag" } */
+  /* 0 flag ignored with precision for certain types, not others.  */
+  printf ("%08.5d", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5i", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5o", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5u", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5x", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5X", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  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" } */
+  /* 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
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "format" "%hhn plain char" } */
+  printf ("%hhn", us); /* { dg-warning "format" "%hhn unsigned char" } */
+}

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



More information about the Gcc-patches mailing list