diff mbox

C PATCH to rectify warning for character types (PR c/23087)

Message ID 20160107171127.GK31604@redhat.com
State New
Headers show

Commit Message

Marek Polacek Jan. 7, 2016, 5:11 p.m. UTC
This PR points out that we issue a wrong warning message when assigning
two pointers when one of them is plain char.  In that case, the compiler
currently says that pointer targets differ in signedness.  But that is
not correct; char is a separate type from (un)signed char and is not
compatible with either.  So we should instead say that the pointer types
are not compatible.

This effectively means that I'm turning a -Wpointer-sign warning into
a -Wincompatible-pointer-types warning.  But -Wincompatible-pointer-types
is a warning that is enabled by default and -Wpointer-sign is enabled by
-Wpedantic || -Wall.  So with this, we'd be more verbose and would warn
by default on e.g. "unsigned char *p = "foo";."  Not sure if that is
desirable at this stage, so I'm leaning towards pushing this patch for
GCC7.

I've fixed various fallout, but on x86_64 only so far; the ppc64le machine
on the compile farm is currently unusable.

Bootstrapped/regtested on x86_64-linux.

2016-01-07  Marek Polacek  <polacek@redhat.com>

	PR c/23087
	* c-typeck.c (convert_for_assignment): Don't consider char and
	(un)signed char as compatible types.

	* gcc.dg/Wno-pointer-sign.c: Change dg-bogus to dg-warning and adjust
	the message.
	* gcc.dg/assign-warn-1.c: Adjust dg-warnings.
	* gcc.dg/assign-warn-2.c: Adjust dg-errors.
	* gcc.dg/conv-2.c: Adjust dg-warnings.
	* gcc.dg/pr23087.c: New test.
	* gcc.dg/pr28726.c: Add dg-warning.
	* gcc.dg/torture/pr64853.c: Likewise.
	* gcc.dg/torture/pr49603.c: Use unsigned char instead of char.
	* gcc.target/i386/avx2-mpsadbw-2.c: Likewise.
	* gcc.target/i386/avx2-vpaddusb-2.c: Add cast to avoid warning.
	* gcc.target/i386/avx2-vpavgb-2.c: Likewise.
	* gcc.target/i386/avx2-vpmaxub-2.c: Likewise.
	* gcc.target/i386/avx2-vpminub-2.c: Likewise.
	* gcc.target/i386/avx2-vpmovzxbd-2.c: Likewise.
	* gcc.target/i386/avx2-vpmovzxbq-2.c: Likewise.
	* gcc.target/i386/avx2-vpmovzxbw-2.c: Likewise.
	* gcc.target/i386/avx2-vpsadbw-2.c: Likewise.
	* gcc.target/i386/avx2-vpsubusb-2.c: Likewise.
	* gcc.target/i386/avx512f-vpmovusdb-2.c: Likewise.


	Marek

Comments

Joseph Myers Jan. 7, 2016, 9:19 p.m. UTC | #1
On Thu, 7 Jan 2016, Marek Polacek wrote:

> This PR points out that we issue a wrong warning message when assigning
> two pointers when one of them is plain char.  In that case, the compiler
> currently says that pointer targets differ in signedness.  But that is
> not correct; char is a separate type from (un)signed char and is not
> compatible with either.  So we should instead say that the pointer types
> are not compatible.
> 
> This effectively means that I'm turning a -Wpointer-sign warning into
> a -Wincompatible-pointer-types warning.  But -Wincompatible-pointer-types
> is a warning that is enabled by default and -Wpointer-sign is enabled by
> -Wpedantic || -Wall.  So with this, we'd be more verbose and would warn
> by default on e.g. "unsigned char *p = "foo";."  Not sure if that is
> desirable at this stage, so I'm leaning towards pushing this patch for
> GCC7.

