diff mbox

C PATCH to display types when printing a conversion warning (PR c/81233)

Message ID 20170713141820.GD2890@redhat.com
State New
Headers show

Commit Message

Marek Polacek July 13, 2017, 2:18 p.m. UTC
This patch improves diagnostic in the C FE by printing the types when reporting
a problem with a conversion.  E.g., instead of 

   warning: assignment from incompatible pointer type

you'll now get

  warning: assignment to 'int *' from incompatible pointer type 'char *'

or instead of

  warning: initialization makes integer from pointer without a cast

this

   warning: initialization of 'int *' from 'int' makes pointer from integer without a cast

I've been wanting this for a long time and here it is.  Two snags: I had to
make pedwarn_init to take '...' for which I had to introduce
emit_diagnostic_valist; you can't pass varargs from one vararg function to
another vararg function (and a macro with __VA_ARGS__ didn't work here).  Also,
PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE and
RHSTYPE so I just decided to unroll the macro instead of making it even more
ugly.  This patch is long but it's mainly because of the testsuite fallout.

If you have better ideas about the wording, let me know.

There are still more warnings to improve but I think better to do this
incrementally rather than a single humongous patch.

Bootstrapped/regtested on x86_64-linux and powerpc64le-unknown-linux-gnu,
ok for trunk?

2017-07-13  Marek Polacek  <polacek@redhat.com>

	PR c/81233
	* c-typeck.c (pedwarn_init): Make the function take a variable list.
	Call emit_diagnostic_valist instead of pedwarn.
	(convert_for_assignment): Unroll the PEDWARN_FOR_ASSIGNMENT macro.
	Print the relevant types in diagnostics.

	* diagnostic-core.h (emit_diagnostic_valist): Add declaration.
	* diagnostic.c (emit_diagnostic): Add a comment.
	(emit_diagnostic_valist): New function.

	* gcc.dg/diagnostic-types-1.c: New test.
	* gcc.dg/assign-warn-1.c: Update warning messages.
	* gcc.dg/assign-warn-2.c: Likewise.
	* gcc.dg/c90-const-expr-5.c: Likewise.
	* gcc.dg/c99-const-expr-5.c: Likewise.
	* gcc.dg/conv-2.c: Likewise.
	* gcc.dg/init-bad-7.c: Likewise.
	* gcc.dg/overflow-warn-1.c: Likewise.
	* gcc.dg/overflow-warn-2.c: Likewise.
	* gcc.dg/overflow-warn-3.c: Likewise.
	* gcc.dg/overflow-warn-4.c: Likewise.
	* gcc.dg/pointer-array-atomic.c: Likewise.
	* gcc.dg/pr26865.c: Likewise.
	* gcc.dg/pr61162-2.c: Likewise.
	* gcc.dg/pr61162.c: Likewise.
	* gcc.dg/pr67730-2.c: Likewise.
	* gcc.dg/pr69156.c: Likewise.
	* gcc.dg/pr70174.c: Likewise.
	* objc.dg/proto-lossage-4.m: Likewise.


	Marek

Comments

Martin Sebor July 13, 2017, 5:42 p.m. UTC | #1
On 07/13/2017 08:18 AM, Marek Polacek wrote:
> This patch improves diagnostic in the C FE by printing the types when reporting
> a problem with a conversion.  E.g., instead of
>
>    warning: assignment from incompatible pointer type
>
> you'll now get
>
>   warning: assignment to 'int *' from incompatible pointer type 'char *'
>
> or instead of
>
>   warning: initialization makes integer from pointer without a cast
>
> this
>
>    warning: initialization of 'int *' from 'int' makes pointer from integer without a cast
>
> I've been wanting this for a long time and here it is.  Two snags: I had to
> make pedwarn_init to take '...' for which I had to introduce
> emit_diagnostic_valist; you can't pass varargs from one vararg function to
> another vararg function (and a macro with __VA_ARGS__ didn't work here).  Also,
> PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE and
> RHSTYPE so I just decided to unroll the macro instead of making it even more
> ugly.  This patch is long but it's mainly because of the testsuite fallout.
>
> If you have better ideas about the wording, let me know.

It looks pretty good as is.  My only wording suggestion is to
consider simply mentioning conversion in the text of the warnings:

   warning: conversion to T* from an incompatible type U*

I'm not sure that being explicit about the context where the bad
conversion takes place (initialization vs assignment vs returning
a value) is terribly helpful.  That would not only simplify the
code and make all the messages consistent, but it would also make
it possible to get rid of the note when passing arguments.

>
> There are still more warnings to improve but I think better to do this
> incrementally rather than a single humongous patch.

That makes sense.  I was going to mention that it would be nice
to also improve:

   warning: comparison of distinct pointer types lacks a cast

If you take the conversion suggestion I think this warning would
need to be phrased in terms of "conversion between T* and U*"
rather than "conversion from T* to U*".  (A similar change could
be made to the error message printed when incompatible pointers
are subtracted from one another.)

Martin
Marek Polacek July 14, 2017, 12:52 p.m. UTC | #2
On Thu, Jul 13, 2017 at 11:42:15AM -0600, Martin Sebor wrote:
> On 07/13/2017 08:18 AM, Marek Polacek wrote:
> > This patch improves diagnostic in the C FE by printing the types when reporting
> > a problem with a conversion.  E.g., instead of
> > 
> >    warning: assignment from incompatible pointer type
> > 
> > you'll now get
> > 
> >   warning: assignment to 'int *' from incompatible pointer type 'char *'
> > 
> > or instead of
> > 
> >   warning: initialization makes integer from pointer without a cast
> > 
> > this
> > 
> >    warning: initialization of 'int *' from 'int' makes pointer from integer without a cast
> > 
> > I've been wanting this for a long time and here it is.  Two snags: I had to
> > make pedwarn_init to take '...' for which I had to introduce
> > emit_diagnostic_valist; you can't pass varargs from one vararg function to
> > another vararg function (and a macro with __VA_ARGS__ didn't work here).  Also,
> > PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE and
> > RHSTYPE so I just decided to unroll the macro instead of making it even more
> > ugly.  This patch is long but it's mainly because of the testsuite fallout.
> > 
> > If you have better ideas about the wording, let me know.
> 
> It looks pretty good as is.  My only wording suggestion is to
> consider simply mentioning conversion in the text of the warnings:
> 
>   warning: conversion to T* from an incompatible type U*
> 
> I'm not sure that being explicit about the context where the bad
> conversion takes place (initialization vs assignment vs returning
> a value) is terribly helpful.  That would not only simplify the
> code and make all the messages consistent, but it would also make
> it possible to get rid of the note when passing arguments.
 
Yeah, I agree, actually.  We print the expressions in question (although,
we could probably do even better), and I don't see why it would be
necessary to mention whether it's an initialization or an assignment.
I think I'll just drop this patch and do something along the lines you
suggest.

David, do you agree with this?  (Joseph's on PTO but I'd of course like
to hear his opinion, too.)

One more thing: for 

int *q = p;
int i = q;
we should be able to provide a fix-it hint, something like 'did you mean
to dereference q?'.  With the current PEDWARN_FOR_ASSIGNMENT macro it
would be awkward to implement that.

> > There are still more warnings to improve but I think better to do this
> > incrementally rather than a single humongous patch.
> 
> That makes sense.  I was going to mention that it would be nice
> to also improve:
> 
>   warning: comparison of distinct pointer types lacks a cast
> 
> If you take the conversion suggestion I think this warning would
> need to be phrased in terms of "conversion between T* and U*"
> rather than "conversion from T* to U*".  (A similar change could
> be made to the error message printed when incompatible pointers
> are subtracted from one another.)

Sure.

	Marek
Marek Polacek July 14, 2017, 1:47 p.m. UTC | #3
On Fri, Jul 14, 2017 at 02:52:36PM +0200, Marek Polacek wrote:
> On Thu, Jul 13, 2017 at 11:42:15AM -0600, Martin Sebor wrote:
> > On 07/13/2017 08:18 AM, Marek Polacek wrote:
> > > This patch improves diagnostic in the C FE by printing the types when reporting
> > > a problem with a conversion.  E.g., instead of
> > > 
> > >    warning: assignment from incompatible pointer type
> > > 
> > > you'll now get
> > > 
> > >   warning: assignment to 'int *' from incompatible pointer type 'char *'
> > > 
> > > or instead of
> > > 
> > >   warning: initialization makes integer from pointer without a cast
> > > 
> > > this
> > > 
> > >    warning: initialization of 'int *' from 'int' makes pointer from integer without a cast
> > > 
> > > I've been wanting this for a long time and here it is.  Two snags: I had to
> > > make pedwarn_init to take '...' for which I had to introduce
> > > emit_diagnostic_valist; you can't pass varargs from one vararg function to
> > > another vararg function (and a macro with __VA_ARGS__ didn't work here).  Also,
> > > PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE and
> > > RHSTYPE so I just decided to unroll the macro instead of making it even more
> > > ugly.  This patch is long but it's mainly because of the testsuite fallout.
> > > 
> > > If you have better ideas about the wording, let me know.
> > 
> > It looks pretty good as is.  My only wording suggestion is to
> > consider simply mentioning conversion in the text of the warnings:
> > 
> >   warning: conversion to T* from an incompatible type U*
> > 
> > I'm not sure that being explicit about the context where the bad
> > conversion takes place (initialization vs assignment vs returning
> > a value) is terribly helpful.  That would not only simplify the
> > code and make all the messages consistent, but it would also make
> > it possible to get rid of the note when passing arguments.
>  
> Yeah, I agree, actually.  We print the expressions in question (although,
> we could probably do even better), and I don't see why it would be
> necessary to mention whether it's an initialization or an assignment.
> I think I'll just drop this patch and do something along the lines you
> suggest.
> 
> David, do you agree with this?  (Joseph's on PTO but I'd of course like
> to hear his opinion, too.)
 
I think I changed my mind.  Because clang says e.g.
warning: returning 'unsigned int *' from a function with result type 'int *'
      converts between pointers to integer types with different sign
so in the end it might be best to just go with my current patch; it should
only improve things anyway.  And then add the fix-it hint.

> One more thing: for 
> 
> int *q = p;
> int i = q;
> we should be able to provide a fix-it hint, something like 'did you mean
> to dereference q?'.  With the current PEDWARN_FOR_ASSIGNMENT macro it
> would be awkward to implement that.
> 
> > > There are still more warnings to improve but I think better to do this
> > > incrementally rather than a single humongous patch.
> > 
> > That makes sense.  I was going to mention that it would be nice
> > to also improve:
> > 
> >   warning: comparison of distinct pointer types lacks a cast
> > 
> > If you take the conversion suggestion I think this warning would
> > need to be phrased in terms of "conversion between T* and U*"
> > rather than "conversion from T* to U*".  (A similar change could
> > be made to the error message printed when incompatible pointers
> > are subtracted from one another.)
> 
> Sure.
> 
> 	Marek

	Marek
Martin Sebor July 14, 2017, 3:40 p.m. UTC | #4
On 07/14/2017 07:47 AM, Marek Polacek wrote:
> On Fri, Jul 14, 2017 at 02:52:36PM +0200, Marek Polacek wrote:
>> On Thu, Jul 13, 2017 at 11:42:15AM -0600, Martin Sebor wrote:
>>> On 07/13/2017 08:18 AM, Marek Polacek wrote:
>>>> This patch improves diagnostic in the C FE by printing the types when reporting
>>>> a problem with a conversion.  E.g., instead of
>>>>
>>>>    warning: assignment from incompatible pointer type
>>>>
>>>> you'll now get
>>>>
>>>>   warning: assignment to 'int *' from incompatible pointer type 'char *'
>>>>
>>>> or instead of
>>>>
>>>>   warning: initialization makes integer from pointer without a cast
>>>>
>>>> this
>>>>
>>>>    warning: initialization of 'int *' from 'int' makes pointer from integer without a cast
>>>>
>>>> I've been wanting this for a long time and here it is.  Two snags: I had to
>>>> make pedwarn_init to take '...' for which I had to introduce
>>>> emit_diagnostic_valist; you can't pass varargs from one vararg function to
>>>> another vararg function (and a macro with __VA_ARGS__ didn't work here).  Also,
>>>> PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE and
>>>> RHSTYPE so I just decided to unroll the macro instead of making it even more
>>>> ugly.  This patch is long but it's mainly because of the testsuite fallout.
>>>>
>>>> If you have better ideas about the wording, let me know.
>>>
>>> It looks pretty good as is.  My only wording suggestion is to
>>> consider simply mentioning conversion in the text of the warnings:
>>>
>>>   warning: conversion to T* from an incompatible type U*
>>>
>>> I'm not sure that being explicit about the context where the bad
>>> conversion takes place (initialization vs assignment vs returning
>>> a value) is terribly helpful.  That would not only simplify the
>>> code and make all the messages consistent, but it would also make
>>> it possible to get rid of the note when passing arguments.
>>
>> Yeah, I agree, actually.  We print the expressions in question (although,
>> we could probably do even better), and I don't see why it would be
>> necessary to mention whether it's an initialization or an assignment.
>> I think I'll just drop this patch and do something along the lines you
>> suggest.
>>
>> David, do you agree with this?  (Joseph's on PTO but I'd of course like
>> to hear his opinion, too.)
>
> I think I changed my mind.  Because clang says e.g.
> warning: returning 'unsigned int *' from a function with result type 'int *'
>       converts between pointers to integer types with different sign
> so in the end it might be best to just go with my current patch; it should
> only improve things anyway.  And then add the fix-it hint.

Yes, Clang does do that.  G++, OTOH, prints an error with the same
text in all these cases.  It's not tremendously important which of
the two forms is used.  What I do think would be nice is if the text
of the same diagnostics, whether warnings or errors, could be more
consistent between the front ends.  A good way to do that in general,
if all of the checking code cannot be shared, is to provide a shared
diagnose_this_or_that() function for each diagnostic.  The function
would be parameterized on the kind of diagnostic (i.e., error or
warning), but would hardcode the shared text.  Each FE would call
it with an argument telling it whether to issue it as an error or
warning.

Martin

>> One more thing: for
>>
>> int *q = p;
>> int i = q;
>> we should be able to provide a fix-it hint, something like 'did you mean
>> to dereference q?'.  With the current PEDWARN_FOR_ASSIGNMENT macro it
>> would be awkward to implement that.
>>
>>>> There are still more warnings to improve but I think better to do this
>>>> incrementally rather than a single humongous patch.
>>>
>>> That makes sense.  I was going to mention that it would be nice
>>> to also improve:
>>>
>>>   warning: comparison of distinct pointer types lacks a cast
>>>
>>> If you take the conversion suggestion I think this warning would
>>> need to be phrased in terms of "conversion between T* and U*"
>>> rather than "conversion from T* to U*".  (A similar change could
>>> be made to the error message printed when incompatible pointers
>>> are subtracted from one another.)
>>
>> Sure.
>>
>> 	Marek
>
> 	Marek
>
Martin Sebor July 14, 2017, 8:02 p.m. UTC | #5
On 07/14/2017 09:40 AM, Martin Sebor wrote:
> On 07/14/2017 07:47 AM, Marek Polacek wrote:
>> On Fri, Jul 14, 2017 at 02:52:36PM +0200, Marek Polacek wrote:
>>> On Thu, Jul 13, 2017 at 11:42:15AM -0600, Martin Sebor wrote:
>>>> On 07/13/2017 08:18 AM, Marek Polacek wrote:
>>>>> This patch improves diagnostic in the C FE by printing the types
>>>>> when reporting
>>>>> a problem with a conversion.  E.g., instead of
>>>>>
>>>>>    warning: assignment from incompatible pointer type
>>>>>
>>>>> you'll now get
>>>>>
>>>>>   warning: assignment to 'int *' from incompatible pointer type
>>>>> 'char *'
>>>>>
>>>>> or instead of
>>>>>
>>>>>   warning: initialization makes integer from pointer without a cast
>>>>>
>>>>> this
>>>>>
>>>>>    warning: initialization of 'int *' from 'int' makes pointer from
>>>>> integer without a cast
>>>>>
>>>>> I've been wanting this for a long time and here it is.  Two snags:
>>>>> I had to
>>>>> make pedwarn_init to take '...' for which I had to introduce
>>>>> emit_diagnostic_valist; you can't pass varargs from one vararg
>>>>> function to
>>>>> another vararg function (and a macro with __VA_ARGS__ didn't work
>>>>> here).  Also,
>>>>> PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing
>>>>> TYPE and
>>>>> RHSTYPE so I just decided to unroll the macro instead of making it
>>>>> even more
>>>>> ugly.  This patch is long but it's mainly because of the testsuite
>>>>> fallout.
>>>>>
>>>>> If you have better ideas about the wording, let me know.
>>>>
>>>> It looks pretty good as is.  My only wording suggestion is to
>>>> consider simply mentioning conversion in the text of the warnings:
>>>>
>>>>   warning: conversion to T* from an incompatible type U*
>>>>
>>>> I'm not sure that being explicit about the context where the bad
>>>> conversion takes place (initialization vs assignment vs returning
>>>> a value) is terribly helpful.  That would not only simplify the
>>>> code and make all the messages consistent, but it would also make
>>>> it possible to get rid of the note when passing arguments.
>>>
>>> Yeah, I agree, actually.  We print the expressions in question
>>> (although,
>>> we could probably do even better), and I don't see why it would be
>>> necessary to mention whether it's an initialization or an assignment.
>>> I think I'll just drop this patch and do something along the lines you
>>> suggest.
>>>
>>> David, do you agree with this?  (Joseph's on PTO but I'd of course like
>>> to hear his opinion, too.)
>>
>> I think I changed my mind.  Because clang says e.g.
>> warning: returning 'unsigned int *' from a function with result type
>> 'int *'
>>       converts between pointers to integer types with different sign
>> so in the end it might be best to just go with my current patch; it
>> should
>> only improve things anyway.  And then add the fix-it hint.
>
> Yes, Clang does do that.  G++, OTOH, prints an error with the same
> text in all these cases.  It's not tremendously important which of
> the two forms is used.  What I do think would be nice is if the text
> of the same diagnostics, whether warnings or errors, could be more
> consistent between the front ends.  A good way to do that in general,
> if all of the checking code cannot be shared, is to provide a shared
> diagnose_this_or_that() function for each diagnostic.  The function
> would be parameterized on the kind of diagnostic (i.e., error or
> warning), but would hardcode the shared text.  Each FE would call
> it with an argument telling it whether to issue it as an error or
> warning.

Just to be clear: I don't mean to suggest to do this in this patch
or necessarily even for this warning.  I'm not even sure to what
extent it might be doable.  I mention it mostly as food for thought.

>
> Martin
>
>>> One more thing: for
>>>
>>> int *q = p;
>>> int i = q;
>>> we should be able to provide a fix-it hint, something like 'did you mean
>>> to dereference q?'.  With the current PEDWARN_FOR_ASSIGNMENT macro it
>>> would be awkward to implement that.
>>>
>>>>> There are still more warnings to improve but I think better to do this
>>>>> incrementally rather than a single humongous patch.
>>>>
>>>> That makes sense.  I was going to mention that it would be nice
>>>> to also improve:
>>>>
>>>>   warning: comparison of distinct pointer types lacks a cast
>>>>
>>>> If you take the conversion suggestion I think this warning would
>>>> need to be phrased in terms of "conversion between T* and U*"
>>>> rather than "conversion from T* to U*".  (A similar change could
>>>> be made to the error message printed when incompatible pointers
>>>> are subtracted from one another.)
>>>
>>> Sure.
>>>
>>>     Marek
>>
>>     Marek
>>
>
Marek Polacek July 19, 2017, 9:33 a.m. UTC | #6
On Fri, Jul 14, 2017 at 02:02:34PM -0600, Martin Sebor wrote:
> Just to be clear: I don't mean to suggest to do this in this patch
> or necessarily even for this warning.  I'm not even sure to what
> extent it might be doable.  I mention it mostly as food for thought.

Sure, and it makes sense (where it's possible).  But this particular
patch just adds the types to the diagnostic and I think anything more
is beyond the scope of this patch.  So - still presenting it as it was :).

Thanks for looking into this,

	Marek
David Malcolm July 19, 2017, 2:51 p.m. UTC | #7
On Thu, 2017-07-13 at 16:18 +0200, Marek Polacek wrote:
> This patch improves diagnostic in the C FE by printing the types when
> reporting
> a problem with a conversion.  E.g., instead of 
> 
>    warning: assignment from incompatible pointer type
> 
> you'll now get
> 
>   warning: assignment to 'int *' from incompatible pointer type 'char
> *'
> 
> or instead of
> 
>   warning: initialization makes integer from pointer without a cast
> 
> this
> 
>    warning: initialization of 'int *' from 'int' makes pointer from
> integer without a cast
> 
> I've been wanting this for a long time and here it is.  Two snags: I
> had to
> make pedwarn_init to take '...' for which I had to introduce
> emit_diagnostic_valist; you can't pass varargs from one vararg
> function to
> another vararg function (and a macro with __VA_ARGS__ didn't work
> here).  

The changes to diagnostic-core.h and diagnostic.c are OK.

> Also,
> PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE
> and
> RHSTYPE so I just decided to unroll the macro instead of making it
> even more
> ugly.
> This patch is long but it's mainly because of the testsuite fallout.

The comment by PEDWARN_FOR_ASSIGNMENT says:


  /* This macro is used to emit diagnostics to ensure that all format
     strings are complete sentences, visible to gettext and checked
at
     compile time.  */

I wonder if it's possible to convert it to an inline function to get
the same test coverage, without unrolling the macro?

[...snip...]

Dave
Marek Polacek July 20, 2017, 10:53 a.m. UTC | #8
On Wed, Jul 19, 2017 at 10:51:33AM -0400, David Malcolm wrote:
> The changes to diagnostic-core.h and diagnostic.c are OK.

Thanks.
 
> > Also,
> > PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE
> > and
> > RHSTYPE so I just decided to unroll the macro instead of making it
> > even more
> > ugly.
> > This patch is long but it's mainly because of the testsuite fallout.
> 
> The comment by PEDWARN_FOR_ASSIGNMENT says:
> 
> 
>   /* This macro is used to emit diagnostics to ensure that all format
>      strings are complete sentences, visible to gettext and checked
> at
>      compile time.  */
> 
> I wonder if it's possible to convert it to an inline function to get
> the same test coverage, without unrolling the macro?

Yeah, I tried, but the resulting inline function would have to have 12
parameters if I count well and that didn't seem like a win.  Perhaps
splitting convert_for_assignment would make sense, but likely not as
part of this patch.

	Marek
Marek Polacek July 31, 2017, 11:27 a.m. UTC | #9
Ping.

On Thu, Jul 20, 2017 at 12:53:10PM +0200, Marek Polacek wrote:
> On Wed, Jul 19, 2017 at 10:51:33AM -0400, David Malcolm wrote:
> > The changes to diagnostic-core.h and diagnostic.c are OK.
> 
> Thanks.
>  
> > > Also,
> > > PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE
> > > and
> > > RHSTYPE so I just decided to unroll the macro instead of making it
> > > even more
> > > ugly.
> > > This patch is long but it's mainly because of the testsuite fallout.
> > 
> > The comment by PEDWARN_FOR_ASSIGNMENT says:
> > 
> > 
> >   /* This macro is used to emit diagnostics to ensure that all format
> >      strings are complete sentences, visible to gettext and checked
> > at
> >      compile time.  */
> > 
> > I wonder if it's possible to convert it to an inline function to get
> > the same test coverage, without unrolling the macro?
> 
> Yeah, I tried, but the resulting inline function would have to have 12
> parameters if I count well and that didn't seem like a win.  Perhaps
> splitting convert_for_assignment would make sense, but likely not as
> part of this patch.

	Marek
Marek Polacek Aug. 8, 2017, 11:28 a.m. UTC | #10
Ping.

On Mon, Jul 31, 2017 at 01:27:01PM +0200, Marek Polacek wrote:
> Ping.
> 
> On Thu, Jul 20, 2017 at 12:53:10PM +0200, Marek Polacek wrote:
> > On Wed, Jul 19, 2017 at 10:51:33AM -0400, David Malcolm wrote:
> > > The changes to diagnostic-core.h and diagnostic.c are OK.
> > 
> > Thanks.
> >  
> > > > Also,
> > > > PEDWARN_FOR_ASSIGNMENT didn't work with the addition of printing TYPE
> > > > and
> > > > RHSTYPE so I just decided to unroll the macro instead of making it
> > > > even more
> > > > ugly.
> > > > This patch is long but it's mainly because of the testsuite fallout.
> > > 
> > > The comment by PEDWARN_FOR_ASSIGNMENT says:
> > > 
> > > 
> > >   /* This macro is used to emit diagnostics to ensure that all format
> > >      strings are complete sentences, visible to gettext and checked
> > > at
> > >      compile time.  */
> > > 
> > > I wonder if it's possible to convert it to an inline function to get
> > > the same test coverage, without unrolling the macro?
> > 
> > Yeah, I tried, but the resulting inline function would have to have 12
> > parameters if I count well and that didn't seem like a win.  Perhaps
> > splitting convert_for_assignment would make sense, but likely not as
> > part of this patch.

	Marek
Joseph Myers Aug. 8, 2017, 9:54 p.m. UTC | #11
On Thu, 13 Jul 2017, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-linux and powerpc64le-unknown-linux-gnu,
> ok for trunk?

OK.
Andreas Schwab Aug. 10, 2017, 8:52 a.m. UTC | #12
On Jul 13 2017, Marek Polacek <polacek@redhat.com> wrote:

> diff --git gcc/testsuite/objc.dg/proto-lossage-4.m gcc/testsuite/objc.dg/proto-lossage-4.m
> index e72328b3703..4c6b560bab4 100644
> --- gcc/testsuite/objc.dg/proto-lossage-4.m
> +++ gcc/testsuite/objc.dg/proto-lossage-4.m
> @@ -28,13 +28,13 @@ long foo(void) {
>    receiver += [receiver anotherValue]; /* { dg-warning "invalid receiver type .intptr_t." } */
>  
>    receiver += [(Obj *)receiver someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
>  
>    receiver += [(Obj *)receiver anotherValue];
>    receiver += [(Obj <Proto> *)receiver someValue];
>    receiver += [(Obj <Proto> *)receiver anotherValue];
>    receiver += [objrcvr someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
>  
>    receiver += [objrcvr anotherValue];
>    receiver += [(Obj <Proto> *)objrcvr someValue];
> @@ -42,7 +42,7 @@ long foo(void) {
>    receiver += [objrcvr2 someValue];
>    receiver += [objrcvr2 anotherValue];
>    receiver += [(Obj *)objrcvr2 someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
>  
>    receiver += [(Obj *)objrcvr2 anotherValue];
>  

FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 30)
FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 36)
FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 44)
FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime (test for excess errors)
Excess errors:
/daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:30:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]
/daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:36:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]
/daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:44:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]

Andreas.
Marek Polacek Aug. 10, 2017, 8:58 a.m. UTC | #13
On Thu, Aug 10, 2017 at 10:52:54AM +0200, Andreas Schwab wrote:
> On Jul 13 2017, Marek Polacek <polacek@redhat.com> wrote:
> 
> > diff --git gcc/testsuite/objc.dg/proto-lossage-4.m gcc/testsuite/objc.dg/proto-lossage-4.m
> > index e72328b3703..4c6b560bab4 100644
> > --- gcc/testsuite/objc.dg/proto-lossage-4.m
> > +++ gcc/testsuite/objc.dg/proto-lossage-4.m
> > @@ -28,13 +28,13 @@ long foo(void) {
> >    receiver += [receiver anotherValue]; /* { dg-warning "invalid receiver type .intptr_t." } */
> >  
> >    receiver += [(Obj *)receiver someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> > -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> > +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> >  
> >    receiver += [(Obj *)receiver anotherValue];
> >    receiver += [(Obj <Proto> *)receiver someValue];
> >    receiver += [(Obj <Proto> *)receiver anotherValue];
> >    receiver += [objrcvr someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> > -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> > +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> >  
> >    receiver += [objrcvr anotherValue];
> >    receiver += [(Obj <Proto> *)objrcvr someValue];
> > @@ -42,7 +42,7 @@ long foo(void) {
> >    receiver += [objrcvr2 someValue];
> >    receiver += [objrcvr2 anotherValue];
> >    receiver += [(Obj *)objrcvr2 someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
> > -/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> > +/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
> >  
> >    receiver += [(Obj *)objrcvr2 anotherValue];
> >  
> 
> FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 30)
> FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 36)
> FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime  (test for warnings, line 44)
> FAIL: objc.dg/proto-lossage-4.m -fgnu-runtime (test for excess errors)
> Excess errors:
> /daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:30:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]
> /daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:36:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]
> /daten/aranym/gcc/gcc-20170810/gcc/testsuite/objc.dg/proto-lossage-4.m:44:12: warning: assignment to 'intptr_t {aka int}' from 'id' makes integer from pointer without a cast [-Wint-conversion]

Argh.  Sorry, will fix now.

	Marek
diff mbox

Patch

diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 4d067e96dd3..742c047f7d1 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -6055,20 +6055,19 @@  error_init (location_t loc, const char *gmsgid)
    it is unconditionally given.  GMSGID identifies the message.  The
    component name is taken from the spelling stack.  */
 
-static void
-pedwarn_init (location_t loc, int opt, const char *gmsgid)
+static void ATTRIBUTE_GCC_DIAG (3,0)
+pedwarn_init (location_t loc, int opt, const char *gmsgid, ...)
 {
-  char *ofwhat;
-  bool warned;
-
   /* Use the location where a macro was expanded rather than where
      it was defined to make sure macros defined in system headers
      but used incorrectly elsewhere are diagnosed.  */
   source_location exploc = expansion_point_location_if_in_system_header (loc);
 
-  /* The gmsgid may be a format string with %< and %>. */
-  warned = pedwarn (exploc, opt, gmsgid);
-  ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool warned = emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, &ap);
+  va_end (ap);
+  char *ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat && warned)
     inform (exploc, "(near initialization for %qs)", ofwhat);
 }
@@ -6301,17 +6300,33 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
       if (checktype != error_mark_node
 	  && TREE_CODE (type) == ENUMERAL_TYPE
 	  && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type))
-	{
-	  PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wc___compat,
-			          G_("enum conversion when passing argument "
-				     "%d of %qE is invalid in C++"),
-			          G_("enum conversion in assignment is "
-				     "invalid in C++"),
-			          G_("enum conversion in initialization is "
-				     "invalid in C++"),
-			          G_("enum conversion in return is "
-				     "invalid in C++"));
-	}
+	switch (errtype)
+	  {
+	  case ic_argpass:
+	    if (pedwarn (expr_loc, OPT_Wc___compat, "enum conversion when "
+			 "passing argument %d of %qE is invalid in C++",
+			 parmnum, rname))
+	      inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+		      ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+		      "expected %qT but argument is of type %qT",
+		      type, rhstype);
+	    break;
+	  case ic_assign:
+	    pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to "
+		     "%qT in assignment is invalid in C++", rhstype, type);
+	    break;
+	  case ic_init:
+	    pedwarn_init (location, OPT_Wc___compat, "enum conversion from "
+			  "%qT to %qT in initialization is invalid in C++",
+			  rhstype, type);
+	    break;
+	  case ic_return:
+	    pedwarn (location, OPT_Wc___compat, "enum conversion from %qT to "
+		     "%qT in return is invalid in C++", rhstype, type);
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
@@ -6717,15 +6732,36 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		;
 	      /* If there is a mismatch, do warn.  */
 	      else if (warn_pointer_sign)
