From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27541 invoked by alias); 14 Aug 2008 19:10:25 -0000 Received: (qmail 27321 invoked by uid 22791); 14 Aug 2008 19:10:14 -0000 X-Spam-Check-By: sourceware.org Received: from fire2.LINUX.UCLA.EDU (HELO linux.ucla.edu) (131.179.104.17) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 14 Aug 2008 19:09:23 +0000 Received: from dsh by linux.ucla.edu with local (Exim 3.36 #1 (Debian)) id 1KTiCH-0000KW-00; Thu, 14 Aug 2008 12:09:21 -0700 Date: Thu, 14 Aug 2008 19:43:00 -0000 From: Dan Hipschman To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: Re: PATCH: Add format string suggestions to -Wformat warnings Message-ID: <20080814190920.GS22846@linux.ucla.edu> Reply-To: dsh@linux.ucla.edu Mail-Followup-To: "Joseph S. Myers" , gcc-patches@gcc.gnu.org References: <20070814235109.GD11055@google.com> <20070821222124.GE11055@google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.13 (2006-08-11) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2008-08/txt/msg01017.txt.bz2 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 * 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 * 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