I don't think it's desirable to raise the warning for this case under 
different conditions from the warning for other signedness cases.  The 
targets do differ in signedness - it's just that the difference is between 
"plain" and "signed" or "plain" and "unsigned", not between signed and 
unsigned.  Maybe the warning message should be more specific in this case, 
but not a less-specific "incompatible" which is what this patch would 
achieve.
Martin Sebor Jan. 8, 2016, 5:49 p.m. UTC | #2
On 01/07/2016 02:19 PM, Joseph Myers wrote:
> On Thu, 7 Jan 2016, Marek Polacek wrote:
>
>> This PR points out that we issue a wrong warning message when assigning
>> two pointers when one of them is plain char.  In that case, the compiler
>> currently says that pointer targets differ in signedness.  But that is
>> not correct; char is a separate type from (un)signed char and is not
>> compatible with either.  So we should instead say that the pointer types
>> are not compatible.
>>
>> This effectively means that I'm turning a -Wpointer-sign warning into
>> a -Wincompatible-pointer-types warning.  But -Wincompatible-pointer-types
>> is a warning that is enabled by default and -Wpointer-sign is enabled by
>> -Wpedantic || -Wall.  So with this, we'd be more verbose and would warn
>> by default on e.g. "unsigned char *p = "foo";."  Not sure if that is
>> desirable at this stage, so I'm leaning towards pushing this patch for
>> GCC7.
>
> I don't think it's desirable to raise the warning for this case under
> different conditions from the warning for other signedness cases.  The
> targets do differ in signedness - it's just that the difference is between
> "plain" and "signed" or "plain" and "unsigned", not between signed and
> unsigned.

I'm sorry Joseph but I don't quite follow this argument.  Plain
char is neither a signed [integer] type nor an unsigned [integer]
type, so it can never differ in signedness from any other type.

It seems to me that by the interpretation you suggest, converting
a signed int* to unsigned long* should be controlled by -Wpointer-
sign when int and long have the same representation, and by
-Wincompatible-pointer-types otherwise.  (Which is not what GCC
does.)

In my view, Marek's change makes perfect sense because it the most
closely reflects the properties of the type.

Martin
Bernd Schmidt Jan. 8, 2016, 5:54 p.m. UTC | #3
On 01/07/2016 10:19 PM, Joseph Myers wrote:

> I don't think it's desirable to raise the warning for this case under
> different conditions from the warning for other signedness cases.  The
> targets do differ in signedness - it's just that the difference is between
> "plain" and "signed" or "plain" and "unsigned", not between signed and
> unsigned.  Maybe the warning message should be more specific in this case,
> but not a less-specific "incompatible" which is what this patch would
> achieve.

I was going to voice the same opinion yesterday but forgot to hit Send. 
If you consider signedness of char a tri-state, then there's nothing 
wrong with the warning message.


Bernd
Marek Polacek Jan. 8, 2016, 6:07 p.m. UTC | #4
On Fri, Jan 08, 2016 at 06:54:32PM +0100, Bernd Schmidt wrote:
> On 01/07/2016 10:19 PM, Joseph Myers wrote:
> 
> >I don't think it's desirable to raise the warning for this case under
> >different conditions from the warning for other signedness cases.  The
> >targets do differ in signedness - it's just that the difference is between
> >"plain" and "signed" or "plain" and "unsigned", not between signed and
> >unsigned.  Maybe the warning message should be more specific in this case,
> >but not a less-specific "incompatible" which is what this patch would
> >achieve.
> 
> I was going to voice the same opinion yesterday but forgot to hit Send. If
> you consider signedness of char a tri-state, then there's nothing wrong with
> the warning message.

Well, it's been discussed at length in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=23087
It seems sort of weird to me to say that 'char' and 'signed char' do differ in
signedness when I know that my machine uses signed chars by default.  But I'm
wary of raising the warning -- it's likely to cause more uproar.  At this point
I don't know if I actually want to pursue this further, likely not.  Yet I'd
like to resolve this very old PR one way or another.

	Marek
Joseph Myers Jan. 8, 2016, 10:27 p.m. UTC | #5
On Fri, 8 Jan 2016, Martin Sebor wrote:

> > I don't think it's desirable to raise the warning for this case under
> > different conditions from the warning for other signedness cases.  The
> > targets do differ in signedness - it's just that the difference is between
> > "plain" and "signed" or "plain" and "unsigned", not between signed and
> > unsigned.
> 
> I'm sorry Joseph but I don't quite follow this argument.  Plain
> char is neither a signed [integer] type nor an unsigned [integer]
> type, so it can never differ in signedness from any other type.

