PR c/25880 improve message of warning for discarding qualifiers

Manuel López-Ibáñez lopezibanez@gmail.com
Fri Jun 4 15:17:00 GMT 2010


This is what I committed as revision 160274.

Cheers,

Manuel.

On 24 May 2010 13:47, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Mon, 24 May 2010, Manuel López-Ibáñez wrote:
>
>> I sometimes forget that humans cannot read minds. Now with patch.
>>
>> Manuel.
>>
>> On 24 May 2010 11:38, Manuel López-Ibáñez <lopezibanez@gmail.com> wrote:
>> > Before updating testcases, I would like to know if the current patch is ok.
>> >
>> > Bootstrapped and regression tested on x86_64-linux-gnu. Failing
>> > testcases are due to the change of wording.
>
> I think you should print "const" as an attribute for functions, like
> volatile; otherwise the changes look OK.  Note that you should update the
> tests of GCC format checking (gcc.dg/format/gcc_diag-1.c) to test the new
> formats, as well as updating tests that fail.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
-------------- next part --------------
Index: gcc/testsuite/gcc.dg/assign-warn-2.c
===================================================================
--- gcc/testsuite/gcc.dg/assign-warn-2.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/assign-warn-2.c	(working copy)
@@ -11,27 +11,27 @@
 #define TESTRET(ID, TL, TR) TR ID##V; TL ID##F(void) { return ID##V; } extern int dummy
 
 typedef void (*fp)(void);
 typedef void (*nrfp)(void) __attribute__((noreturn));
 
-TESTARG(fqa, nrfp, fp); /* { dg-error "passing argument 1 of 'fqaF' makes qualified function pointer from unqualified" } */
-TESTARP(fqb, nrfp, fp); /* { dg-error "passing argument 1 of 'fqbFp.x' makes qualified function pointer from unqualified" } */
-TESTASS(fqc, nrfp, fp); /* { dg-error "assignment makes qualified function pointer from unqualified" } */
-TESTINI(fqd, nrfp, fp); /* { dg-error "initialization makes qualified function pointer from unqualified" } */
-TESTRET(fqe, nrfp, fp); /* { dg-error "return makes qualified function pointer from unqualified" } */
+TESTARG(fqa, nrfp, fp); /* { dg-error "passing argument 1 of 'fqaF' makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTARP(fqb, nrfp, fp); /* { dg-error "passing argument 1 of 'fqbFp.x' makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTASS(fqc, nrfp, fp); /* { dg-error "assignment makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTINI(fqd, nrfp, fp); /* { dg-error "initialization makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTRET(fqe, nrfp, fp); /* { dg-error "return makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
 
 TESTARG(ofqa, fp, nrfp);
 TESTARP(ofqb, fp, nrfp);
 TESTASS(ofqc, fp, nrfp);
 TESTINI(ofqd, fp, nrfp);
 TESTRET(ofqe, fp, nrfp);
 
-TESTARG(qa, char *, const char *); /* { dg-error "passing argument 1 of 'qaF' discards qualifiers from pointer target type" } */
-TESTARP(qb, char *, const char *); /* { dg-error "passing argument 1 of 'qbFp.x' discards qualifiers from pointer target type" } */
-TESTASS(qc, char *, const char *); /* { dg-error "assignment discards qualifiers from pointer target type" } */
-TESTINI(qd, char *, const char *); /* { dg-error "initialization discards qualifiers from pointer target type" } */
-TESTRET(qe, char *, const char *); /* { dg-error "return discards qualifiers from pointer target type" } */
+TESTARG(qa, char *, const char *); /* { dg-error "passing argument 1 of 'qaF' discards 'const' qualifier from pointer target type" } */
+TESTARP(qb, char *, const char *); /* { dg-error "passing argument 1 of 'qbFp.x' discards 'const' qualifier from pointer target type" } */
+TESTASS(qc, char *, const char *); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+TESTINI(qd, char *, const char *); /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+TESTRET(qe, char *, const char *); /* { dg-error "return discards 'const' qualifier from pointer target type" } */
 
 TESTARG(oqa, const char *, char *);
 TESTARP(oqb, const char *, char *);
 TESTASS(oqc, const char *, char *);
 TESTINI(oqd, const char *, char *);