-		 PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpointer_sign,
-				         G_("pointer targets in passing argument "
-					    "%d of %qE differ in signedness"),
-				         G_("pointer targets in assignment "
-					    "differ in signedness"),
-				         G_("pointer targets in initialization "
-					    "differ in signedness"),
-				         G_("pointer targets in return differ "
-					    "in signedness"));
+		switch (errtype)
+		  {
+		  case ic_argpass:
+		    if (pedwarn (expr_loc, OPT_Wpointer_sign,
+				 "pointer targets in passing argument %d of "
+				 "%qE differ in signedness", parmnum, rname))
+		      inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+			      ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+			      "expected %qT but argument is of type %qT",
+			      type, rhstype);
+		    break;
+		  case ic_assign:
+		    pedwarn (location, OPT_Wpointer_sign,
+			     "pointer targets in assignment from %qT to %qT "
+			     "differ in signedness", rhstype, type);
+		    break;
+		  case ic_init:
+		    pedwarn_init (location, OPT_Wpointer_sign,
+				  "pointer targets in initialization of %qT "
+				  "from %qT differ in signedness", type,
+				  rhstype);
+		    break;
+		  case ic_return:
+		    pedwarn (location, OPT_Wpointer_sign, "pointer targets in "
+			     "returning %qT from a function with return type "
+			     "%qT differ in signedness", rhstype, type);
+		    break;
+		  default:
+		    gcc_unreachable ();
+		  }
 	    }
 	  else if (TREE_CODE (ttl) == FUNCTION_TYPE
 		   && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -6750,17 +6786,39 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 				        TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
 	    }
 	}
