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]
Other format: [Raw text]

Re: PATCH: Add format string suggestions to -Wformat warnings


On Thu, Sep 13, 2007 at 10:44:08PM +0000, Joseph S. Myers wrote:
> We're moving away from having dg-* as regular expressions to match 
> multiple messages on one line to having a separate dg-* for each 
> diagnostic (that way, you know if only some of the expected diagnostics on 
> a line have disappeared).

Sorry for the *very* long delay resending this patch.  I got a bit
distracted.  I also haven't been following GCC development as closely as
I might hope, so hopefully nothing has changed that would now make this
patch unacceptable.  The last send of this patch was here:

http://gcc.gnu.org/ml/gcc-patches/2007-08/msg00908.html

I've only separated the dg-warnings and dg-messages out to their own
lines.  Everything else is the same.  I retested on x86_64 GNU/Linux.

> The revised C front-end changes look good to me but I can't reach a final 
> conclusion on them without seeing the tests revised to avoid matching 
> multiple diagnostics with a single regexp.

The front-end changes are exactly the same, so hopefully these are still
OK.

Thanks!
Dan

gcc/
2008-08-14  Dan Hipschman  <dsh@google.com>

	* c-format.h: New FMT_SUG_* flags.
	(format_suggestions): New structure.
	(format_kind_info): Add suggestions field.
	* c-format.c (format_wanted_type): Add suggestions field.
	(printf_suggestions): New global.
	(format_types_orig): Add suggestions field initializers.
	(check_format_info_main): Use suggestions.
	(arg_readonly): New function.
	(check_format_types): Use it.  Pass orig_cur_param instead of
	orig_cur_type to format_type_warning.
	(format_type_warning): Add suggestions and arg parameters.  Remove
	arg_type parameter.  Use format suggestions in warnings.
	* c-typeck.c (build_c_cast): Add a call to convert even if main
	variants are the same.
	* c-common.c (copy_type_with_name): New function.
	(c_common_nodes_and_builtins): Use it.

testsuite/
2008-08-14  Dan Hipschman  <dsh@google.com>

	* gcc.dg/format/dfp-suggest-1.c: New test.
	* gcc.dg/format/ext-suggest-1.c: New test.
	* gcc.dg/format/ext-suggest-2.c: New test.
	* gcc.dg/format/typedef-suggest-1.c: New test.
	* gcc.dg/format/typedef-suggest-2.c: New test.
	* gcc.dg/format/array-1.c: Update to handle format suggestion notes.
	* gcc.dg/format/branch-1.c: Likewise.
	* gcc.dg/format/builtin-1.c: Likewise.
	* gcc.dg/format/c90-printf-1.c: Likewise.
	* gcc.dg/format/c90-printf-3.c: Likewise.
	* gcc.dg/format/c99-printf-1.c: Likewise.
	* gcc.dg/format/c99-printf-3.c: Likewise.
	* gcc.dg/format/cast-1.c: Likewise.
	* gcc.dg/format/dfp-printf-1.c: Likewise.
	* gcc.dg/format/diag-1.c: Likewise.
	* gcc.dg/format/ext-1.c: Likewise.
	* gcc.dg/format/ext-5.c: Likewise.
	* gcc.dg/format/ext-6.c: Likewise.
	* gcc.dg/format/multattr-3.c: Likewise.
	* gcc.dg/format/unnamed-1.c: Likewise.
	* gcc.dg/format/va-1.c: Likewise.
	* gcc.dg/format/xopen-1.c: Likewise.

Index: gcc/testsuite/gcc.dg/format/builtin-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/builtin-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/builtin-1.c	(working copy)
@@ -12,11 +12,15 @@
 {
   __builtin_fprintf (stdout, "%d", i);
   __builtin_fprintf (stdout, "%ld", i); /* { dg-warning "format" "__builtin_fprintf" } */
+                                        /* { dg-message ": d, i$" "format suggestion" 14 } */
   __builtin_printf ("%d", i);
   __builtin_printf ("%ld", i); /* { dg-warning "format" "__builtin_printf" } */
+                               /* { dg-message ": d, i$" "format suggestion" 17 } */
 
   __builtin_fprintf_unlocked (stdout, "%d", i);
   __builtin_fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "__builtin_fprintf_unlocked" } */
+                                                 /* { dg-message ": d, i$" "format suggestion" 21 } */
   __builtin_printf_unlocked ("%d", i);
   __builtin_printf_unlocked ("%ld", i); /* { dg-warning "format" "__builtin_printf_unlocked" } */
+                                        /* { dg-message ": d, i$" "format suggestion" 24 } */
 }