Index: gcc/testsuite/gcc.dg/cpp/line3.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/line3.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/cpp/line3.c	(working copy)
@@ -11,18 +11,18 @@
 int
 main(void)
 {
   char *A;
 
-  A = "text";		/* { dg-warning "discards qualifiers" "case zero" } */
-  A = one("text"	/* { dg-warning "discards qualifiers" "case one" } */
+  A = "text";		/* { dg-warning "discards 'const' qualifier" "case zero" } */
+  A = one("text"	/* { dg-warning "discards 'const' qualifier" "case one" } */
 	  "text")
 	;
-  A = two("text"	/* { dg-warning "discards qualifiers" "case two" } */
+  A = two("text"	/* { dg-warning "discards 'const' qualifier" "case two" } */
 	  "text")
 	;
-  A = four("text"	/* { dg-warning "discards qualifiers" "case four" } */
+  A = four("text"	/* { dg-warning "discards 'const' qualifier" "case four" } */
 	   "text")
 	;
 
   return 0;
 }
Index: gcc/testsuite/gcc.dg/c99-array-lval-8.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-array-lval-8.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/c99-array-lval-8.c	(working copy)
@@ -10,19 +10,19 @@ void
 f (void)
 {
   const struct {
     int a[1];
   } s;
-  int *p1 = s.a; /* { dg-error "qualifiers" } */
+  int *p1 = s.a; /* { dg-error "qualifier" } */
   int *p2 = (a ? s : s).a;
   /* In this case, the qualifier is properly on the array element type
      not on the rvalue structure and so is not discarded.  */
   struct {
     const int a[1];
   } t;
-  int *p3 = t.a; /* { dg-error "qualifiers" } */
-  int *p4 = (a ? t : t).a; /* { dg-error "qualifiers" } */
+  int *p3 = t.a; /* { dg-error "qualifier" } */
+  int *p4 = (a ? t : t).a; /* { dg-error "qualifier" } */
   /* The issue could also lead to code being wrongly accepted.  */
   const struct {
     int a[1][1];
   } u;
   const int (*p5)[1] = u.a;
Index: gcc/testsuite/gcc.dg/cast-qual-2.c
===================================================================
--- gcc/testsuite/gcc.dg/cast-qual-2.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/cast-qual-2.c	(working copy)
@@ -16,19 +16,19 @@ volatile voidfn_t noreturnfn;
 intfn_t *i1 = intfn;
 intfn_t *i2 = (intfn_t *) intfn;
 intfn_t *i3 = constfn;
 intfn_t *i4 = (intfn_t *) constfn; /* { dg-bogus "discards qualifier" } */
 
-constfn_t p1 = intfn; /* { dg-warning "makes qualified function" } */
-constfn_t p2 = (constfn_t) intfn; /* { dg-warning "new qualifier" } */
+constfn_t p1 = intfn; /* { dg-warning "makes '__attribute__..const..' qualified function" } */
+constfn_t p2 = (constfn_t) intfn; /* { dg-warning "adds '__attribute__..const..' qualifier" } */
 constfn_t p3 = constfn;
 constfn_t p4 = (constfn_t) constfn;
 
 voidfn_t *v1 = voidfn;
 voidfn_t *v2 = (voidfn_t *) voidfn;
 voidfn_t *v3 = noreturnfn;
 voidfn_t *v4 = (voidfn_t *) noreturnfn; /* { dg-bogus "discards qualifier" } */
 
-noreturnfn_t n1 = voidfn; /* { dg-warning "makes qualified function" } */
-noreturnfn_t n2 = (noreturnfn_t) voidfn; /* { dg-warning "new qualifier" } */
+noreturnfn_t n1 = voidfn; /* { dg-warning "makes '__attribute__..noreturn..' qualified function" } */
+noreturnfn_t n2 = (noreturnfn_t) voidfn; /* { dg-warning "adds '__attribute__..noreturn..' qualifier" } */
 noreturnfn_t n3 = noreturnfn;
 noreturnfn_t n4 = (noreturnfn_t) noreturnfn;
Index: gcc/testsuite/gcc.dg/c99-arraydecl-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-arraydecl-3.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/c99-arraydecl-3.c	(working copy)
@@ -5,16 +5,16 @@
 /* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
 
 void
 f0 (int a[restrict])
 {
-  int **b = &a; /* { dg-error "discards qualifiers" } */
+  int **b = &a; /* { dg-error "discards 'restrict' qualifier" } */
   int *restrict *c = &a;
 }
 
 void
 f1 (a)
      int a[restrict];
 {
-  int **b = &a; /* { dg-error "discards qualifiers" } */
+  int **b = &a; /* { dg-error "discards 'restrict' qualifier" } */
   int *restrict *c = &a;
 }
Index: gcc/testsuite/gcc.dg/assign-warn-1.c
===================================================================
--- gcc/testsuite/gcc.dg/assign-warn-1.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/assign-warn-1.c	(working copy)
@@ -10,27 +10,27 @@
 #define TESTRET(ID, TL, TR) TR ID##V; TL ID##F(void) { return ID##V; } extern int dummy
 
 typedef void (*fp)(void);
 typedef void (*nrfp)(void) __attribute__((noreturn));
 
-TESTARG(fqa, nrfp, fp); /* { dg-warning "passing argument 1 of 'fqaF' makes qualified function pointer from unqualified" } */
-TESTARP(fqb, nrfp, fp); /* { dg-warning "passing argument 1 of 'fqbFp.x' makes qualified function pointer from unqualified" } */
-TESTASS(fqc, nrfp, fp); /* { dg-warning "assignment makes qualified function pointer from unqualified" } */
-TESTINI(fqd, nrfp, fp); /* { dg-warning "initialization makes qualified function pointer from unqualified" } */
-TESTRET(fqe, nrfp, fp); /* { dg-warning "return makes qualified function pointer from unqualified" } */
+TESTARG(fqa, nrfp, fp); /* { dg-warning "passing argument 1 of 'fqaF' makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTARP(fqb, nrfp, fp); /* { dg-warning "passing argument 1 of 'fqbFp.x' makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTASS(fqc, nrfp, fp); /* { dg-warning "assignment makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTINI(fqd, nrfp, fp); /* { dg-warning "initialization makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
+TESTRET(fqe, nrfp, fp); /* { dg-warning "return makes '__attribute__..noreturn..' qualified function pointer from unqualified" } */
 
 TESTARG(ofqa, fp, nrfp);
 TESTARP(ofqb, fp, nrfp);
 TESTASS(ofqc, fp, nrfp);
 TESTINI(ofqd, fp, nrfp);
 TESTRET(ofqe, fp, nrfp);
 
-TESTARG(qa, char *, const char *); /* { dg-warning "passing argument 1 of 'qaF' discards qualifiers from pointer target type" } */
-TESTARP(qb, char *, const char *); /* { dg-warning "passing argument 1 of 'qbFp.x' discards qualifiers from pointer target type" } */
-TESTASS(qc, char *, const char *); /* { dg-warning "assignment discards qualifiers from pointer target type" } */
-TESTINI(qd, char *, const char *); /* { dg-warning "initialization discards qualifiers from pointer target type" } */
-TESTRET(qe, char *, const char *); /* { dg-warning "return discards qualifiers from pointer target type" } */
+TESTARG(qa, char *, const char *); /* { dg-warning "passing argument 1 of 'qaF' discards 'const' qualifier from pointer target type" } */
+TESTARP(qb, char *, const char *); /* { dg-warning "passing argument 1 of 'qbFp.x' discards 'const' qualifier from pointer target type" } */
+TESTASS(qc, char *, const char *); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+TESTINI(qd, char *, const char *); /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+TESTRET(qe, char *, const char *); /* { dg-warning "return discards 'const' qualifier from pointer target type" } */
 
 TESTARG(oqa, const char *, char *);
 TESTARP(oqb, const char *, char *);
 TESTASS(oqc, const char *, char *);
 TESTINI(oqd, const char *, char *);
Index: gcc/testsuite/gcc.dg/format/gcc_diag-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/gcc_diag-1.c	(revision 160273)
+++ gcc/testsuite/gcc.dg/format/gcc_diag-1.c	(working copy)
@@ -68,26 +68,30 @@ foo (int i, int i1, int i2, unsigned int
   diag ("%m");
   tdiag ("%m");
   cdiag ("%m");
   cxxdiag ("%m");
 
-  tdiag ("%D%F%T", t1, t1, t1);
-  tdiag ("%+D%+F%+T", t1, t1, t1);
-  tdiag ("%q+D%q+F%q+T", t1, t1, t1);
+  tdiag ("%D%F%T%V", t1, t1, t1, t1);
+  tdiag ("%+D%+F%+T%+V", t1, t1, t1, t1);
+  tdiag ("%q+D%q+F%q+T%q+V", t1, t1, t1, t1);
   tdiag ("%D%D%D%D", t1, t2, *t3, t4[5]);
-  cdiag ("%D%F%T", t1, t1, t1);
-  cdiag ("%+D%+F%+T", t1, t1, t1);
-  cdiag ("%q+D%q+F%q+T", t1, t1, t1);
+  cdiag ("%D%F%T%V", t1, t1, t1, t1);
+  cdiag ("%+D%+F%+T%+V", t1, t1, t1, t1);
+  cdiag ("%q+D%q+F%q+T%q+V", t1, t1, t1, t1);
   cdiag ("%D%D%D%D", t1, t2, *t3, t4[5]);
   cdiag ("%E", t1);
   cxxdiag ("%A%D%E%F%T%V", t1, t1, t1, t1, t1, t1);
   cxxdiag ("%D%D%D%D", t1, t2, *t3, t4[5]);
   cxxdiag ("%#A%#D%#E%#F%#T%#V", t1, t1, t1, t1, t1, t1);
   cxxdiag ("%+A%+D%+E%+F%+T%+V", t1, t1, t1, t1, t1, t1);
   cxxdiag ("%+#A%+#D%+#E%+#F%+#T%+#V", t1, t1, t1, t1, t1, t1);
   cxxdiag ("%C%L%O%P%Q", i, i, i, i, i);
 
+  tdiag ("%v%qv%#v", i, i, i);
+  cdiag ("%v%qv%#v", i, i, i);
+  cxxdiag ("%v%qv%#v", i, i, i);
+
   /* Bad stuff with extensions.  */
   diag ("%m", i); /* { dg-warning "format" "extra arg" } */
   tdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
   cdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
   cxxdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
@@ -119,10 +123,18 @@ foo (int i, int i1, int i2, unsigned int
   cxxdiag ("%D", i); /* { dg-warning "format" "wrong arg" } */
   tdiag ("%D", t1, t1); /* { dg-warning "format" "extra arg" } */
   cdiag ("%D", t1, t1); /* { dg-warning "format" "extra arg" } */
   cxxdiag ("%D", t1, t1); /* { dg-warning "format" "extra arg" } */
 
+  tdiag ("%V", i); /* { dg-warning "format" "wrong arg" } */
+  cdiag ("%V", i); /* { dg-warning "format" "wrong arg" } */
+  cxxdiag ("%V", i); /* { dg-warning "format" "wrong arg" } */
+
+  tdiag ("%v", t1); /* { dg-warning "format" "wrong arg" } */
+  cdiag ("%v", t1); /* { dg-warning "format" "wrong arg" } */
+  cxxdiag ("%v", t1); /* { dg-warning "format" "wrong arg" } */
+
   /* Standard specifiers not accepted in the diagnostic framework.  */
   diag ("%X\n", u); /* { dg-warning "format" "HEX" } */
   diag ("%f\n", d); /* { dg-warning "format" "float" } */
   diag ("%e\n", d); /* { dg-warning "format" "float" } */
   diag ("%E\n", d); /* { dg-warning "format" "float" } */
Index: gcc/c-objc-common.c
===================================================================
--- gcc/c-objc-common.c	(revision 160273)
+++ gcc/c-objc-common.c	(working copy)
@@ -77,13 +77,14 @@ c_objc_common_init (void)
    is as follows:
    %D: a general decl,
    %E: an identifier or expression,
    %F: a function declaration,
    %T: a type.
+   %V: a list of type qualifiers from a tree.
+   %v: an explicit list of type qualifiers
+   %#v: an explicit list of type qualifiers of a function type.
 
-   These format specifiers form a subset of the format specifiers set used
-   by the C++ front-end.
    Please notice when called, the `%' part was already skipped by the
    diagnostic machinery.  */
 static bool
 c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
 		int precision, bool wide, bool set_locus, bool hash)
@@ -91,23 +92,25 @@ c_tree_printer (pretty_printer *pp, text
   tree t;
   tree name;
   c_pretty_printer *cpp = (c_pretty_printer *) pp;
   pp->padding = pp_none;
 
-  if (precision != 0 || wide || hash)
+  if (precision != 0 || wide)
     return false;
 
   if (*spec == 'K')
     {
       percent_K_format (text);
       return true;
     }
 
-  t = va_arg (*text->args_ptr, tree);
-
-  if (set_locus && text->locus)
-    *text->locus = DECL_SOURCE_LOCATION (t);
+  if (*spec != 'v')
+    {
+      t = va_arg (*text->args_ptr, tree);
+      if (set_locus && text->locus)
+	*text->locus = DECL_SOURCE_LOCATION (t);
+    }
 
   switch (*spec)
     {
     case 'D':
       if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t))
@@ -153,10 +156,18 @@ c_tree_printer (pretty_printer *pp, text
 	pp_identifier (cpp, IDENTIFIER_POINTER (t));
       else
 	pp_expression (cpp, t);
       return true;
 
+    case 'V':
+      pp_c_type_qualifier_list (cpp, t);
+      return true;
+
+    case 'v':
+      pp_c_cv_qualifiers (cpp, va_arg (*text->args_ptr, int), hash);
+      return true;
+
     default:
       return false;
     }
 
   pp_string (cpp, _("({anonymous})"));
Index: gcc/c-format.c
===================================================================
--- gcc/c-format.c	(revision 160273)
+++ gcc/c-format.c	(working copy)
@@ -419,28 +419,20 @@ static const format_flag_pair gcc_gfc_fl
 };
 
 static const format_flag_spec gcc_diag_flag_specs[] =
 {
   { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
   { 'q',  0, 0, N_("'q' flag"),        N_("the 'q' diagnostic flag"),          STD_C89 },
   { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
   { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
   { 0, 0, 0, NULL, NULL, STD_C89 }
 };
 
 #define gcc_tdiag_flag_specs gcc_diag_flag_specs
 #define gcc_cdiag_flag_specs gcc_diag_flag_specs
-
-static const format_flag_spec gcc_cxxdiag_flag_specs[] =
-{
-  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
-  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
-  { 'q',  0, 0, N_("'q' flag"),        N_("the 'q' diagnostic flag"),          STD_C89 },
-  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
-  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
-  { 0, 0, 0, NULL, NULL, STD_C89 }
-};
+#define gcc_cxxdiag_flag_specs gcc_diag_flag_specs
 
 static const format_flag_spec scanf_flag_specs[] =
 {
   { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
   { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
@@ -583,11 +575,13 @@ static const format_char_info gcc_tdiag_
   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
 
   /* Custom conversion specifiers.  */
 
   /* These will require a "tree" at runtime.  */
-  { "DFKTE", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
+  { "DFKTEV", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
+
+  { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
 
   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
 };
@@ -603,11 +597,13 @@ static const format_char_info gcc_cdiag_
   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
 
   /* Custom conversion specifiers.  */
 
   /* These will require a "tree" at runtime.  */
-  { "DEFKT", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
+  { "DEFKTV", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
+
+  { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
 
   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
 };
@@ -625,10 +621,12 @@ static const format_char_info gcc_cxxdia
   /* Custom conversion specifiers.  */
 
   /* These will require a "tree" at runtime.  */
   { "ADEFKTV",0,STD_C89,{ T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+#",   "",   NULL },
 
+  { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
+
   /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.)  */
   { "CLOPQ",0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
 
   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
@@ -720,23 +718,23 @@ static const format_kind_info format_typ
     asm_fprintf_flag_specs, asm_fprintf_flag_pairs,
     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",   gcc_diag_length_specs,  gcc_diag_char_table, "q+#", NULL,
     gcc_diag_flag_specs, gcc_diag_flag_pairs,
     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",   gcc_tdiag_length_specs,  gcc_tdiag_char_table, "q+#", NULL,
     gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs,
     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",   gcc_cdiag_length_specs,  gcc_cdiag_char_table, "q+#", NULL,
     gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
     FMT_FLAG_ARG_CONVERT,
     0, 0, 'p', 0, 'L', 0,
     NULL, &integer_type_node
   },
Index: gcc/c-pretty-print.c
===================================================================
--- gcc/c-pretty-print.c	(revision 160273)
+++ gcc/c-pretty-print.c	(working copy)
@@ -168,22 +168,47 @@ pp_c_exclamation (c_pretty_printer *pp)
 {
   pp_exclamation (pp);
   pp_base (pp)->padding = pp_none;
 }
 
-/* Print out the external representation of CV-QUALIFIER.  */
+/* Print out the external representation of QUALIFIERS.  */
 
-static void
-pp_c_cv_qualifier (c_pretty_printer *pp, const char *cv)
+void
+pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type)
 {
   const char *p = pp_last_position_in_text (pp);
+  bool previous = false;
+
+  if (!qualifiers)
+    return;
+
   /* The C programming language does not have references, but it is much
      simpler to handle those here rather than going through the same
      logic in the C++ pretty-printer.  */
   if (p != NULL && (*p == '*' || *p == '&'))
     pp_c_whitespace (pp);
-  pp_c_ws_string (pp, cv);
+
+  if (qualifiers & TYPE_QUAL_CONST)
+    {
+      pp_c_ws_string (pp, func_type ? "__attribute__((const))" : "const");
+      previous = true;
+    }
+
+  if (qualifiers & TYPE_QUAL_VOLATILE)
+    {
+      if (previous)
+        pp_c_whitespace (pp);
+      pp_c_ws_string (pp, func_type ? "__attribute__((noreturn))" : "volatile");
+      previous = true;
+    }
+
+  if (qualifiers & TYPE_QUAL_RESTRICT)
+    {
+      if (previous)
+        pp_c_whitespace (pp);
+      pp_c_ws_string (pp, flag_isoc99 ? "restrict" : "__restrict__");
+    }
 }
 
 /* Pretty-print T using the type-cast notation '( type-name )'.  */
 
 static void
@@ -240,16 +265,12 @@ pp_c_type_qualifier_list (c_pretty_print
 
   if (!TYPE_P (t))
     t = TREE_TYPE (t);
 
   qualifiers = TYPE_QUALS (t);
-  if (qualifiers & TYPE_QUAL_CONST)
-    pp_c_cv_qualifier (pp, "const");
-  if (qualifiers & TYPE_QUAL_VOLATILE)
-    pp_c_cv_qualifier (pp, "volatile");
-  if (qualifiers & TYPE_QUAL_RESTRICT)
-    pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__");
+  pp_c_cv_qualifiers (pp, qualifiers,
+		      TREE_CODE (t) == FUNCTION_TYPE);
 
   if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
     {
       const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t));
       pp_c_identifier (pp, as);
Index: gcc/c-pretty-print.h
===================================================================
--- gcc/c-pretty-print.h	(revision 160273)
+++ gcc/c-pretty-print.h	(working copy)
@@ -174,10 +174,11 @@ void pp_c_space_for_pointer_operator (c_
 
 /* Declarations.  */
 void pp_c_tree_decl_identifier (c_pretty_printer *, tree);
 void pp_c_function_definition (c_pretty_printer *, tree);
 void pp_c_attributes (c_pretty_printer *, tree);
+void pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type);
 void pp_c_type_qualifier_list (c_pretty_printer *, tree);
 void pp_c_parameter_type_list (c_pretty_printer *, tree);
 void pp_c_declaration (c_pretty_printer *, tree);
 void pp_c_declaration_specifiers (c_pretty_printer *, tree);
 void pp_c_declarator (c_pretty_printer *, tree);
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 160273)
+++ gcc/c-typeck.c	(working copy)
@@ -4438,17 +4438,19 @@ handle_warn_cast_qual (tree type, tree o
     }
   while (TREE_CODE (in_type) == POINTER_TYPE
 	 && TREE_CODE (in_otype) == POINTER_TYPE);
 
   if (added)
-    warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
+    warning (OPT_Wcast_qual, "cast adds %q#v qualifier to function type",
+	     added);
 
   if (discarded)
     /* There are qualifiers present in IN_OTYPE that are not present
        in IN_TYPE.  */
     warning (OPT_Wcast_qual,
-	     "cast discards qualifiers from pointer target type");
+	     "cast discards %q#v qualifier from pointer target type",
+	     discarded);
 
   if (added || discarded)
     return;
 
   /* A cast from **T to const **T is unsafe, because it can cause a
@@ -4477,13 +4479,14 @@ handle_warn_cast_qual (tree type, tree o
       in_type = TREE_TYPE (in_type);
       in_otype = TREE_TYPE (in_otype);
       if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
 	  && !is_const)
 	{
+	  int added = TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype);
 	  warning (OPT_Wcast_qual,
-		   ("new qualifiers in middle of multi-level non-const cast "
-		    "are unsafe"));
+		   ("new %qv qualifier in middle of multi-level non-const cast "
+		    "is unsafe"), added);
 	  break;
 	}
       if (is_const)
 	is_const = TYPE_READONLY (in_type);
     }
@@ -5005,10 +5008,40 @@ convert_for_assignment (location_t locat
       default:                                                           \
         gcc_unreachable ();                                              \
       }                                                                  \
   } while (0)
 
+  /* This macro is used to emit diagnostics to ensure that all format
+     strings are complete sentences, visible to gettext and checked at
+     compile time.  It is the same as WARN_FOR_ASSIGNMENT but with an
+     extra parameter to enumerate qualifiers.  */
+
+#define WARN_FOR_QUALIFIERS(LOCATION, OPT, AR, AS, IN, RE, QUALS)        \
+  do {                                                                   \
+    switch (errtype)                                                     \
+      {                                                                  \
+      case ic_argpass:                                                   \
+        if (pedwarn (LOCATION, OPT, AR, parmnum, rname, QUALS))          \
+          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
+	      	  ? DECL_SOURCE_LOCATION (fundecl) : LOCATION,		 \
+                  "expected %qT but argument is of type %qT",            \
+                  type, rhstype);                                        \
+        break;                                                           \
+      case ic_assign:                                                    \
+        pedwarn (LOCATION, OPT, AS, QUALS);                          \
+        break;                                                           \
+      case ic_init:                                                      \
+        pedwarn (LOCATION, OPT, IN, QUALS);                          \
+        break;                                                           \
+      case ic_return:                                                    \
+        pedwarn (LOCATION, OPT, RE, QUALS);                        	 \
+        break;                                                           \
+      default:                                                           \
+        gcc_unreachable ();                                              \
+      }                                                                  \
+  } while (0)
+
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
 
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
@@ -5212,34 +5245,36 @@ convert_for_assignment (location_t locat
 		     certain things, it is okay to use a const or volatile
 		     function where an ordinary one is wanted, but not
 		     vice-versa.  */
 		  if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
 		      & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-		    WARN_FOR_ASSIGNMENT (location, 0,
+		    WARN_FOR_QUALIFIERS (location, 0,
 					 G_("passing argument %d of %qE "
-					    "makes qualified function "
+					    "makes %q#v qualified function "
 					    "pointer from unqualified"),
-					 G_("assignment makes qualified "
+					 G_("assignment makes %q#v qualified "
 					    "function pointer from "
 					    "unqualified"),
-					 G_("initialization makes qualified "
+					 G_("initialization makes %q#v qualified "
 					    "function pointer from "
 					    "unqualified"),
-					 G_("return makes qualified function "
-					    "pointer from unqualified"));
+					 G_("return makes %q#v qualified function "
+					    "pointer from unqualified"),
+					 TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
 		}
 	      else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
 		       & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
-		WARN_FOR_ASSIGNMENT (location, 0,
+		WARN_FOR_QUALIFIERS (location, 0,
 				     G_("passing argument %d of %qE discards "
-					"qualifiers from pointer target type"),
-				     G_("assignment discards qualifiers "
+					"%qv qualifier from pointer target type"),
+				     G_("assignment discards %qv qualifier "
 					"from pointer target type"),
-				     G_("initialization discards qualifiers "
+				     G_("initialization discards %qv qualifier "
 					"from pointer target type"),
-				     G_("return discards qualifiers from "
-					"pointer target type"));
+				     G_("return discards %qv qualifier from "
+					"pointer target type"),
+				     TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
 
 	      memb = marginal_memb;
 	    }
 
 	  if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
@@ -5381,19 +5416,20 @@ convert_for_assignment (location_t locat
 		{
 		  /* Types differing only by the presence of the 'volatile'
 		     qualifier are acceptable if the 'volatile' has been added
 		     in by the Objective-C EH machinery.  */
 		  if (!objc_type_quals_match (ttl, ttr))
-		    WARN_FOR_ASSIGNMENT (location, 0,
+		    WARN_FOR_QUALIFIERS (location, 0,
 					 G_("passing argument %d of %qE discards "
-					    "qualifiers from pointer target type"),
-					 G_("assignment discards qualifiers "
+					    "%qv qualifier from pointer target type"),
+					 G_("assignment discards %qv qualifier "
 					    "from pointer target type"),
-					 G_("initialization discards qualifiers "
+					 G_("initialization discards %qv qualifier "
 					    "from pointer target type"),
-					 G_("return discards qualifiers from "
-					    "pointer target type"));
+					 G_("return discards %qv qualifier from "
+					    "pointer target type"),
+					 TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
 		}
 	      /* If this is not a case of ignoring a mismatch in signedness,
 		 no warning.  */
 	      else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
 		       || target_cmp)
@@ -5417,20 +5453,21 @@ convert_for_assignment (location_t locat
 		 that say the function will not do certain things,
 		 it is okay to use a const or volatile function
 		 where an ordinary one is wanted, but not vice-versa.  */
 	      if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
 		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-		WARN_FOR_ASSIGNMENT (location, 0,
+		WARN_FOR_QUALIFIERS (location, 0,
 				     G_("passing argument %d of %qE makes "
-					"qualified function pointer "
+					"%q#v qualified function pointer "
 					"from unqualified"),
-				     G_("assignment makes qualified function "
+				     G_("assignment makes %q#v qualified function "
 					"pointer from unqualified"),
-				     G_("initialization makes qualified "
+				     G_("initialization makes %q#v qualified "
 					"function pointer from unqualified"),
-				     G_("return makes qualified function "
-					"pointer from unqualified"));
+				     G_("return makes %q#v qualified function "
+					"pointer from unqualified"),
+				     TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
 	    }
 	}
       else
 	/* Avoid warning about the volatile ObjC EH puts on decls.  */
 	if (!objc_ok)


More information about the Gcc-patches mailing list