-      else
-	/* Avoid warning about the volatile ObjC EH puts on decls.  */
-	if (!objc_ok)
-	  PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
-			          OPT_Wincompatible_pointer_types,
-			          G_("passing argument %d of %qE from "
-				     "incompatible pointer type"),
-			          G_("assignment from incompatible pointer type"),
-			          G_("initialization from incompatible "
-				     "pointer type"),
-			          G_("return from incompatible pointer type"));
+      /* Avoid warning about the volatile ObjC EH puts on decls.  */
+      else if (!objc_ok)
+	{
+	  switch (errtype)
+	    {
+	    case ic_argpass:
+	      if (pedwarn (expr_loc, OPT_Wincompatible_pointer_types,
+			   "passing argument %d of %qE from incompatible "
+			   "pointer type", parmnum, rname))
+		inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+			? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+			"expected %qT but argument is of type %qT",
+			type, rhstype);
+	      break;
+	    case ic_assign:
+	      pedwarn (location, OPT_Wincompatible_pointer_types,
+		       "assignment to %qT from incompatible pointer type %qT",
+		       type, rhstype);
+	      break;
+	    case ic_init:
+	      pedwarn_init (location, OPT_Wincompatible_pointer_types,
+			    "initialization of %qT from incompatible pointer "
+			    "type %qT", type, rhstype);
+	      break;
+	    case ic_return:
+	      pedwarn (location, OPT_Wincompatible_pointer_types,
+		       "returning %qT from a function with incompatible "
+		       "return type %qT", rhstype, type);
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
 
       return convert (type, rhs);
     }