Index: gcc/testsuite/gcc.dg/format/ext-6.c
===================================================================
--- gcc/testsuite/gcc.dg/format/ext-6.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/ext-6.c	(working copy)
@@ -14,16 +14,22 @@
 {
   fprintf (stdout, "%d", i);
   fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+                              /* { dg-message ": d, i$" "format suggestion" 16 } */
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
+                     /* { dg-message ": d, i$" "format suggestion" 19 } */
   fprintf_unlocked (stdout, "%d", i);
   fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+                                       /* { dg-message ": d, i$" "format suggestion" 22 } */
   printf_unlocked ("%d", i);
   printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
+                              /* { dg-message ": d, i$" "format suggestion" 25 } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+                         /* { dg-message ": d, i$" "format suggestion" 28 } */
   snprintf (s, n, "%d", i);
   snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+                             /* { dg-message ": d, i$" "format suggestion" 31 } */
   vfprintf (stdout, "%d", v0);
   vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
   vprintf ("%d", v2);
Index: gcc/testsuite/gcc.dg/format/xopen-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/xopen-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/xopen-1.c	(working copy)
@@ -90,6 +90,7 @@
   scanf ("%1$d", ip);
   printf ("%1$d", i);
   printf ("%1$d", l); /* { dg-warning "arg 2|argument 2" "mismatched args with $ format" } */
+                      /* { dg-message ": ld, li$" "format suggestion" 92 } */
   printf ("%3$*2$.*1$ld", i2, i, l);
   printf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", i, i, i, l, i, i, l);
   scanf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", ip, ip, ip, lp, ip, ip, lp);
@@ -110,15 +111,15 @@
      warning about unused arguments rather than the more serious one about
      argument gaps.  */
   scanf ("%3$d%1$d", ip, ip, ip); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
-  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 112 } */
+  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 113 } */
   /* If there are non-pointer arguments unused at the end, this is also OK.  */
   scanf ("%3$d%1$d", ip, ip, ip, i); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
-  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 115 } */
+  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 116 } */
   scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
   /* Can't check the arguments in the vscanf case, so should suppose the
      lesser problem.  */
   vscanf ("%3$d%1$d", va); /* { dg-bogus "before used" "unused $ scanf pointer operand" } */
-  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 120 } */
+  /* { dg-warning "unused" "unused $ scanf pointer operand" { target *-*-* } 121 } */
   scanf ("%2$*d%1$d", ip, ip); /* { dg-warning "operand" "operand number with suppression" } */
   printf ("%1$d%1$d", i);
   scanf ("%1$d%1$d", ip); /* { dg-warning "more than once" "multiple use of scanf argument" } */
Index: gcc/testsuite/gcc.dg/format/c99-printf-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/c99-printf-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/c99-printf-1.c	(working copy)
@@ -193,5 +193,6 @@
      is used is not signed char *.)
   */
   printf ("%hhn", s); /* { dg-warning "format" "%hhn plain char" } */
+                      /* { dg-message ": s$" "format suggestion" 195 } */
   printf ("%hhn", us); /* { dg-warning "format" "%hhn unsigned char" } */
 }
Index: gcc/testsuite/gcc.dg/format/array-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/array-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/array-1.c	(working copy)
@@ -24,17 +24,21 @@
   printf (a1);
   printf (a2, i);
   printf (a2, l); /* { dg-warning "format" "wrong type with array" } */
+                  /* { dg-message ": ld, li$" "format suggestion" 26 } */
   printf (b1); /* { dg-warning "unterminated" "unterminated array" } */
   printf (b2); /* { dg-warning "unterminated" "unterminated array" } */
   printf (c1);
   printf (c2, i);
   printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+                  /* { dg-message ": ld, li$" "format suggestion" 32 } */
   printf (p1);
   printf (p2, i);
   printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+                  /* { dg-message ": ld, li$" "format suggestion" 36 } */
   printf (q1);
   printf (q2, i);
   printf (q2, l); /* { dg-warning "format" "wrong type with array" } */
+                  /* { dg-message ": ld, li$" "format suggestion" 40 } */
   /* Volatile or non-constant arrays must not be checked.  */
   printf (d); /* { dg-warning "not a string literal" "non-const" } */
   printf ((const char *)e); /* { dg-warning "not a string literal" "volatile" } */