Signedness of char (and of bit-fields) is a tristate, "signed", "unsigned" 
and "".  My claim is that a difference between any two of those three 
values is essentially the same kind of difference.  And so at most the 
wording should be adjusted (or maybe an inform ("%<char%> and %<signed 
char%> are different types" added), not the conditions for some such 
warning to be given.

> It seems to me that by the interpretation you suggest, converting
> a signed int* to unsigned long* should be controlled by -Wpointer-
> sign when int and long have the same representation, and by
> -Wincompatible-pointer-types otherwise.  (Which is not what GCC
> does.)

No, because those differ between "int" and "long", not between "signed" 
and "" or "unsigned" and "" as signedness.
Martin Sebor Jan. 8, 2016, 11:28 p.m. UTC | #6
> Signedness of char (and of bit-fields) is a tristate, "signed", "unsigned"
> and "".  My claim is that a difference between any two of those three
> values is essentially the same kind of difference.  And so at most the
> wording should be adjusted (or maybe an inform ("%<char%> and %<signed
> char%> are different types" added), not the conditions for some such
> warning to be given.

This explanation isn't grounded in the C definition of the types
(which is fine if you want to use some other definition of
"signedness").

In C, plain char type is neither a signed nor an unsigned integer
type, whether or not it has a sign bit.  It's a distinct type that's
incompatible with both signed char and unsigned char, and pointers
to the three types are incompatible with one another.

The only thing char, signed char, and unsigned char have in common
other than the word "char" is that they are classified as "character
types."  (Plain "char" might as well be called "character.")

>> It seems to me that by the interpretation you suggest, converting
>> a signed int* to unsigned long* should be controlled by -Wpointer-
>> sign when int and long have the same representation, and by
>> -Wincompatible-pointer-types otherwise.  (Which is not what GCC
>> does.)
>
> No, because those differ between "int" and "long", not between "signed"
> and "" or "unsigned" and "" as signedness.

int and long differ because they're not compatible according
to the C definition of the term, even if they have the same
size, representation, and alignment (e.g., in ILP32).

"char" and "signed char" are also incompatible, even if they
otherwise have identical properties, for the same reason (i.e.,
because the standard says they're not).

I believe the answer here hinges on the definition of the term
"signedness."  If we use the same definition as the standard,
the text of the warning is strictly speaking incorrect, and
the proposed change makes it correct.

If we define signedness differently, say as "having a sign bit,"
then the warning is appropriate in one of the two cases in the
bug but not in the other.  Which one depends on the the setting
of -fsigned-char:

   signed char   *ps = "signed";    // okay with -fsigned-char
   unsigned char *pu = "unsigned";  // okay with -fno-signed-char

and ditto for:

   extern char *p;

   ps = p;   // okay with -fsigned-char
   pu = p;   // okay with -fno-signed-char

However, this definition of signedness would imply that the
warning should not be issued for the code below (for example)
when int and long have the same size, representation, and
alignment:

   int *p = (long*)0;

Perhaps there is another definition according to which the text
of the warning would be correct in all cases.  If there is one,
it should be outlined in the documentation.  (I would recommend
using the standard definition since that's what most users are
either already familiar with or can easily look it up.)

Martin
Joseph Myers Jan. 8, 2016, 11:51 p.m. UTC | #7
On Fri, 8 Jan 2016, Martin Sebor wrote:

> > Signedness of char (and of bit-fields) is a tristate, "signed", "unsigned"
> > and "".  My claim is that a difference between any two of those three
> > values is essentially the same kind of difference.  And so at most the
> > wording should be adjusted (or maybe an inform ("%<char%> and %<signed
> > char%> are different types" added), not the conditions for some such
> > warning to be given.
> 
> This explanation isn't grounded in the C definition of the types
> (which is fine if you want to use some other definition of
> "signedness").
> 
> In C, plain char type is neither a signed nor an unsigned integer
> type, whether or not it has a sign bit.  It's a distinct type that's

Exactly.  "signed type", "unsigned type" and "type that is neither signed 
nor unsigned" are the three cases in the tristate.  ("type that is both 
signed and unsigned" doesn't exist.)

The point of this warning is that there are certain cases of incompatible 
types that are less serious than others - namely, those where the only 
aspect of the type that is different is its signedness.  Those get a more 
specific warning, which is given under more restrictive conditions.

ISO C specifically envisages such differences as being less serious when 
it allows variation between pointers to character types and void when 
passing arguments to unprototyped functions.

> However, this definition of signedness would imply that the
> warning should not be issued for the code below (for example)
> when int and long have the same size, representation, and
> alignment:
> 
>   int *p = (long*)0;

And of course the signedness warning isn't issued - the other generic 
warning about incompatible types is issued, because this is one of the 
more serious cases of incompatibility, where there is a difference other 
than signedness.
Martin Sebor Jan. 9, 2016, 1:21 a.m. UTC | #8
> The point of this warning is that there are certain cases of incompatible
> types that are less serious than others - namely, those where the only
> aspect of the type that is different is its signedness.  Those get a more
> specific warning, which is given under more restrictive conditions.

I see.  It means the warnings aren't based on the C definitions
of signedness or compatibility but rather on our perception of
the likely correctness of the code we've seen violate the
constraints implied by the definitions.

FWIW, I have no objection to treating the three character types
as special as you suggest.  But I also feel that -Wincompatible-
pointer-types is more appropriate than -Wpointer-sign, not only
for the reason stated in the bug but also because it more closely
corresponds to the C definitions of the terms.  Perhaps tweaking
the patch by adding an option, say -Wincompatible-char, to make
it possible to enable and disable the warning for the character
types, would be an acceptable compromise.  It would satisfy
the user's request and avoid the potential fallout you and Marek
are concerned about.

Martin
Martin Sebor Jan. 11, 2016, 4:37 p.m. UTC | #9
On 01/08/2016 06:21 PM, Martin Sebor wrote:
>> The point of this warning is that there are certain cases of incompatible
>> types that are less serious than others - namely, those where the only
>> aspect of the type that is different is its signedness.  Those get a more
>> specific warning, which is given under more restrictive conditions.

FWIW, below is a survey of a few popular compilers I have access
to and how they treat the problem and under what option.  The C
code I used to test is:

     void foo (char *p, signed char *q) { q = p; }

Clang (controlled by -Wpointer-sign, enabled by default):

warning: assigning to 'signed char *' from 'char *' converts
          between pointers to integer types with different sign
          [-Wpointer-sign]

EDG eccp (warns by default):
warning: a value of type "char *" cannot be assigned to an
           entity of type "signed char *"

Intel ICC (requires -Wpointer-sign):

warning #556: a value of type "char *" cannot be assigned to
               an entity of type "signed char *"

Oracle CC (warns by default):
warning: assignment type mismatch:
  	pointer to signed char "=" pointer to char

IBM XLC (warns by default):
1506-068 (W) Operation between types "signed char*" and "char*"
              is not allowed.

Visual C (rejects code by default):
error C2440: '=': cannot convert from 'char *' to 'signed char *'
note: Types pointed to are unrelated;

Martin
diff mbox

Patch

diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 952041b..36001d2 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -6434,7 +6434,11 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	       == c_common_unsigned_type (mvr))
 	      && (c_common_signed_type (mvl)
 		  == c_common_signed_type (mvr))
-	      && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)))
+	      && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)
+	      /* char is a separate type and not compatible with signed char
+		 or unsigned char.  */
+	      && mvl != char_type_node
+	      && mvr != char_type_node))
 	{
 	  /* Warn about loss of qualifers from pointers to arrays with
 	     qualifiers on the element type. */
diff --git gcc/testsuite/gcc.dg/Wno-pointer-sign.c gcc/testsuite/gcc.dg/Wno-pointer-sign.c
index 780c9d4..c9f02a4 100644
--- gcc/testsuite/gcc.dg/Wno-pointer-sign.c
+++ gcc/testsuite/gcc.dg/Wno-pointer-sign.c
@@ -17,10 +17,10 @@  int main()
   f1(ulp);	/* { dg-bogus " differ in signedness" } */
   f2(lp);	/* { dg-bogus " differ in signedness" } */
 
-  cp = ucp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
-  cp = scp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
+  cp = ucp;	/* { dg-warning "assignment from incompatible pointer type" } */
+  cp = scp;	/* { dg-warning "assignment from incompatible pointer type" } */
   ucp = scp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
-  ucp = cp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
+  ucp = cp;	/* { dg-warning "assignment from incompatible pointer type" } */
   scp = ucp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
-  scp = cp;	/* { dg-bogus " pointer targets in assignment differ in signedness" } */
+  scp = cp;	/* { dg-warning "assignment from incompatible pointer type" } */
 }