@@ -6777,31 +6835,70 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	 or one that results from arithmetic, even including
 	 a cast to integer type.  */
       if (!null_pointer_constant)
-	PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
-			        OPT_Wint_conversion,
-			        G_("passing argument %d of %qE makes "
-				   "pointer from integer without a cast"),
-			        G_("assignment makes pointer from integer "
-				   "without a cast"),
-			        G_("initialization makes pointer from "
-				   "integer without a cast"),
-			        G_("return makes pointer from integer "
-				   "without a cast"));
+	switch (errtype)
+	  {
+	  case ic_argpass:
+	    if (pedwarn (expr_loc, OPT_Wint_conversion,
+			 "passing argument %d of %qE makes pointer from "
+			 "integer without a cast", parmnum, rname))
+	      inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+		      ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+		      "expected %qT but argument is of type %qT",
+		      type, rhstype);
+	    break;
+	  case ic_assign:
+	    pedwarn (location, OPT_Wint_conversion,
+		     "assignment to %qT from %qT makes pointer from integer "
+		     "without a cast", type, rhstype);
+	    break;
+	  case ic_init:
+	    pedwarn_init (location, OPT_Wint_conversion,
+			  "initialization of %qT from %qT makes pointer from "
+			  "integer without a cast", type, rhstype);
+	    break;
+	  case ic_return:
+	    pedwarn (location, OPT_Wint_conversion, "returning %qT from a "
+		     "function with return type %qT makes pointer from "
+		     "integer without a cast", rhstype, type);
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
 
       return convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
     {
-      PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
-			      OPT_Wint_conversion,
-			      G_("passing argument %d of %qE makes integer "
-			         "from pointer without a cast"),
-			      G_("assignment makes integer from pointer "
-			         "without a cast"),
-			      G_("initialization makes integer from pointer "
-			         "without a cast"),
-			      G_("return makes integer from pointer "
-			         "without a cast"));
+      switch (errtype)
+	{
+	case ic_argpass:
+	  if (pedwarn (expr_loc, OPT_Wint_conversion,
+		       "passing argument %d of %qE makes integer from "
+		       "pointer without a cast", parmnum, rname))
+	    inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+		    ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+		    "expected %qT but argument is of type %qT",
+		    type, rhstype);
+	  break;
+	case ic_assign:
+	  pedwarn (location, OPT_Wint_conversion,
+		   "assignment to %qT from %qT makes integer from pointer "
+		   "without a cast", type, rhstype);
+	  break;
+	case ic_init:
+	  pedwarn_init (location, OPT_Wint_conversion,
+			"initialization of %qT from %qT makes integer from "
+			"pointer without a cast", type, rhstype);
+	  break;
+	case ic_return:
+	  pedwarn (location, OPT_Wint_conversion, "returning %qT from a "
+		   "function with return type %qT makes integer from "
+		   "pointer without a cast", rhstype, type);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+
       return convert (type, rhs);
     }
   else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
diff --git gcc/diagnostic-core.h gcc/diagnostic-core.h
index e9f7b6784da..1fa28027b5b 100644
--- gcc/diagnostic-core.h
+++ gcc/diagnostic-core.h
@@ -93,6 +93,8 @@  extern void inform_n (location_t, int, const char *, const char *, ...)
 extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern bool emit_diagnostic (diagnostic_t, location_t, int,
 			     const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
+extern bool emit_diagnostic_valist (diagnostic_t, location_t, int, const char *,
+				    va_list *) ATTRIBUTE_GCC_DIAG (4,0);
 extern bool seen_error (void);
 
 #ifdef BUFSIZ
diff --git gcc/diagnostic.c gcc/diagnostic.c
index bbf5f5ce7a6..a98bf4a3333 100644
--- gcc/diagnostic.c
+++ gcc/diagnostic.c
@@ -1128,6 +1128,8 @@  diagnostic_n_impl (location_t location, int opt, int n,
 				    singular_gmsgid, plural_gmsgid, ap, kind);
 }
 
+/* Wrapper around diagnostic_impl taking a variable argument list.  */
+
 bool
 emit_diagnostic (diagnostic_t kind, location_t location, int opt,
 		 const char *gmsgid, ...)
@@ -1140,6 +1142,16 @@  emit_diagnostic (diagnostic_t kind, location_t location, int opt,
   return ret;
 }
 
+/* Wrapper around diagnostic_impl taking a va_list parameter.  */
+
+bool
+emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
+			const char *gmsgid, va_list *ap)
+{
+  rich_location richloc (line_table, location);
+  return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
+}
+
 /* An informative note at LOCATION.  Use this for additional details on an error
    message.  */
 void
diff --git gcc/testsuite/gcc.dg/assign-warn-1.c gcc/testsuite/gcc.dg/assign-warn-1.c
index f26a5447ea0..365025724c4 100644
--- gcc/testsuite/gcc.dg/assign-warn-1.c
+++ gcc/testsuite/gcc.dg/assign-warn-1.c
@@ -50,63 +50,63 @@  TESTRET(dfe, void *, fp); /* { dg-warning "ISO C forbids return between function
 
 TESTARG(sua, int *, unsigned int *); /* { dg-warning "pointer targets in passing argument 1 of 'suaF' differ in signedness" } */
 TESTARP(sub, int *, unsigned int *); /* { dg-warning "pointer targets in passing argument 1 of 'subFp.x' differ in signedness" } */