Index: gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc/testsuite/gcc.dg/format/c90-printf-3.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/c90-printf-3.c	(working copy)
@@ -14,13 +14,16 @@
 {
   fprintf (stdout, "%d", i);
   fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+                              /* { dg-message ": d, i$" "format suggestion" 16 } */
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
+                     /* { dg-message ": d, i$" "format suggestion" 19 } */
   /* The "unlocked" functions shouldn't warn in c90 mode.  */
   fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
   printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+                         /* { dg-message ": d, i$" "format suggestion" 25 } */
   vfprintf (stdout, "%d", v0);
   vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
   vprintf ("%d", v2);
Index: gcc/testsuite/gcc.dg/format/dfp-printf-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/dfp-printf-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/dfp-printf-1.c	(working copy)
@@ -43,30 +43,54 @@
   /* Check warnings for type mismatches.  */
 
   printf ("%Hf\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 45 } */
   printf ("%HF\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 47 } */
   printf ("%He\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 49 } */
   printf ("%HE\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 51 } */
   printf ("%Hg\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 53 } */
   printf ("%HG\n", y);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 55 } */
   printf ("%Hf\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 57 } */
   printf ("%HF\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 59 } */
   printf ("%He\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 61 } */
   printf ("%HE\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 63 } */
   printf ("%Hg\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 65 } */
   printf ("%HG\n", z);	/* { dg-warning "expects type" "bad use of %H" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 67 } */
 
   printf ("%Df\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 70 } */
   printf ("%DF\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 72 } */
   printf ("%De\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 74 } */
   printf ("%DE\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 76 } */
   printf ("%Dg\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 78 } */
   printf ("%DG\n", x);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": He, HE, Hf, HF, Hg, HG$" "format suggestion" 80 } */
   printf ("%Df\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 82 } */
   printf ("%DF\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 84 } */
   printf ("%De\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 86 } */
   printf ("%DE\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 88 } */
   printf ("%Dg\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 90 } */
   printf ("%DG\n", z);	/* { dg-warning "expects type" "bad use of %D" } */
+                        /* { dg-message ": DDe, DDE, DDf, DDF, DDg, DDG$" "format suggestion" 92 } */
 
   printf ("%DDf\n", x);	/* { dg-warning "expects type" "bad use of %DD" } */
   printf ("%DDF\n", x);	/* { dg-warning "expects type" "bad use of %DD" } */
@@ -75,11 +99,17 @@
   printf ("%DDg\n", x);	/* { dg-warning "expects type" "bad use of %DD" } */
   printf ("%DDG\n", x);	/* { dg-warning "expects type" "bad use of %DD" } */
   printf ("%DDf\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 101 } */
   printf ("%DDF\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 103 } */
   printf ("%DDe\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 105 } */
   printf ("%DDE\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 107 } */
   printf ("%DDg\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 109 } */
   printf ("%DDG\n", y);	/* { dg-warning "expects type" "bad use of %DD" } */
+                        /* { dg-message ": De, DE, Df, DF, Dg, DG$" "format suggestion" 111 } */
 
   /* Check for warnings for bad use of H, D, and DD length specifiers.  */
 
Index: gcc/testsuite/gcc.dg/format/unnamed-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/unnamed-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/unnamed-1.c	(working copy)
@@ -19,6 +19,7 @@
 f (TItype x)
 {
   printf("%d", x); /* { dg-warning "expects type" } */
+  /* { dg-message ": ld, li$" "format suggestion" 21 } */
   printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
-  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 23 } */
 }
Index: gcc/testsuite/gcc.dg/format/cast-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/cast-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/cast-1.c	(working copy)
@@ -11,6 +11,8 @@
 f (int x)
 {
   printf("%s", x); /* { dg-warning "format" } */
+                   /* { dg-message ": d, i$" "format suggestion" 13 } */
   printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+                                   /* { dg-message ": d, i$" "format suggestion" 15 } */
   printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
 }
Index: gcc/testsuite/gcc.dg/format/branch-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/branch-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/branch-1.c	(working copy)
@@ -10,8 +10,11 @@
 {
   printf ((nfoo > 1) ? "%d foos" : "%d foo", nfoo);
   printf ((l > 1) ? "%d foos" : "%d foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                              /* { dg-message ": ld, li$" "format suggestion" 12 } */
   printf ((l > 1) ? "%ld foos" : "%d foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                               /* { dg-message ": ld, li$" "format suggestion" 14 } */
   printf ((l > 1) ? "%d foos" : "%ld foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                               /* { dg-message ": ld, li$" "format suggestion" 16 } */
   /* Should allow one case to have extra arguments.  */
   printf ((nfoo > 1) ? "%d foos" : "1 foo", nfoo);
   printf ((nfoo > 1) ? "many foos" : "1 foo", nfoo); /* { dg-warning "too many" "too many args in all branches" } */
@@ -19,9 +22,12 @@
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "1 foo" : "no foos"), nfoo);
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%d foo" : "%d foos"), nfoo);
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%d foo" : "%ld foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                /* { dg-message ": d, i$" "format suggestion" 24 } */
   printf ((nfoo > 1) ? "%ld foos" : ((nfoo > 0) ? "%d foo" : "%d foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                /* { dg-message ": d, i$" "format suggestion" 26 } */
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%ld foo" : "%d foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                /* { dg-message ": d, i$" "format suggestion" 28 } */
   /* Extra arguments to NULL should be complained about.  */
   printf (NULL, "foo"); /* { dg-warning "too many" "NULL extra args" } */
-  /* { dg-warning "null" "null format arg" { target *-*-* } 25 } */
+  /* { dg-warning "null" "null format arg" { target *-*-* } 31 } */
 }
Index: gcc/testsuite/gcc.dg/format/diag-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/diag-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/diag-1.c	(working copy)
@@ -10,9 +10,12 @@
 {
   /* This should get a message referring to `hh', not to `H'.  */
   printf ("%hhf", d); /* { dg-warning "hh" "%hhf warning" } */
+                      /* { dg-message ": a, A, e, E, f, F, g, G$" "format suggestion" 12 } */
   /* This should get a message referring to `ll', not to `q'.  */
   printf ("%llf", d); /* { dg-warning "ll" "%llf warning" } */
+                      /* { dg-message ": a, A, e, E, f, F, g, G$" "format suggestion" 15 } */
   /* This should get a message referring to 'size_t', not to
      'unsigned int' or similar.  */
   printf ("%zu", d); /* { dg-warning "size_t" "size_t format warning" } */
+                     /* { dg-message ": a, A, e, E, f, F, g, G$" "format suggestion" 19 } */
 }
Index: gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc/testsuite/gcc.dg/format/c99-printf-3.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/c99-printf-3.c	(working copy)
@@ -13,15 +13,19 @@
 {
   fprintf (stdout, "%d", i);
   fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+                              /* { dg-message ": d, i$" "format suggestion" 15 } */
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
+                     /* { dg-message ": d, i$" "format suggestion" 18 } */
   /* The "unlocked" functions shouldn't warn in c99 mode.  */
   fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
   printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+                         /* { dg-message ": d, i$" "format suggestion" 24 } */
   snprintf (s, n, "%d", i);
   snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+                             /* { dg-message ": d, i$" "format suggestion" 27 } */
   vfprintf (stdout, "%d", v0);
   vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
   vprintf ("%d", v0);
Index: gcc/testsuite/gcc.dg/format/multattr-3.c
===================================================================
--- gcc/testsuite/gcc.dg/format/multattr-3.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/multattr-3.c	(working copy)
@@ -14,8 +14,11 @@
 {
   printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
   printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                                 /* { dg-message ": ld, li$" "format suggestion" 16 } */
   printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                                  /* { dg-message ": ld, li$" "format suggestion" 18 } */
   printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+                                                  /* { dg-message ": ld, li$" "format suggestion" 20 } */
   /* Should allow one case to have extra arguments.  */
   printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
   printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
@@ -23,6 +26,9 @@
   printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
   printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
   printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                 /* { dg-message ": d, i$" "format suggestion" 28 } */
   printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                 /* { dg-message ": d, i$" "format suggestion" 30 } */
   printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+                                                                                 /* { dg-message ": d, i$" "format suggestion" 32 } */
 }
Index: gcc/testsuite/gcc.dg/format/c90-printf-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/c90-printf-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/c90-printf-1.c	(working copy)
@@ -177,12 +177,17 @@
   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" } */
+                    /* { dg-message ": ld, li$" "format suggestion" 179 } */
   printf ("%*.*d", l, i2, i); /* { dg-warning "field" "bad * argument types" } */
   printf ("%*.*d", i1, l, i); /* { dg-warning "field" "bad * argument types" } */
   printf ("%ld", i); /* { dg-warning "format" "bad argument types" } */
+                     /* { dg-message ": d, i$" "format suggestion" 183 } */
   printf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+                    /* { dg-message ": n$" "format suggestion" 185 } */
   printf ("%p", i); /* { dg-warning "format" "bad argument types" } */
+                    /* { dg-message ": d, i$" "format suggestion" 187 } */
   printf ("%n", p); /* { dg-warning "format" "bad argument types" } */
+                    /* { dg-message ": p$" "format suggestion" 189 } */
   /* With -pedantic, we want some further checks for pointer targets:
      %p should allow only pointers to void (possibly qualified) and
      to character types (possibly qualified), but not function pointers
@@ -199,6 +204,7 @@
   printf ("%p", foo); /* { dg-warning "format" "bad argument types" } */
   printf ("%n", un); /* { dg-warning "format" "bad argument types" } */
   printf ("%p", n); /* { dg-warning "format" "bad argument types" } */
+                    /* { dg-message ": n$" "format suggestion" 206 } */
   /* Allow character pointers with %p.  */
   printf ("%p%p%p%p", s, ss, us, css);
   /* %s allows any character type.  */
@@ -208,6 +214,7 @@
      read to permit it.
   */
   printf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+                    /* { dg-message ": p$" "format suggestion" 216 } */
   /* The historical behavior is to allow signed / unsigned types
      interchangably as arguments.  For values representable in both types,
      such usage may be correct.  For now preserve the behavior of GCC
Index: gcc/testsuite/gcc.dg/format/ext-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/ext-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/ext-1.c	(working copy)
@@ -121,6 +121,8 @@
      i.e. thread unsafe versions of these functions.  */
   fprintf_unlocked (stdout, "%d", i);
   fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+                                       /* { dg-message ": d, i$" "format suggestion" 123 } */
   printf_unlocked ("%d", i);
   printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
+                              /* { dg-message ": d, i$" "format suggestion" 126 } */
 }
Index: gcc/testsuite/gcc.dg/format/ext-5.c
===================================================================
--- gcc/testsuite/gcc.dg/format/ext-5.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/ext-5.c	(working copy)
@@ -10,8 +10,11 @@
 {
   printf (gettext ("%d"), i);
   printf (gettext ("%ld"), i); /* { dg-warning "format" "gettext" } */
+                               /* { dg-message ": d, i$" "format suggestion" 12 } */
   printf (dgettext ("", "%d"), i);
   printf (dgettext ("", "%ld"), i); /* { dg-warning "format" "dgettext" } */
+                                    /* { dg-message ": d, i$" "format suggestion" 15 } */
   printf (dcgettext ("", "%d", 0), i);
   printf (dcgettext ("", "%ld", 0), i); /* { dg-warning "format" "dcgettext" } */
+                                        /* { dg-message ": d, i$" "format suggestion" 18 } */
 }
Index: gcc/testsuite/gcc.dg/format/va-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/va-1.c	(revision 138884)
+++ gcc/testsuite/gcc.dg/format/va-1.c	(working copy)
@@ -10,4 +10,5 @@
 {
   printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
   /* { dg-warning "format" "format error" { target *-*-* } 11 } */
+  /* { dg-message ": p$" "format suggestion" 11 } */
 }
Index: gcc/c-format.c
===================================================================
--- gcc/c-format.c	(revision 138884)
+++ gcc/c-format.c	(working copy)
@@ -270,6 +270,8 @@
   /* Whether the argument, dereferenced once, is read from and so
      must not be a NULL pointer.  */
   int reading_from_flag;
+  /* Format conversion suggestions, if available, otherwise NULL.  */
+  format_suggestions *suggestions;
   /* If warnings should be of the form "field precision should have
      type 'int'", the name to use (in this case "field precision"),
      otherwise NULL, for "format expects type 'long'" type
@@ -505,6 +507,43 @@
   { 0, 0, 0, 0 }
 };
 
+static format_suggestions printf_suggestions[] =
+{
+  { &wchar_type_node, "wchar_t", FMT_SUG_POINTER, STD_C94, "ls" },
+  { &wchar_type_node, "wchar_t", 0, STD_C94, "lc" },
+  { &wint_type_node, "wint_t", 0, STD_C94, "lc" },
+  { &signed_size_type_node, "ssize_t", 0, STD_C99, "zd, zi" },
+  { &size_type_node, "size_t", 0, STD_C99, "zo, zu, zx, zX" },
+  { &ptrdiff_type_node, "ptrdiff_t", 0, STD_C99, "td, ti" },
+  { &intmax_type_node, "intmax_t", 0, STD_C99, "jd, ji" },
+  { &uintmax_type_node, "uintmax_t", 0, STD_C99, "jo, ju, jx, jX" },
+  { &dfloat32_type_node, "_Decimal32", 0, STD_EXT, "He, HE, Hf, HF, Hg, HG" },
+  { &dfloat64_type_node, "_Decimal64", 0, STD_EXT, "De, DE, Df, DF, Dg, DG" },
+  { &dfloat128_type_node, "_Decimal128", 0, STD_EXT, "DDe, DDE, DDf, DDF, DDg, DDG" },
+  { &unsigned_char_type_node, NULL, 0, STD_C99, "c, hho, hhu, hhx, hhX" },
+  { &unsigned_char_type_node, NULL, 0, STD_C89, "c" },
+  { &signed_char_type_node, NULL, 0, STD_C99, "hhd, hhi" },
+  { &short_unsigned_type_node, NULL, 0, STD_C89, "ho, hu, hx, hX" },
+  { &short_integer_type_node, NULL, 0, STD_C89, "hd, hi" },
+  { &unsigned_type_node, NULL, 0, STD_C89, "o, u, x, X" },
+  { &integer_type_node, NULL, 0, STD_C89, "d, i" },
+  { &long_integer_type_node, NULL, 0, STD_C89, "ld, li" },
+  { &long_long_integer_type_node, NULL, 0, STD_C9L, "lld, lli" },
+  { &char_type_node, NULL, FMT_SUG_POINTER, STD_C89, "s" },
+  { &long_unsigned_type_node, NULL, 0, STD_C89, "lo, lu, lx, lX" },
+  { &long_long_unsigned_type_node, NULL, 0, STD_C9L, "llo, llu, llx, llX" },
+  { &double_type_node, NULL, 0, STD_C99, "a, A, e, E, f, F, g, G" },
+  { &long_double_type_node, NULL, 0, STD_C99, "La, LA, Le, LE, Lf, LF, Lg, LG" },
+  { &double_type_node, NULL, 0, STD_C89, "e, E, f, g, G" },
+  { &long_double_type_node, NULL, 0, STD_C89, "Le, LE, Lf, Lg, LG" },
+  { &signed_char_type_node, NULL, FMT_SUG_POINTER|FMT_SUG_WRITE, STD_C99, "hhn" },
+  { &short_integer_type_node, NULL, FMT_SUG_POINTER|FMT_SUG_WRITE, STD_C89, "hn" },
+  { &integer_type_node, NULL, FMT_SUG_POINTER|FMT_SUG_WRITE, STD_C89, "n" },
+  { &long_integer_type_node, NULL, FMT_SUG_POINTER|FMT_SUG_WRITE, STD_C89, "ln" },
+  { &long_long_integer_type_node, NULL, FMT_SUG_POINTER|FMT_SUG_WRITE, STD_C9L, "lln" },
+  { &void_type_node, NULL, FMT_SUG_POINTER, STD_C89, "p" },
+  { NULL, NULL, 0, 0, NULL }
+};
 
 static const format_char_info print_char_table[] =
 {
@@ -720,60 +759,60 @@
 static const format_kind_info format_types_orig[] =
 {
   { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
-    printf_flag_specs, printf_flag_pairs,
+    printf_flag_specs, printf_flag_pairs, printf_suggestions,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
     &integer_type_node, &integer_type_node
   },
   { "asm_fprintf",   asm_fprintf_length_specs,  asm_fprintf_char_table, " +#0-", NULL,
-    asm_fprintf_flag_specs, asm_fprintf_flag_pairs,
+    asm_fprintf_flag_specs, asm_fprintf_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
     NULL, NULL
   },
   { "gcc_diag",   gcc_diag_length_specs,  gcc_diag_char_table, "q+", NULL,
-    gcc_diag_flag_specs, gcc_diag_flag_pairs,
+    gcc_diag_flag_specs, gcc_diag_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 'p', 0, 'L', 0,
     NULL, &integer_type_node
   },
   { "gcc_tdiag",   gcc_tdiag_length_specs,  gcc_tdiag_char_table, "q+", NULL,
-    gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs,
+    gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 'p', 0, 'L', 0,
     NULL, &integer_type_node
   },
   { "gcc_cdiag",   gcc_cdiag_length_specs,  gcc_cdiag_char_table, "q+", NULL,
-    gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
+    gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 'p', 0, 'L', 0,
     NULL, &integer_type_node
   },
   { "gcc_cxxdiag",   gcc_cxxdiag_length_specs,  gcc_cxxdiag_char_table, "q+#", NULL,
-    gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs,
+    gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 'p', 0, 'L', 0,
     NULL, &integer_type_node
   },
   { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "", NULL,
-    NULL, gcc_gfc_flag_pairs,
+    NULL, gcc_gfc_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
   { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
-    scanf_flag_specs, scanf_flag_pairs,
+    scanf_flag_specs, scanf_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
   { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
-    strftime_flag_specs, strftime_flag_pairs,
+    strftime_flag_specs, strftime_flag_pairs, NULL,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
   { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
-    strfmon_flag_specs, strfmon_flag_pairs,
+    strfmon_flag_specs, strfmon_flag_pairs, NULL,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
   }
@@ -841,7 +880,8 @@
 
 static void check_format_types (format_wanted_type *, const char *, int);
 static void format_type_warning (const char *, const char *, int, tree,
-				 int, const char *, tree, int);
+				 int, const char *, tree, int,
+				 format_suggestions *);
 
 /* Decode a format type from a string, returning the type, or
    format_type_error if not valid, in which case the caller should print an
@@ -1629,6 +1669,7 @@
 		  width_wanted_type.name = _("field width");
 		  width_wanted_type.param = cur_param;
 		  width_wanted_type.arg_num = arg_num;
+		  width_wanted_type.suggestions = NULL;
 		  width_wanted_type.next = NULL;
 		  if (last_wanted_type != 0)
 		    last_wanted_type->next = &width_wanted_type;
@@ -1731,6 +1772,7 @@
 		  precision_wanted_type.name = _("field precision");
 		  precision_wanted_type.param = cur_param;
 		  precision_wanted_type.arg_num = arg_num;
+		  precision_wanted_type.suggestions = NULL;
 		  precision_wanted_type.next = NULL;
 		  if (last_wanted_type != 0)
 		    last_wanted_type->next = &precision_wanted_type;
@@ -2101,6 +2143,7 @@
 	      wanted_type_ptr->name = NULL;
 	      wanted_type_ptr->param = cur_param;
 	      wanted_type_ptr->arg_num = arg_num;
+	      wanted_type_ptr->suggestions = fki->suggestions;
 	      wanted_type_ptr->next = NULL;
 	      if (last_wanted_type != 0)
 		last_wanted_type->next = wanted_type_ptr;
@@ -2127,6 +2170,15 @@
 }
 
 
+/* Check if an argument cannot be written to (for example, by the %n
+   conversion).  */
+static int
+arg_readonly (tree arg)
+{
+  return CONSTANT_CLASS_P (arg) || (DECL_P (arg) && TREE_READONLY (arg));
+}
+
+
 /* Check the argument types from a single format conversion (possibly
    including width and precision arguments).  */
 static void
@@ -2137,7 +2189,7 @@
     {
       tree cur_param;
       tree cur_type;
-      tree orig_cur_type;
+      tree orig_cur_param;
       tree wanted_type;
       int arg_num;
       int i;
@@ -2146,7 +2198,7 @@
       cur_type = TREE_TYPE (cur_param);
       if (cur_type == error_mark_node)
 	continue;
-      orig_cur_type = cur_type;
+      orig_cur_param = cur_param;
       char_type_flag = 0;
       wanted_type = types->wanted_type;
       arg_num = types->arg_num;
@@ -2201,10 +2253,7 @@
 	      if (types->writing_in_flag
 		  && i == 0
 		  && (TYPE_READONLY (cur_type)
-		      || (cur_param != 0
-			  && (CONSTANT_CLASS_P (cur_param)
-			      || (DECL_P (cur_param)
-				  && TREE_READONLY (cur_param))))))
+		      || (cur_param != 0 && arg_readonly (cur_param))))
 		warning (OPT_Wformat, "writing into constant object "
 			 "(argument %d)", arg_num);
 
@@ -2225,8 +2274,8 @@
 	    {
 	      format_type_warning (types->name, format_start, format_length,
 				   wanted_type, types->pointer_count,
-				   types->wanted_type_name, orig_cur_type,
-				   arg_num);
+				   types->wanted_type_name, orig_cur_param,
+				   arg_num, types->suggestions);
 	      break;
 	    }
 	}
@@ -2274,7 +2323,8 @@
       /* Now we have a type mismatch.  */
       format_type_warning (types->name, format_start, format_length,
 			   wanted_type, types->pointer_count,
-			   types->wanted_type_name, orig_cur_type, arg_num);
+			   types->wanted_type_name, orig_cur_param, arg_num,
+			   types->suggestions);
     }
 }
 
@@ -2286,15 +2336,19 @@
    FORMAT_LENGTH is its length.  WANTED_TYPE is the type the argument
    should have after POINTER_COUNT pointer dereferences.
    WANTED_NAME_NAME is a possibly more friendly name of WANTED_TYPE,
-   or NULL if the ordinary name of the type should be used.  ARG_TYPE
-   is the type of the actual argument.  ARG_NUM is the number of that
-   argument.  */
+   or NULL if the ordinary name of the type should be used.  ARG
+   is the actual argument.  ARG_NUM is the number of that
+   argument.  SUGGESTIONS is used to suggest format conversions that
+   are acceptable for the argument type provided.  It may be NULL.  */
 static void
 format_type_warning (const char *descr, const char *format_start,
 		     int format_length, tree wanted_type, int pointer_count,
-		     const char *wanted_type_name, tree arg_type, int arg_num)
+		     const char *wanted_type_name, tree arg, int arg_num,
+		     format_suggestions *suggestions)
 {
+  tree arg_type;
   char *p;
+  arg_type = TREE_TYPE (arg);
   /* If ARG_TYPE is a typedef with a misleading name (for example,
      size_t but not the standard size_t expected by printf %zu), avoid
      printing the typedef name.  */
@@ -2324,6 +2378,94 @@
       memset (p + 1, '*', pointer_count);
       p[pointer_count + 1] = 0;
     }
+
+  if (suggestions)
+    {
+      tree type = TREE_TYPE (arg);
+      tree strp_arg = arg;
+      STRIP_NOPS (strp_arg);
+      for ( ; suggestions->type; ++suggestions)
+	{
+	  tree sug_type;
+	  tree test_type;
+	  if (C_STD_VER < ADJ_STD (suggestions->std)
+	      && (suggestions->std != STD_EXT || flag_iso))
+	    continue;
+	  if (suggestions->flags & FMT_SUG_POINTER)
+	    {
+	      if (TREE_CODE (type) == POINTER_TYPE)
+		test_type = TREE_TYPE (type);
+	      else
+		continue;
+	    }
+	  else
+	    test_type = type;
+	  if (suggestions->flags & FMT_SUG_WRITE)
+	    {
+	      gcc_assert (suggestions->flags & FMT_SUG_POINTER);
+	      if (TYPE_READONLY (test_type)
+		  || (TREE_CODE (strp_arg) == ADDR_EXPR
+		      && arg_readonly (TREE_OPERAND (strp_arg, 0))))
+		continue;
+	    }
+	  sug_type = *suggestions->type;
+	  if (suggestions->name)
+	    {
+	      tree named_type = test_type;
+	      int match = 0;
+	      while (named_type)
+		{
+		  if ((named_type == size_type_node
+		       || named_type == ptrdiff_type_node
+		       || named_type == wchar_type_node)
+		      && named_type == sug_type)
+		    {
+		      match = 2;
+		      break;
+		    }
+		  else
+		    {
+		      if (TYPE_NAME (named_type)
+			  && TREE_CODE (TYPE_NAME (named_type)) == TYPE_DECL)
+			{
+			  const char *type_name;
+			  type_name = get_name (TYPE_NAME (named_type));
+			  named_type
+			    = DECL_ORIGINAL_TYPE (TYPE_NAME (named_type));
+			  if (type_name
+			      && strcmp (type_name, suggestions->name) == 0)
+			    {
+			      match = 1;
+			      break;
+			    }
+			}
+		      else
+			break;
+		    }
+		}
+	      if (match == 2)
+		break;
+	      else if (match == 0)
+		continue;
+	    }
+	  test_type = TYPE_MAIN_VARIANT (test_type);
+	  if (lang_hooks.types_compatible_p (test_type, sug_type))
+	    break;
+	  if (!(suggestions->flags & FMT_SUG_POINTER))
+	    {
+	      tree pro_type = lang_hooks.types.type_promotes_to (sug_type);
+	      if (lang_hooks.types_compatible_p (pro_type, test_type)
+		  && (TREE_CODE (arg) == NOP_EXPR
+		      || TREE_CODE (arg) == CONVERT_EXPR))
+		{
+		  tree orig_arg_type = TREE_TYPE (TREE_OPERAND (arg, 0));
+		  if (lang_hooks.types_compatible_p (sug_type, orig_arg_type))
+		    break;
+		}
+	    }
+	}
+    }
+
   if (wanted_type_name)
     {
       if (descr)
@@ -2347,6 +2489,17 @@
 		 "but argument %d has type %qT",
 		 format_length, format_start, wanted_type, p, arg_num, arg_type);
     }
+  if (suggestions && suggestions->type)
+    {
+      if (suggestions->name)
+	inform ("acceptable formats for type %<%s%s%> are: %s", suggestions->name,
+		suggestions->flags & FMT_SUG_POINTER ? " *" : "",
+		suggestions->desc);
+      else
+	inform ("acceptable formats for type %<%T%s%> are: %s", *suggestions->type,
+		suggestions->flags & FMT_SUG_POINTER ? " *" : "",
+		suggestions->desc);
+    }
 }
 
 
Index: gcc/c-format.h
===================================================================
--- gcc/c-format.h	(revision 138884)
+++ gcc/c-format.h	(working copy)
@@ -201,6 +201,33 @@
 } format_flag_pair;
 
 
+/* Flags used to specify types in format string suggestions.  */
+enum
+{
+  /* Set if the required type is a pointer to the type specified in the
+     format_suggestions structure.  */
+  FMT_SUG_POINTER = 1,
+  /* Set if the required type must be writable.  The FMT_SUG_POINTER flag
+     must also be set.  */
+  FMT_SUG_WRITE = 2
+};
+
+/* Structure mapping a type to format conversion suggestions.  */
+typedef struct
+{
+  /* The type wanted by the conversions.  */
+  tree *type;
+  /* A name for this type if it's typedef'd, otherwise NULL.  */
+  const char *name;
+  /* Flags specified by the FMT_SUG_ constants.  */
+  unsigned flags;
+  /* The standard to which the conversions belong.  */
+  enum format_std_version std;
+  /* The conversion suggestions for use with this type.  */
+  const char *desc;
+} format_suggestions;
+
+
 /* Structure describing a particular kind of format processed by GCC.  */
 typedef struct
 {
@@ -219,6 +246,8 @@
   const format_flag_spec *flag_specs;
   /* Details of bad combinations of flags.  */
   const format_flag_pair *bad_flag_pairs;
+  /* Suggestions for conversions based on type.  */
+  format_suggestions *suggestions;
   /* Flags applicable to this kind of format.  */
   int flags;
   /* Flag character to treat a width as, or 0 if width not used.  */
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 138884)
+++ gcc/c-typeck.c	(working copy)
@@ -3620,6 +3620,12 @@
 	  || TREE_CODE (type) == UNION_TYPE)
 	pedwarn (OPT_pedantic, 
 		 "ISO C forbids casting nonscalar to the same type");
+      /* Add a conversion even if the main variants are the same since the
+	 types seen by the user may not be.  For example, if size_t has the
+	 same type as unsigned int, then "(unsigned) sizeof x" might be
+	 redundant, but for warning messages, the user wants the type to be
+	 thought of as	unsigned int.  */
+      value = convert (type, value);
     }
   else if (TREE_CODE (type) == UNION_TYPE)
     {
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 138884)
+++ gcc/c-common.c	(working copy)
@@ -4016,6 +4016,19 @@
     mudflap_init ();
 }
 
+
+/* Look up the type with identifier NAME and return a copy of it.  We want
+   some of the standard, but non-primitive, types, such as size_t, to be
+   copies of the types they represent, so we can still tell them apart.  */
+
+static tree
+copy_type_with_name (const char *name)
+{
+  tree id = get_identifier (name);
+  return build_variant_type_copy (TREE_TYPE (identifier_global_value (id)));
+}
+
+
 /* Build tree nodes and builtin functions common to both C and C++ language
    frontends.  */
 
@@ -4107,8 +4120,7 @@
   /* `unsigned long' is the standard type for sizeof.
      Note that stddef.h uses `unsigned long',
      and this must agree, even if long and int are the same size.  */
-  size_type_node =
-    TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
+  size_type_node = copy_type_with_name (SIZE_TYPE);
   signed_size_type_node = c_common_signed_type (size_type_node);
   set_sizetype (size_type_node);
 
@@ -4252,8 +4264,7 @@
 			  (char_type_node, TYPE_QUAL_CONST));
 
   /* This is special for C++ so functions can be overloaded.  */
-  wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE);
-  wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
+  wchar_type_node = copy_type_with_name (MODIFIED_WCHAR_TYPE);
   wchar_type_size = TYPE_PRECISION (wchar_type_node);
   if (c_dialect_cxx ())
     {
@@ -4314,8 +4325,7 @@
     TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE)));
 
   default_function_type = build_function_type (integer_type_node, NULL_TREE);
-  ptrdiff_type_node
-    = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
+  ptrdiff_type_node = copy_type_with_name (PTRDIFF_TYPE);
   unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
 
   lang_hooks.decls.pushdecl


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