diff --git gcc/testsuite/gcc.dg/assign-warn-1.c gcc/testsuite/gcc.dg/assign-warn-1.c
index f26a544..ce540cb 100644
--- gcc/testsuite/gcc.dg/assign-warn-1.c
+++ gcc/testsuite/gcc.dg/assign-warn-1.c
@@ -60,29 +60,29 @@  TESTASS(usc, unsigned int *, int *); /* { dg-warning "pointer targets in assignm
 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" } */
 
-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" } */
-
-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" } */
-
-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" } */
-
-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" } */
+TESTARG(cua, char *, unsigned char *); /* { dg-warning "passing argument 1 of 'cuaF' from incompatible pointer type" } */
+TESTARP(cub, char *, unsigned char *); /* { dg-warning "passing argument 1 of 'cubFp.x' from incompatible pointer type" } */
+TESTASS(cuc, char *, unsigned char *); /* { dg-warning "assignment from incompatible pointer type" } */
+TESTINI(cud, char *, unsigned char *); /* { dg-warning "initialization from incompatible pointer type" } */
+TESTRET(cue, char *, unsigned char *); /* { dg-warning "return from incompatible pointer type" } */
+
+TESTARG(uca, unsigned char *, char *); /* { dg-warning "passing argument 1 of 'ucaF' from incompatible pointer type" } */
+TESTARP(ucb, unsigned char *, char *); /* { dg-warning "passing argument 1 of 'ucbFp.x' from incompatible pointer type" } */
+TESTASS(ucc, unsigned char *, char *); /* { dg-warning "assignment from incompatible pointer type" } */
+TESTINI(ucd, unsigned char *, char *); /* { dg-warning "initialization from incompatible pointer type" } */
+TESTRET(uce, unsigned char *, char *); /* { dg-warning "return from incompatible pointer type" } */
+
+TESTARG(csa, char *, signed char *); /* { dg-warning "passing argument 1 of 'csaF' from incompatible pointer type" } */
+TESTARP(csb, char *, signed char *); /* { dg-warning "passing argument 1 of 'csbFp.x' from incompatible pointer type" } */
+TESTASS(csc, char *, signed char *); /* { dg-warning "assignment from incompatible pointer type" } */
+TESTINI(csd, char *, signed char *); /* { dg-warning "initialization from incompatible pointer type" } */
+TESTRET(cse, char *, signed char *); /* { dg-warning "return from incompatible pointer type" } */
+
+TESTARG(sca, signed char *, char *); /* { dg-warning "passing argument 1 of 'scaF' from incompatible pointer type" } */
+TESTARP(scb, signed char *, char *); /* { dg-warning "passing argument 1 of 'scbFp.x' from incompatible pointer type" } */
+TESTASS(scc, signed char *, char *); /* { dg-warning "assignment from incompatible pointer type" } */
+TESTINI(scd, signed char *, char *); /* { dg-warning "initialization from incompatible pointer type" } */
+TESTRET(sce, signed char *, char *); /* { dg-warning "return from incompatible pointer type" } */
 
 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" } */