-TESTASS(suc, int *, unsigned int *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(sud, int *, unsigned int *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(sue, int *, unsigned int *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(suc, int *, unsigned int *); /* { dg-warning "pointer targets in assignment from 'unsigned int \\*' to 'int \\*' differ in signedness" } */
+TESTINI(sud, int *, unsigned int *); /* { dg-warning "pointer targets in initialization of 'int \\*' from 'unsigned int \\*' differ in signedness" } */
+TESTRET(sue, int *, unsigned int *); /* { dg-warning "pointer targets in returning 'unsigned int \\*' from a function with return type 'int \\*' differ in signedness" } */
 
 TESTARG(usa, unsigned int *, int *); /* { dg-warning "pointer targets in passing argument 1 of 'usaF' differ in signedness" } */
 TESTARP(usb, unsigned int *, int *); /* { dg-warning "pointer targets in passing argument 1 of 'usbFp.x' differ in signedness" } */
-TESTASS(usc, unsigned int *, int *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(usd, unsigned int *, int *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(use, unsigned int *, int *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(usc, unsigned int *, int *); /* { dg-warning "pointer targets in assignment from 'int \\*' to 'unsigned int \\*' differ in signedness" } */
+TESTINI(usd, unsigned int *, int *); /* { dg-warning "pointer targets in initialization of 'unsigned int \\*' from 'int \\*' differ in signedness" } */
+TESTRET(use, unsigned int *, int *); /* { dg-warning "pointer targets in returning 'int \\*' from a function with return type 'unsigned int \\*' differ in signedness" } */
 
 TESTARG(cua, char *, unsigned char *); /* { dg-warning "pointer targets in passing argument 1 of 'cuaF' differ in signedness" } */
 TESTARP(cub, char *, unsigned char *); /* { dg-warning "pointer targets in passing argument 1 of 'cubFp.x' differ in signedness" } */
-TESTASS(cuc, char *, unsigned char *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(cud, char *, unsigned char *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(cue, char *, unsigned char *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(cuc, char *, unsigned char *); /* { dg-warning "pointer targets in assignment from 'unsigned char \\*' to 'char \\*' differ in signedness" } */
+TESTINI(cud, char *, unsigned char *); /* { dg-warning "pointer targets in initialization of 'char \\*' from 'unsigned char \\*' differ in signedness" } */
+TESTRET(cue, char *, unsigned char *); /* { dg-warning "pointer targets in returning 'unsigned char \\*' from a function with return type 'char \\*' differ in signedness" } */
 
 TESTARG(uca, unsigned char *, char *); /* { dg-warning "pointer targets in passing argument 1 of 'ucaF' differ in signedness" } */
 TESTARP(ucb, unsigned char *, char *); /* { dg-warning "pointer targets in passing argument 1 of 'ucbFp.x' differ in signedness" } */
-TESTASS(ucc, unsigned char *, char *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(ucd, unsigned char *, char *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(uce, unsigned char *, char *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(ucc, unsigned char *, char *); /* { dg-warning "pointer targets in assignment from 'char \\*' to 'unsigned char \\*' differ in signedness" } */
+TESTINI(ucd, unsigned char *, char *); /* { dg-warning "pointer targets in initialization of 'unsigned char \\*' from 'char \\*' differ in signedness" } */
+TESTRET(uce, unsigned char *, char *); /* { dg-warning "pointer targets in returning 'char \\*' from a function with return type 'unsigned char \\*' differ in signedness" } */
 
 TESTARG(csa, char *, signed char *); /* { dg-warning "pointer targets in passing argument 1 of 'csaF' differ in signedness" } */
 TESTARP(csb, char *, signed char *); /* { dg-warning "pointer targets in passing argument 1 of 'csbFp.x' differ in signedness" } */
-TESTASS(csc, char *, signed char *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(csd, char *, signed char *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(cse, char *, signed char *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(csc, char *, signed char *); /* { dg-warning "pointer targets in assignment from 'signed char \\*' to 'char \\*' differ in signedness" } */
+TESTINI(csd, char *, signed char *); /* { dg-warning "pointer targets in initialization of 'char \\*' from 'signed char \\*' differ in signedness" } */
+TESTRET(cse, char *, signed char *); /* { dg-warning "pointer targets in returning 'signed char \\*' from a function with return type 'char \\*' differ in signedness" } */
 
 TESTARG(sca, signed char *, char *); /* { dg-warning "pointer targets in passing argument 1 of 'scaF' differ in signedness" } */
 TESTARP(scb, signed char *, char *); /* { dg-warning "pointer targets in passing argument 1 of 'scbFp.x' differ in signedness" } */
-TESTASS(scc, signed char *, char *); /* { dg-warning "pointer targets in assignment differ in signedness" } */
-TESTINI(scd, signed char *, char *); /* { dg-warning "pointer targets in initialization differ in signedness" } */
-TESTRET(sce, signed char *, char *); /* { dg-warning "pointer targets in return differ in signedness" } */
+TESTASS(scc, signed char *, char *); /* { dg-warning "pointer targets in assignment from 'char \\*' to 'signed char \\*' differ in signedness" } */
+TESTINI(scd, signed char *, char *); /* { dg-warning "pointer targets in initialization of 'signed char \\*' from 'char \\*' differ in signedness" } */
+TESTRET(sce, signed char *, char *); /* { dg-warning "pointer targets in returning 'char \\*' from a function with return type 'signed char \\*' differ in signedness" } */
 
 TESTARG(cia, char *, int *); /* { dg-warning "passing argument 1 of 'ciaF' from incompatible pointer type" } */
 TESTARP(cib, char *, int *); /* { dg-warning "passing argument 1 of 'cibFp.x' from incompatible pointer type" } */
-TESTASS(cic, char *, int *); /* { dg-warning "assignment from incompatible pointer type" } */
-TESTINI(cid, char *, int *); /* { dg-warning "initialization from incompatible pointer type" } */
-TESTRET(cie, char *, int *); /* { dg-warning "return from incompatible pointer type" } */
+TESTASS(cic, char *, int *); /* { dg-warning "assignment to 'char \\*' from incompatible pointer type 'int \\*'" } */
+TESTINI(cid, char *, int *); /* { dg-warning "initialization of 'char \\*' from incompatible pointer type 'int \\*'" } */
+TESTRET(cie, char *, int *); /* { dg-warning "returning 'int \\*' from a function with incompatible return type 'char \\*'" } */
 
 TESTARG(ica, int *, char *); /* { dg-warning "passing argument 1 of 'icaF' from incompatible pointer type" } */
 TESTARP(icb, int *, char *); /* { dg-warning "passing argument 1 of 'icbFp.x' from incompatible pointer type" } */
-TESTASS(icc, int *, char *); /* { dg-warning "assignment from incompatible pointer type" } */
-TESTINI(icd, int *, char *); /* { dg-warning "initialization from incompatible pointer type" } */
-TESTRET(ice, int *, char *); /* { dg-warning "return from incompatible pointer type" } */
+TESTASS(icc, int *, char *); /* { dg-warning "assignment to 'int \\*' from incompatible pointer type 'char \\*'" } */
+TESTINI(icd, int *, char *); /* { dg-warning "initialization of 'int \\*' from incompatible pointer type 'char \\*'" } */
+TESTRET(ice, int *, char *); /* { dg-warning "returning 'char \\*' from a function with incompatible return type 'int \\*'" } */
 
 TESTARG(ciia, char *, int); /* { dg-warning "passing argument 1 of 'ciiaF' makes pointer from integer without a cast" } */
 TESTARP(ciib, char *, int); /* { dg-warning "passing argument 1 of 'ciibFp.x' makes pointer from integer without a cast" } */
-TESTASS(ciic, char *, int); /* { dg-warning "assignment makes pointer from integer without a cast" } */
-TESTINI(ciid, char *, int); /* { dg-warning "initialization makes pointer from integer without a cast" } */
-TESTRET(ciie, char *, int); /* { dg-warning "return makes pointer from integer without a cast" } */
+TESTASS(ciic, char *, int); /* { dg-warning "assignment to 'char \\*' from 'int' makes pointer from integer without a cast" } */
+TESTINI(ciid, char *, int); /* { dg-warning "initialization of 'char \\*' from 'int' makes pointer from integer without a cast" } */
+TESTRET(ciie, char *, int); /* { dg-warning "returning 'int' from a function with return type 'char \\*' makes pointer from integer without a cast" } */
 
 TESTARG(iica, int, char *); /* { dg-warning "passing argument 1 of 'iicaF' makes integer from pointer without a cast" } */
 TESTARP(iicb, int, char *); /* { dg-warning "passing argument 1 of 'iicbFp.x' makes integer from pointer without a cast" } */
-TESTASS(iicc, int, char *); /* { dg-warning "assignment makes integer from pointer without a cast" } */
-TESTINI(iicd, int, char *); /* { dg-warning "initialization makes integer from pointer without a cast" } */
-TESTRET(iice, int, char *); /* { dg-warning "return makes integer from pointer without a cast" } */
+TESTASS(iicc, int, char *); /* { dg-warning "assignment to 'int' from 'char \\*' makes integer from pointer without a cast" } */
+TESTINI(iicd, int, char *); /* { dg-warning "initialization of 'int' from 'char \\*' makes integer from pointer without a cast" } */
+TESTRET(iice, int, char *); /* { dg-warning "returning 'char \\*' from a function with return type 'int' makes integer from pointer without a cast" } */
 
 struct s { int a; };
 
diff --git gcc/testsuite/gcc.dg/assign-warn-2.c gcc/testsuite/gcc.dg/assign-warn-2.c
index 1e5eb1ca6e5..0c8a8ee7833 100644
--- gcc/testsuite/gcc.dg/assign-warn-2.c
+++ gcc/testsuite/gcc.dg/assign-warn-2.c
@@ -51,63 +51,63 @@  TESTRET(dfe, void *, fp); /* { dg-error "ISO C forbids return between function p
 
 TESTARG(sua, int *, unsigned int *); /* { dg-error "pointer targets in passing argument 1 of 'suaF' differ in signedness" } */
 TESTARP(sub, int *, unsigned int *); /* { dg-error "pointer targets in passing argument 1 of 'subFp.x' differ in signedness" } */
-TESTASS(suc, int *, unsigned int *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(sud, int *, unsigned int *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(sue, int *, unsigned int *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(suc, int *, unsigned int *); /* { dg-error "pointer targets in assignment from 'unsigned int \\*' to 'int \\*' differ in signedness" } */
+TESTINI(sud, int *, unsigned int *); /* { dg-error "pointer targets in initialization of 'int \\*' from 'unsigned int \\*' differ in signedness" } */
+TESTRET(sue, int *, unsigned int *); /* { dg-error "pointer targets in returning 'unsigned int \\*' from a function with return type 'int \\*' differ in signedness" } */
 
 TESTARG(usa, unsigned int *, int *); /* { dg-error "pointer targets in passing argument 1 of 'usaF' differ in signedness" } */
 TESTARP(usb, unsigned int *, int *); /* { dg-error "pointer targets in passing argument 1 of 'usbFp.x' differ in signedness" } */
-TESTASS(usc, unsigned int *, int *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(usd, unsigned int *, int *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(use, unsigned int *, int *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(usc, unsigned int *, int *); /* { dg-error "pointer targets in assignment from 'int \\*' to 'unsigned int \\*' differ in signedness" } */
+TESTINI(usd, unsigned int *, int *); /* { dg-error "pointer targets in initialization of 'unsigned int \\*' from 'int \\*' differ in signedness" } */
+TESTRET(use, unsigned int *, int *); /* { dg-error "pointer targets in returning 'int \\*' from a function with return type 'unsigned int \\*' differ in signedness" } */
 
 TESTARG(cua, char *, unsigned char *); /* { dg-error "pointer targets in passing argument 1 of 'cuaF' differ in signedness" } */
 TESTARP(cub, char *, unsigned char *); /* { dg-error "pointer targets in passing argument 1 of 'cubFp.x' differ in signedness" } */
-TESTASS(cuc, char *, unsigned char *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(cud, char *, unsigned char *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(cue, char *, unsigned char *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(cuc, char *, unsigned char *); /* { dg-error "pointer targets in assignment from 'unsigned char \\*' to 'char \\*' differ in signedness" } */
+TESTINI(cud, char *, unsigned char *); /* { dg-error "pointer targets in initialization of 'char \\*' from 'unsigned char \\*' differ in signedness" } */
+TESTRET(cue, char *, unsigned char *); /* { dg-error "pointer targets in returning 'unsigned char \\*' from a function with return type 'char \\*' differ in signedness" } */
 
 TESTARG(uca, unsigned char *, char *); /* { dg-error "pointer targets in passing argument 1 of 'ucaF' differ in signedness" } */
 TESTARP(ucb, unsigned char *, char *); /* { dg-error "pointer targets in passing argument 1 of 'ucbFp.x' differ in signedness" } */
-TESTASS(ucc, unsigned char *, char *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(ucd, unsigned char *, char *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(uce, unsigned char *, char *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(ucc, unsigned char *, char *); /* { dg-error "pointer targets in assignment from 'char \\*' to 'unsigned char \\*' differ in signedness" } */
+TESTINI(ucd, unsigned char *, char *); /* { dg-error "pointer targets in initialization of 'unsigned char \\*' from 'char \\*' differ in signedness" } */
+TESTRET(uce, unsigned char *, char *); /* { dg-error "pointer targets in returning 'char \\*' from a function with return type 'unsigned char \\*' differ in signedness" } */
 
 TESTARG(csa, char *, signed char *); /* { dg-error "pointer targets in passing argument 1 of 'csaF' differ in signedness" } */
 TESTARP(csb, char *, signed char *); /* { dg-error "pointer targets in passing argument 1 of 'csbFp.x' differ in signedness" } */
-TESTASS(csc, char *, signed char *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(csd, char *, signed char *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(cse, char *, signed char *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(csc, char *, signed char *); /* { dg-error "pointer targets in assignment from 'signed char \\*' to 'char \\*' differ in signedness" } */
+TESTINI(csd, char *, signed char *); /* { dg-error "pointer targets in initialization of 'char \\*' from 'signed char \\*' differ in signedness" } */
+TESTRET(cse, char *, signed char *); /* { dg-error "pointer targets in returning 'signed char \\*' from a function with return type 'char \\*' differ in signedness" } */
 
 TESTARG(sca, signed char *, char *); /* { dg-error "pointer targets in passing argument 1 of 'scaF' differ in signedness" } */
 TESTARP(scb, signed char *, char *); /* { dg-error "pointer targets in passing argument 1 of 'scbFp.x' differ in signedness" } */
-TESTASS(scc, signed char *, char *); /* { dg-error "pointer targets in assignment differ in signedness" } */
-TESTINI(scd, signed char *, char *); /* { dg-error "pointer targets in initialization differ in signedness" } */
-TESTRET(sce, signed char *, char *); /* { dg-error "pointer targets in return differ in signedness" } */
+TESTASS(scc, signed char *, char *); /* { dg-error "pointer targets in assignment from 'char \\*' to 'signed char \\*' differ in signedness" } */
+TESTINI(scd, signed char *, char *); /* { dg-error "pointer targets in initialization of 'signed char \\*' from 'char \\*' differ in signedness" } */
+TESTRET(sce, signed char *, char *); /* { dg-error "pointer targets in returning 'char \\*' from a function with return type 'signed char \\*' differ in signedness" } */
 
 TESTARG(cia, char *, int *); /* { dg-error "passing argument 1 of 'ciaF' from incompatible pointer type" } */
 TESTARP(cib, char *, int *); /* { dg-error "passing argument 1 of 'cibFp.x' from incompatible pointer type" } */
-TESTASS(cic, char *, int *); /* { dg-error "assignment from incompatible pointer type" } */
-TESTINI(cid, char *, int *); /* { dg-error "initialization from incompatible pointer type" } */
-TESTRET(cie, char *, int *); /* { dg-error "return from incompatible pointer type" } */
+TESTASS(cic, char *, int *); /* { dg-error "assignment to 'char \\*' from incompatible pointer type 'int \\*'" } */
+TESTINI(cid, char *, int *); /* { dg-error "initialization of 'char \\*' from incompatible pointer type 'int \\*'" } */
+TESTRET(cie, char *, int *); /* { dg-error "returning 'int \\*' from a function with incompatible return type 'char \\*'" } */
 
 TESTARG(ica, int *, char *); /* { dg-error "passing argument 1 of 'icaF' from incompatible pointer type" } */
 TESTARP(icb, int *, char *); /* { dg-error "passing argument 1 of 'icbFp.x' from incompatible pointer type" } */
-TESTASS(icc, int *, char *); /* { dg-error "assignment from incompatible pointer type" } */
-TESTINI(icd, int *, char *); /* { dg-error "initialization from incompatible pointer type" } */
-TESTRET(ice, int *, char *); /* { dg-error "return from incompatible pointer type" } */
+TESTASS(icc, int *, char *); /* { dg-error "assignment to 'int \\*' from incompatible pointer type 'char \\*'" } */
+TESTINI(icd, int *, char *); /* { dg-error "initialization of 'int \\*' from incompatible pointer type 'char \\*'" } */
+TESTRET(ice, int *, char *); /* { dg-error "returning 'char \\*' from a function with incompatible return type 'int \\*'" } */
 
 TESTARG(ciia, char *, int); /* { dg-error "passing argument 1 of 'ciiaF' makes pointer from integer without a cast" } */
 TESTARP(ciib, char *, int); /* { dg-error "passing argument 1 of 'ciibFp.x' makes pointer from integer without a cast" } */
-TESTASS(ciic, char *, int); /* { dg-error "assignment makes pointer from integer without a cast" } */
-TESTINI(ciid, char *, int); /* { dg-error "initialization makes pointer from integer without a cast" } */
-TESTRET(ciie, char *, int); /* { dg-error "return makes pointer from integer without a cast" } */
+TESTASS(ciic, char *, int); /* { dg-error "assignment to 'char \\*' from 'int' makes pointer from integer without a cast" } */
+TESTINI(ciid, char *, int); /* { dg-error "initialization of 'char \\*' from 'int' makes pointer from integer without a cast" } */
+TESTRET(ciie, char *, int); /* { dg-error "returning 'int' from a function with return type 'char \\*' makes pointer from integer without a cast" } */
 
 TESTARG(iica, int, char *); /* { dg-error "passing argument 1 of 'iicaF' makes integer from pointer without a cast" } */
 TESTARP(iicb, int, char *); /* { dg-error "passing argument 1 of 'iicbFp.x' makes integer from pointer without a cast" } */
-TESTASS(iicc, int, char *); /* { dg-error "assignment makes integer from pointer without a cast" } */
-TESTINI(iicd, int, char *); /* { dg-error "initialization makes integer from pointer without a cast" } */
-TESTRET(iice, int, char *); /* { dg-error "return makes integer from pointer without a cast" } */
+TESTASS(iicc, int, char *); /* { dg-error "assignment to 'int' from 'char \\*' makes integer from pointer without a cast" } */
+TESTINI(iicd, int, char *); /* { dg-error "initialization of 'int' from 'char \\*' makes integer from pointer without a cast" } */
+TESTRET(iice, int, char *); /* { dg-error "returning 'char \\*' from a function with return type 'int' makes integer from pointer without a cast" } */
 
 struct s { int a; };
 
diff --git gcc/testsuite/gcc.dg/c90-const-expr-5.c gcc/testsuite/gcc.dg/c90-const-expr-5.c
index 9f5cdef8399..e7422eb6020 100644
--- gcc/testsuite/gcc.dg/c90-const-expr-5.c
+++ gcc/testsuite/gcc.dg/c90-const-expr-5.c
@@ -15,8 +15,8 @@  f (void)
 {
   /* (V *)0 is a null pointer constant, so the assignment should be
      diagnosed.  */
-  q = (j ? p : (V *)0); /* { dg-error "5:assignment from incompatible pointer type" } */
-  q = (j ? p : (void *)0); /* { dg-error "5:assignment from incompatible pointer type" } */
+  q = (j ? p : (V *)0); /* { dg-error "5:assignment to 'long int \\*' from incompatible pointer type 'int \\*'" } */
+  q = (j ? p : (void *)0); /* { dg-error "5:assignment to 'long int \\*' from incompatible pointer type 'int \\*'" } */
   /* And this conversion should be valid.  */
   (void (*)(void))(V *)0;
   (void (*)(void))(void *)0;
diff --git gcc/testsuite/gcc.dg/c99-const-expr-5.c gcc/testsuite/gcc.dg/c99-const-expr-5.c
index 3bfa7f6fe27..693b97d018c 100644
--- gcc/testsuite/gcc.dg/c99-const-expr-5.c
+++ gcc/testsuite/gcc.dg/c99-const-expr-5.c
@@ -15,8 +15,8 @@  f (void)
 {
   /* (V *)0 is a null pointer constant, so the assignment should be
      diagnosed.  */
-  q = (j ? p : (V *)0); /* { dg-error "assignment from incompatible pointer type" } */
-  q = (j ? p : (void *)0); /* { dg-error "assignment from incompatible pointer type" } */
+  q = (j ? p : (V *)0); /* { dg-error "assignment to 'long int \\*' from incompatible pointer type 'int \\*'" } */
+  q = (j ? p : (void *)0); /* { dg-error "assignment to 'long int \\*' from incompatible pointer type 'int \\*'" } */
   /* And this conversion should be valid.  */
   (void (*)(void))(V *)0;
   (void (*)(void))(void *)0;
diff --git gcc/testsuite/gcc.dg/conv-2.c gcc/testsuite/gcc.dg/conv-2.c
index 388dee3d746..83468cdad1c 100644
--- gcc/testsuite/gcc.dg/conv-2.c
+++ gcc/testsuite/gcc.dg/conv-2.c
@@ -12,15 +12,15 @@  int main()
   unsigned char *ucp;
   signed char *scp;
 
-  ulp = lp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  lp = ulp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
+  ulp = lp;	/* { dg-warning " pointer targets in assignment from 'long int \\*' to 'long unsigned int \\*' differ in signedness" } */
+  lp = ulp;	/* { dg-warning " pointer targets in assignment from 'long unsigned int \\*' to 'long int \\*' differ in signedness" } */
   f1(ulp);	/* { dg-warning " differ in signedness" } */
   f2(lp);	/* { dg-warning " differ in signedness" } */
 
-  cp = ucp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  cp = scp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  ucp = scp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  ucp = cp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  scp = ucp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  scp = cp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
+  cp = ucp;	/* { dg-warning " pointer targets in assignment from 'unsigned char \\*' to 'char \\*' differ in signedness" } */
+  cp = scp;	/* { dg-warning " pointer targets in assignment from 'signed char \\*' to 'char \\*' differ in signedness" } */
+  ucp = scp;	/* { dg-warning " pointer targets in assignment from 'signed char \\*' to 'unsigned char \\*' differ in signedness" } */
+  ucp = cp;	/* { dg-warning " pointer targets in assignment from 'char \\*' to 'unsigned char \\*' differ in signedness" } */
+  scp = ucp;	/* { dg-warning " pointer targets in assignment from 'unsigned char \\*' to 'signed char \\*' differ in signedness" } */
+  scp = cp;	/* { dg-warning " pointer targets in assignment from 'char \\*' to 'signed char \\*' differ in signedness" } */
 }
diff --git gcc/testsuite/gcc.dg/diagnostic-types-1.c gcc/testsuite/gcc.dg/diagnostic-types-1.c
index e69de29bb2d..fc4b104df05 100644
--- gcc/testsuite/gcc.dg/diagnostic-types-1.c
+++ gcc/testsuite/gcc.dg/diagnostic-types-1.c
@@ -0,0 +1,57 @@ 
+/* PR c/81233 */
+/* { dg-do compile } */
+/* { dg-options "-Wc++-compat -Wpedantic" } */
+/* Test we're printing the types, like the good compiler we are.  */
+
+enum E1 { A } e;
+enum E2 { B };
+extern void foo_E (enum E1); /* { dg-message "expected 'enum E1' but argument is of type 'int'" } */
+extern void foo (char *); /* { dg-message "expected 'char \\*' but argument is of type 'int \\*'" } */
+extern void foo2 (int *); /* { dg-message "expected 'int \\*' but argument is of type 'int'" } */
+extern void foo3 (int); /* { dg-message "expected 'int' but argument is of type 'int \\*'" } */
+extern void foo4 (int *); /* { dg-message "expected 'int \\*' but argument is of type 'unsigned int \\*'" } */
+
+char *
+fn0 (int *p, char *q)
+{
+  p = q; /* { dg-warning "assignment to 'int \\*' from incompatible pointer type 'char \\*'" } */
+  int *r = q; /* { dg-warning "initialization of 'int \\*' from incompatible pointer type 'char \\*'" } */
+  foo (r); /* { dg-warning "passing argument 1 of 'foo' from incompatible pointer type" } */
+  return p; /* { dg-warning "returning 'int \\*' from a function with incompatible return type 'char \\*'" } */
+}
+
+int *
+fn1 (int *p)
+{
+  p = 1; /* { dg-warning "assignment to 'int \\*' from 'int' makes pointer from integer without a cast" } */
+  int *q = 1; /* { dg-warning "initialization of 'int \\*' from 'int' makes pointer from integer without a cast" } */
+  foo2 (1); /* { dg-warning "passing argument 1 of 'foo2' makes pointer from integer without a cast" } */
+  return 1; /* { dg-warning "returning 'int' from a function with return type 'int \\*' makes pointer from integer without a cast" } */
+}
+
+int
+fn2 (int i, int *p)
+{
+  i = p; /* { dg-warning "assignment to 'int' from 'int \\*' makes integer from pointer without a cast" } */
+  int j = p; /* { dg-warning "initialization of 'int' from 'int \\*' makes integer from pointer without a cast" } */
+  foo3 (p); /* { dg-warning "passing argument 1 of 'foo3' makes integer from pointer without a cast" } */
+  return p; /* { dg-warning "returning 'int \\*' from a function with return type 'int' makes integer from pointer without a cast" } */
+}
+
+int *
+fn3 (int *p, unsigned int *u)
+{
+  p = u; /* { dg-warning "pointer targets in assignment from 'unsigned int \\*' to 'int \\*' differ in signedness" } */
+  int *q = u; /* { dg-warning "pointer targets in initialization of 'int \\*' from 'unsigned int \\*' differ in signedness" } */
+  foo4 (u); /* { dg-warning "pointer targets in passing argument 1 of 'foo4' differ in signedness" } */
+  return u; /* { dg-warning "pointer targets in returning 'unsigned int \\*' from a function with return type 'int \\*' differ in signedness" } */
+}
+
+enum E1
+fn4 (void)
+{
+  foo_E (B); /* { dg-warning "enum conversion when passing argument" } */
+  e = 0; /* { dg-warning "enum conversion from 'int' to 'enum E1' in assignment is invalid" } */
+  enum E1 f = 0; /* { dg-warning "enum conversion from 'int' to 'enum E1' in initialization is invalid" } */
+  return 0; /* { dg-warning "enum conversion from 'int' to 'enum E1' in return is invalid" } */
+}
diff --git gcc/testsuite/gcc.dg/init-bad-7.c gcc/testsuite/gcc.dg/init-bad-7.c
index 738ed605060..de5e570978c 100644
--- gcc/testsuite/gcc.dg/init-bad-7.c
+++ gcc/testsuite/gcc.dg/init-bad-7.c
@@ -8,4 +8,4 @@  struct f
 };
 
 char b[10];
-struct f g = {b}; /* { dg-warning "initialization from incompatible pointer type|near initialization for" } */
+struct f g = {b}; /* { dg-warning "initialization of 'int \\*' from incompatible pointer type|near initialization for" } */
diff --git gcc/testsuite/gcc.dg/overflow-warn-1.c gcc/testsuite/gcc.dg/overflow-warn-1.c
index 8eb322579cf..bbab3988fff 100644
--- gcc/testsuite/gcc.dg/overflow-warn-1.c
+++ gcc/testsuite/gcc.dg/overflow-warn-1.c
@@ -47,10 +47,10 @@  static int sc = INT_MAX + 1; /* { dg-warning "25:integer overflow in expression"
    constants.  The third has the overflow in an unevaluated
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-1 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-1 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
 /* { dg-error "initializer element is not computable at load time" "constant" { target *-*-* } .-1 } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *r = (1 ? 0 : INT_MAX+1);
 
 void
diff --git gcc/testsuite/gcc.dg/overflow-warn-2.c gcc/testsuite/gcc.dg/overflow-warn-2.c
index f048d6dae2a..f1ceaa32304 100644
--- gcc/testsuite/gcc.dg/overflow-warn-2.c
+++ gcc/testsuite/gcc.dg/overflow-warn-2.c
@@ -47,10 +47,10 @@  static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
    constants.  The third has the overflow in an unevaluated
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-1 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-1 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
 /* { dg-error "initializer element is not computable at load time" "constant" { target *-*-* } .-1 } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *r = (1 ? 0 : INT_MAX+1);
 
 void
diff --git gcc/testsuite/gcc.dg/overflow-warn-3.c gcc/testsuite/gcc.dg/overflow-warn-3.c
index 664011e401d..92b03a440e4 100644
--- gcc/testsuite/gcc.dg/overflow-warn-3.c
+++ gcc/testsuite/gcc.dg/overflow-warn-3.c
@@ -53,10 +53,10 @@  static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
 /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } .-1 } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
 /* { dg-error "initializer element is not computable at load time" "constant" { target *-*-* } .-1 } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-warning "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *r = (1 ? 0 : INT_MAX+1);
 
 void
diff --git gcc/testsuite/gcc.dg/overflow-warn-4.c gcc/testsuite/gcc.dg/overflow-warn-4.c
index 52677ce897a..dc09816da64 100644
--- gcc/testsuite/gcc.dg/overflow-warn-4.c
+++ gcc/testsuite/gcc.dg/overflow-warn-4.c
@@ -53,10 +53,10 @@  static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
 /* { dg-error "overflow in constant expression" "constant" { target *-*-* } .-1 } */
-/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-error "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
 /* { dg-error "initializer element is not computable at load time" "constant" { target *-*-* } .-1 } */
-/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
+/* { dg-error "initialization of 'void \\*' from 'int' makes pointer from integer without a cast" "null" { target *-*-* } .-2 } */
 void *r = (1 ? 0 : INT_MAX+1);
 
 void
diff --git gcc/testsuite/gcc.dg/pointer-array-atomic.c gcc/testsuite/gcc.dg/pointer-array-atomic.c
index 55b58e84e35..bb63797b237 100644
--- gcc/testsuite/gcc.dg/pointer-array-atomic.c
+++ gcc/testsuite/gcc.dg/pointer-array-atomic.c
@@ -6,8 +6,8 @@  void transpose0(double* out, _Atomic double* in) { }
 void transpose1(double out[2][2], _Atomic double in[2][2]) { }
 void transpose2(double out[2][2][2], _Atomic double in[2][2][2]) { }
 // return
-int (*x2(_Atomic int x[3][3]))[3] { return x; } /* { dg-warning "return from incompatible pointer type" } */
-_Atomic int (*x3(int x[3][3]))[3] { return x; } /* { dg-warning "return from incompatible pointer type" } */
+int (*x2(_Atomic int x[3][3]))[3] { return x; } /* { dg-warning "returning '_Atomic int \\(\\*\\)\\\[3\\\]' from a function with incompatible return type" } */
+_Atomic int (*x3(int x[3][3]))[3] { return x; } /* { dg-warning "returning 'int \\(\\*\\)\\\[3\\\]' from a function with incompatible return type" } */
 void test(void)
 {
 	double x0[2];
@@ -31,13 +31,13 @@  void test(void)
 	transpose2(y2, o2); /* { dg-warning "passing argument 2 of 'transpose2' from incompatible pointer type" } */
 	transpose2(y2, x2); /* { dg-warning "passing argument 2 of 'transpose2' from incompatible pointer type" } */
 	// initialization
-	_Atomic double (*x0p) = x0; /* { dg-warning "initialization from incompatible pointer type" } */
-	_Atomic double (*x1p)[2] = x1; /* { dg-warning "initialization from incompatible pointer type" } */
-	_Atomic double (*x2p)[2][2] = x2; /* { dg-warning "initialization from incompatible pointer type" } */
+	_Atomic double (*x0p) = x0; /* { dg-warning "initialization of '_Atomic double \\*' from incompatible pointer type" } */
+	_Atomic double (*x1p)[2] = x1; /* { dg-warning "initialization of '_Atomic double \\(\\*\\)\\\[2\\\]' from incompatible pointer type" } */
+	_Atomic double (*x2p)[2][2] = x2; /* { dg-warning "initialization of '_Atomic double \\(\\*\\)\\\[2\\\]\\\[2\\\]' from incompatible pointer type" } */
 	// assignment
-	x0p = x0; /* { dg-warning "assignment from incompatible pointer type" } */
-	x1p = x1; /* { dg-warning "assignment from incompatible pointer type" } */
-	x2p = x2; /* { dg-warning "assignment from incompatible pointer type" } */
+	x0p = x0; /* { dg-warning "assignment to '_Atomic double \\*' from incompatible pointer type" } */
+	x1p = x1; /* { dg-warning "assignment to '_Atomic double \\(\\*\\)\\\[2\\\]' from incompatible pointer type" } */
+	x2p = x2; /* { dg-warning "assignment to '_Atomic double \\(\\*\\)\\\[2\\\]\\\[2\\\]' from incompatible pointer type" } */
 	// subtraction
 	&(x0[1]) - &(z0[0]); /* { dg-error "invalid operands to binary" } */
 	&(x1[1]) - &(z1[0]); /* { dg-error "invalid operands to binary" } */
diff --git gcc/testsuite/gcc.dg/pr26865.c gcc/testsuite/gcc.dg/pr26865.c
index d9f1fe0d3a1..f49d1d29f9c 100644
--- gcc/testsuite/gcc.dg/pr26865.c
+++ gcc/testsuite/gcc.dg/pr26865.c
@@ -4,5 +4,5 @@ 
 void
 foo (void)
 {
-  char *e = alloca (100); /* { dg-warning "implicit declaration|initialization makes" } */
+  char *e = alloca (100); /* { dg-warning "implicit declaration|initialization of 'char \\*' from 'int' makes" } */
 }
diff --git gcc/testsuite/gcc.dg/pr61162-2.c gcc/testsuite/gcc.dg/pr61162-2.c
index 1045408d736..4aa8493d1a3 100644
--- gcc/testsuite/gcc.dg/pr61162-2.c
+++ gcc/testsuite/gcc.dg/pr61162-2.c
@@ -8,7 +8,7 @@  struct s { int a; };
 enum e
 fn1 (void)
 {
-  return 0; /* { dg-warning "10:enum conversion in return" } */
+  return 0; /* { dg-warning "10:enum conversion from 'int' to 'enum e' in return" } */
 }
 
 int
@@ -26,19 +26,19 @@  fn3 (void)
 int
 fn4 (int *a)
 {
-  return a; /* { dg-warning "10:return makes integer from pointer without a cast" } */
+  return a; /* { dg-warning "10:returning 'int \\*' from a function with return type 'int' makes integer from pointer without a cast" } */
 }
 
 int *
 fn5 (int a)
 {
-  return a; /* { dg-warning "10:return makes pointer from integer without a cast" } */
+  return a; /* { dg-warning "10:returning 'int' from a function with return type 'int \\*' makes pointer from integer without a cast" } */
 }
 
 unsigned int *
 fn6 (int *i)
 {
-  return i; /* { dg-warning "10:pointer targets in return differ" } */
+  return i; /* { dg-warning "10:pointer targets in returning 'int \\*' from a function with return type 'unsigned int \\*' differ" } */
 }
 
 void *
diff --git gcc/testsuite/gcc.dg/pr61162.c gcc/testsuite/gcc.dg/pr61162.c
index 8dcb0c8ed40..7ed0741e6c0 100644
--- gcc/testsuite/gcc.dg/pr61162.c
+++ gcc/testsuite/gcc.dg/pr61162.c
@@ -6,7 +6,7 @@  enum e { A };
 enum e
 fn1 (void)
 {
-  enum e e, q = 0; /* { dg-warning "17:enum conversion in initialization is invalid" } */
-  e = 0; /* { dg-warning "5:enum conversion in assignment is invalid" } */
-  1; return 0; /* { dg-warning "13:enum conversion in return is invalid" } */
+  enum e e, q = 0; /* { dg-warning "17:enum conversion from 'int' to 'enum e' in initialization is invalid" } */
+  e = 0; /* { dg-warning "5:enum conversion from 'int' to 'enum e' in assignment is invalid" } */
+  1; return 0; /* { dg-warning "13:enum conversion from 'int' to 'enum e' in return is invalid" } */
 }
diff --git gcc/testsuite/gcc.dg/pr67730-2.c gcc/testsuite/gcc.dg/pr67730-2.c
index 29d726754bf..260cc3e3821 100644
--- gcc/testsuite/gcc.dg/pr67730-2.c
+++ gcc/testsuite/gcc.dg/pr67730-2.c
@@ -9,14 +9,14 @@  extern void bar (int);
 int
 fn1 (void)
 {
-  int a = NULL; /* { dg-warning "initialization makes integer from pointer" } */
-  a = NULL; /* { dg-warning "assignment makes integer from pointer" } */
+  int a = NULL; /* { dg-warning "initialization of 'int' from 'void \\*' makes integer from pointer" } */
+  a = NULL; /* { dg-warning "assignment to 'int' from 'void \\*' makes integer from pointer" } */
   bar (NULL); /* { dg-warning "passing argument 1" } */
-  return NULL; /* { dg-warning "return makes integer from pointer" } */
+  return NULL; /* { dg-warning "returning 'void \\*' from a function with return type 'int' makes integer from pointer" } */
 }
 
 int
 fn2 (void)
 {
-  RETURN; /* { dg-warning "return makes integer from pointer" } */
+  RETURN; /* { dg-warning "returning 'void \\*' from a function with return type 'int' makes integer from pointer" } */
 }
diff --git gcc/testsuite/gcc.dg/pr69156.c gcc/testsuite/gcc.dg/pr69156.c
index b22aaec4706..1addfa3f6aa 100644
--- gcc/testsuite/gcc.dg/pr69156.c
+++ gcc/testsuite/gcc.dg/pr69156.c
@@ -5,6 +5,6 @@ 
 _Bool
 foo ()
 {
-  _Bool (*f) () = __builtin_abs;	/* { dg-warning "initialization from incompatible pointer type" } */
+  _Bool (*f) () = __builtin_abs;	/* { dg-warning "initialization of '_Bool \\(\\*\\)\\(\\)' from incompatible pointer type" } */
   return f (0);
 }
diff --git gcc/testsuite/gcc.dg/pr70174.c gcc/testsuite/gcc.dg/pr70174.c
index 8a3bc904fad..59d231e1623 100644
--- gcc/testsuite/gcc.dg/pr70174.c
+++ gcc/testsuite/gcc.dg/pr70174.c
@@ -7,5 +7,5 @@  struct S { int f : 4; } a;
 void
 foo (void)
 { 
-  a.f = foo;	/* { dg-warning "assignment makes integer from pointer without a cast" } */
+  a.f = foo;	/* { dg-warning "assignment to 'signed char:4' from 'void \\(\\*\\)\\(void\\)' makes integer from pointer without a cast" } */
 }
diff --git gcc/testsuite/objc.dg/proto-lossage-4.m gcc/testsuite/objc.dg/proto-lossage-4.m
index e72328b3703..4c6b560bab4 100644
--- gcc/testsuite/objc.dg/proto-lossage-4.m
+++ gcc/testsuite/objc.dg/proto-lossage-4.m
@@ -28,13 +28,13 @@  long foo(void) {
   receiver += [receiver anotherValue]; /* { dg-warning "invalid receiver type .intptr_t." } */
 
   receiver += [(Obj *)receiver someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
-/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
+/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
 
   receiver += [(Obj *)receiver anotherValue];
   receiver += [(Obj <Proto> *)receiver someValue];
   receiver += [(Obj <Proto> *)receiver anotherValue];
   receiver += [objrcvr someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
-/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
+/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
 
   receiver += [objrcvr anotherValue];
   receiver += [(Obj <Proto> *)objrcvr someValue];
@@ -42,7 +42,7 @@  long foo(void) {
   receiver += [objrcvr2 someValue];
   receiver += [objrcvr2 anotherValue];
   receiver += [(Obj *)objrcvr2 someValue]; /* { dg-warning ".Obj. may not respond to .\\-someValue." } */
-/* { dg-warning "assignment makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
+/* { dg-warning "assignment to 'intptr_t {aka long int}' from 'id' makes integer from pointer without a cast" "" { target *-*-* } .-1 } */
 
   receiver += [(Obj *)objrcvr2 anotherValue];