diff --git gcc/testsuite/gcc.dg/assign-warn-2.c gcc/testsuite/gcc.dg/assign-warn-2.c
index 1e5eb1c..51c2e92 100644
--- gcc/testsuite/gcc.dg/assign-warn-2.c
+++ gcc/testsuite/gcc.dg/assign-warn-2.c
@@ -61,29 +61,29 @@  TESTASS(usc, unsigned int *, int *); /* { dg-error "pointer targets in assignmen
 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" } */
 
-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" } */
-
-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" } */
-
-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" } */
-
-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" } */
+TESTARG(cua, char *, unsigned char *); /* { dg-error "passing argument 1 of 'cuaF' from incompatible pointer type" } */
+TESTARP(cub, char *, unsigned char *); /* { dg-error "passing argument 1 of 'cubFp.x' from incompatible pointer type" } */
+TESTASS(cuc, char *, unsigned char *); /* { dg-error "assignment from incompatible pointer type" } */
+TESTINI(cud, char *, unsigned char *); /* { dg-error "initialization from incompatible pointer type" } */
+TESTRET(cue, char *, unsigned char *); /* { dg-error "return from incompatible pointer type" } */
+
+TESTARG(uca, unsigned char *, char *); /* { dg-error "passing argument 1 of 'ucaF' from incompatible pointer type" } */
+TESTARP(ucb, unsigned char *, char *); /* { dg-error "passing argument 1 of 'ucbFp.x' from incompatible pointer type" } */
+TESTASS(ucc, unsigned char *, char *); /* { dg-error "assignment from incompatible pointer type" } */
+TESTINI(ucd, unsigned char *, char *); /* { dg-error "initialization from incompatible pointer type" } */
+TESTRET(uce, unsigned char *, char *); /* { dg-error "return from incompatible pointer type" } */
+
+TESTARG(csa, char *, signed char *); /* { dg-error "passing argument 1 of 'csaF' from incompatible pointer type" } */
+TESTARP(csb, char *, signed char *); /* { dg-error "passing argument 1 of 'csbFp.x' from incompatible pointer type" } */
+TESTASS(csc, char *, signed char *); /* { dg-error "assignment from incompatible pointer type" } */
+TESTINI(csd, char *, signed char *); /* { dg-error "initialization from incompatible pointer type" } */
+TESTRET(cse, char *, signed char *); /* { dg-error "return from incompatible pointer type" } */
+
+TESTARG(sca, signed char *, char *); /* { dg-error "passing argument 1 of 'scaF' from incompatible pointer type" } */
+TESTARP(scb, signed char *, char *); /* { dg-error "passing argument 1 of 'scbFp.x' from incompatible pointer type" } */
+TESTASS(scc, signed char *, char *); /* { dg-error "assignment from incompatible pointer type" } */
+TESTINI(scd, signed char *, char *); /* { dg-error "initialization from incompatible pointer type" } */
+TESTRET(sce, signed char *, char *); /* { dg-error "return from incompatible pointer type" } */
 
 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" } */
diff --git gcc/testsuite/gcc.dg/conv-2.c gcc/testsuite/gcc.dg/conv-2.c
index 388dee3..7c8c89d 100644
--- gcc/testsuite/gcc.dg/conv-2.c
+++ gcc/testsuite/gcc.dg/conv-2.c
@@ -17,10 +17,10 @@  int main()
   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" } */
+  cp = ucp;	/* { dg-warning "assignment from incompatible pointer type" } */
+  cp = scp;	/* { dg-warning "assignment from incompatible pointer type" } */
   ucp = scp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  ucp = cp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
+  ucp = cp;	/* { dg-warning "assignment from incompatible pointer type" } */
   scp = ucp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
-  scp = cp;	/* { dg-warning " pointer targets in assignment differ in signedness" } */
+  scp = cp;	/* { dg-warning "assignment from incompatible pointer type" } */
 }
diff --git gcc/testsuite/gcc.dg/pr23087.c gcc/testsuite/gcc.dg/pr23087.c
index e69de29..4bb45bb 100644
--- gcc/testsuite/gcc.dg/pr23087.c
+++ gcc/testsuite/gcc.dg/pr23087.c
@@ -0,0 +1,64 @@ 
+/* PR c/23087 */
+/* { dg-do compile } */
+/* { dg-options "-Wpointer-sign" } */
+
+/* char is a separate type from the other two [signed char and unsigned char]
+   and is not compatible with either.  */
+
+void
+fn1 (void)
+{
+  char *pc = 0;
+  char *pc2 = pc;
+  signed char *psc = pc; /* { dg-warning "initialization from incompatible pointer type" } */
+  unsigned char *puc = pc; /* { dg-warning "initialization from incompatible pointer type" } */
+}
+
+void
+fn2 (void)
+{
+  signed char *psc = 0;
+  char *pc = psc; /* { dg-warning "initialization from incompatible pointer type" } */
+  signed char *psc2 = psc;
+  unsigned char *puc = psc; /* { dg-warning "pointer targets in initialization differ in signedness" } */
+}
+
+void
+fn3 (void)
+{
+  unsigned char *puc = 0;
+  char *pc = puc; /* { dg-warning "initialization from incompatible pointer type" } */
+  signed char *psc = puc; /* { dg-warning "pointer targets in initialization differ in signedness" } */
+  unsigned char *puc2 = puc;
+}
+
+/* String literals have type "char []".  */
+
+void
+fn4 (void)
+{
+  char *p = "";
+  signed char *ps = ""; /* { dg-warning "initialization from incompatible pointer type" } */
+  unsigned char *pu = ""; /* { dg-warning "initialization from incompatible pointer type" } */
+}
+
+void
+fn5 (void)
+{
+  const char *pcc = 0;
+  char *pc = pcc; /* { dg-warning "initialization discards" } */
+  signed char *psc = pcc; /* { dg-warning "initialization from incompatible pointer type" } */
+  unsigned char *puc = pcc; /* { dg-warning "initialization from incompatible pointer type" } */
+}
+
+void
+fn6 (void)
+{
+  char *pc = 0;
+  char *pc2;
+  unsigned char *puc;
+  signed char *psc;
+  pc2 = pc;
+  puc = pc; /* { dg-warning "assignment from incompatible pointer type" } */
+  psc = pc; /* { dg-warning "assignment from incompatible pointer type" } */
+}
diff --git gcc/testsuite/gcc.dg/pr28726.c gcc/testsuite/gcc.dg/pr28726.c
index 11232ac..76bd7cf 100644
--- gcc/testsuite/gcc.dg/pr28726.c
+++ gcc/testsuite/gcc.dg/pr28726.c
@@ -11,7 +11,7 @@  static double my_loop(void) __attribute__((noinline));
 static double my_loop(void)
 {
   double retval = 0.0;
-  const unsigned char *start = "\005\b\000";
+  const unsigned char *start = "\005\b\000"; /* { dg-warning "initialization from incompatible pointer type" } */
   const unsigned char *const end = start + 2;
 
   while (start < end)
diff --git gcc/testsuite/gcc.dg/torture/pr49603.c gcc/testsuite/gcc.dg/torture/pr49603.c
index 9bde989..d7e3ba1 100644
--- gcc/testsuite/gcc.dg/torture/pr49603.c
+++ gcc/testsuite/gcc.dg/torture/pr49603.c
@@ -6,7 +6,7 @@  struct gl_visual {
 struct gl_context {
     struct gl_visual *Visual;
 };
-void foo (char *);
+void foo (unsigned char *);
 void quickdraw_rgb( struct gl_context * ctx,
 		    int width, int height)
 {
diff --git gcc/testsuite/gcc.dg/torture/pr64853.c gcc/testsuite/gcc.dg/torture/pr64853.c
index 620f99d..aa8cfbd 100644
--- gcc/testsuite/gcc.dg/torture/pr64853.c
+++ gcc/testsuite/gcc.dg/torture/pr64853.c
@@ -7,7 +7,7 @@  struct S
 
 static struct S a = { 1 };
 char b;
-static unsigned char *c = &b;
+static unsigned char *c = &b; /* { dg-warning "initialization from incompatible pointer type" } */
 int d, e, f;
 
 int
diff --git gcc/testsuite/gcc.target/i386/avx2-mpsadbw-2.c gcc/testsuite/gcc.target/i386/avx2-mpsadbw-2.c
index 18118e4..6b43908 100644
--- gcc/testsuite/gcc.target/i386/avx2-mpsadbw-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-mpsadbw-2.c
@@ -21,8 +21,8 @@  compute_mpsadbw (int *i1, int *i2, int mask, int *r)
   unsigned char s[4];
   int i, j;
   int offs1, offs2;
-  unsigned char *v1 = (char *) i1;
-  unsigned char *v2 = (char *) i2;
+  unsigned char *v1 = (unsigned char *) i1;
+  unsigned char *v2 = (unsigned char *) i2;
   unsigned short *ret = (unsigned short *) r;
 
   memset (ret, 0, 32);
diff --git gcc/testsuite/gcc.target/i386/avx2-vpaddusb-2.c gcc/testsuite/gcc.target/i386/avx2-vpaddusb-2.c
index 68ad4f0..d9c652a 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpaddusb-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpaddusb-2.c
@@ -31,6 +31,6 @@  avx2_test (void)
       e[i] = tmp;
     }
 
-  if (check_union256i_b (u, e))
+  if (check_union256i_b (u, (char *) e))
     abort ();
 }
diff --git gcc/testsuite/gcc.target/i386/avx2-vpavgb-2.c gcc/testsuite/gcc.target/i386/avx2-vpavgb-2.c
index 8519e9b..14a69aa 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpavgb-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpavgb-2.c
@@ -25,6 +25,6 @@  avx2_test (void)
   for (i = 0; i < 32; i++)
     e[i] = ((unsigned char) s1.a[i] + (unsigned char) s2.a[i] + 1) >> 1;
 
-  if (check_union256i_b (u, e))
+  if (check_union256i_b (u, (char *) e))
     abort ();
 }
diff --git gcc/testsuite/gcc.target/i386/avx2-vpmaxub-2.c gcc/testsuite/gcc.target/i386/avx2-vpmaxub-2.c
index f0654e0..a7ce05a 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpmaxub-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpmaxub-2.c
@@ -34,7 +34,7 @@  avx2_test (void)
       compute_pmaxub256 ((unsigned char *) s1.a,
 			 (unsigned char *) s2.a, (unsigned char *) res_ref);
 
-      fail += check_union256i_b (res, res_ref);
+      fail += check_union256i_b (res, (char *) res_ref);
     }
 
   if (fail != 0)
diff --git gcc/testsuite/gcc.target/i386/avx2-vpminub-2.c gcc/testsuite/gcc.target/i386/avx2-vpminub-2.c
index 16c5f76..8f5a7f2 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpminub-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpminub-2.c
@@ -34,7 +34,7 @@  avx2_test (void)
       compute_pminub256 ((unsigned char *) s1.a,
 			 (unsigned char *) s2.a, (unsigned char *) res_ref);
 
-      fail += check_union256i_b (res, res_ref);
+      fail += check_union256i_b (res, (char *) res_ref);
     }
 
   if (fail != 0)
diff --git gcc/testsuite/gcc.target/i386/avx2-vpmovzxbd-2.c gcc/testsuite/gcc.target/i386/avx2-vpmovzxbd-2.c
index 7a212c8..ac2c21c 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpmovzxbd-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpmovzxbd-2.c
@@ -24,7 +24,7 @@  avx2_test (void)
 
   res.x = _mm256_cvtepu8_epi32 (s.x);
 
-  compute_movzxbd (s.a, res_ref);
+  compute_movzxbd ((unsigned char *) s.a, res_ref);
 
   if (check_union256i_d (res, res_ref))
     abort ();
diff --git gcc/testsuite/gcc.target/i386/avx2-vpmovzxbq-2.c gcc/testsuite/gcc.target/i386/avx2-vpmovzxbq-2.c
index c09c21d..5e36bd3 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpmovzxbq-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpmovzxbq-2.c
@@ -24,7 +24,7 @@  avx2_test (void)
 
   res.x = _mm256_cvtepu8_epi64 (s.x);
 
-  compute_movzxbq (s.a, res_ref);
+  compute_movzxbq ((unsigned char *) s.a, res_ref);
 
   if (check_union256i_q (res, res_ref))
     abort ();
diff --git gcc/testsuite/gcc.target/i386/avx2-vpmovzxbw-2.c gcc/testsuite/gcc.target/i386/avx2-vpmovzxbw-2.c
index 5ef4b15..3d46933 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpmovzxbw-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpmovzxbw-2.c
@@ -24,7 +24,7 @@  avx2_test (void)
 
   res.x = _mm256_cvtepu8_epi16 (s.x);
 
-  compute_movzxbw (s.a, res_ref);
+  compute_movzxbw ((unsigned char *) s.a, res_ref);
 
   if (check_union256i_w (res, res_ref))
     abort ();
diff --git gcc/testsuite/gcc.target/i386/avx2-vpsadbw-2.c gcc/testsuite/gcc.target/i386/avx2-vpsadbw-2.c
index 3926136..bf367a9 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpsadbw-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpsadbw-2.c
@@ -47,7 +47,7 @@  avx2_test (void)
 	}
 
       res.x = _mm256_sad_epu8 (s1.x, s2.x);;
-      compute_sadbw256 (s1.a, s2.a, res_ref);
+      compute_sadbw256 ((unsigned char *) s1.a, (unsigned char *) s2.a, res_ref);
 
       fail += check_union256i_w (res, res_ref);
     }
diff --git gcc/testsuite/gcc.target/i386/avx2-vpsubusb-2.c gcc/testsuite/gcc.target/i386/avx2-vpsubusb-2.c
index bffb5b6f..7921404 100644
--- gcc/testsuite/gcc.target/i386/avx2-vpsubusb-2.c
+++ gcc/testsuite/gcc.target/i386/avx2-vpsubusb-2.c
@@ -31,6 +31,6 @@  avx2_test (void)
       e[i] = tmp;
     }
 
-  if (check_union256i_b (u, e))
+  if (check_union256i_b (u, (char *) e))
     abort ();
 }
diff --git gcc/testsuite/gcc.target/i386/avx512f-vpmovusdb-2.c gcc/testsuite/gcc.target/i386/avx512f-vpmovusdb-2.c
index 5a201d3..5aad21e 100644
--- gcc/testsuite/gcc.target/i386/avx512f-vpmovusdb-2.c
+++ gcc/testsuite/gcc.target/i386/avx512f-vpmovusdb-2.c
@@ -62,7 +62,7 @@  TEST (void)
   INTRINSIC (_mask_cvtusepi32_storeu_epi8) (res4, mask, src.x);
   CALC (res_ref2, src.a, 1);
 
-  MASK_MERGE (i_b) (res_ref2, mask, SIZE);
-  if (checkVc (res4, res_ref2, 16))
+  MASK_MERGE (i_b) ((char *) res_ref2, mask, SIZE);
+  if (checkVc ((char *) res4, (char *) res_ref2, 16))
     abort ();
 }