have all bits set that are set in the ~ operand when it is
extended. */
- op0 = c_common_get_narrower (op0, &unsignedp0);
- op1 = c_common_get_narrower (op1, &unsignedp1);
+ tree arg0 = c_common_get_narrower (op0, &unsignedp0);
+ if (TYPE_PRECISION (TREE_TYPE (arg0)) == TYPE_PRECISION (TREE_TYPE (op0)))
+ unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+ op0 = arg0;
+ tree arg1 = c_common_get_narrower (op1, &unsignedp1);
+ if (TYPE_PRECISION (TREE_TYPE (arg1)) == TYPE_PRECISION (TREE_TYPE (op1)))
+ unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (op1));
+ op1 = arg1;
if ((TREE_CODE (op0) == BIT_NOT_EXPR)
^ (TREE_CODE (op1) == BIT_NOT_EXPR))
{
- if (TREE_CODE (op0) == BIT_NOT_EXPR)
- op0 = c_common_get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
if (TREE_CODE (op1) == BIT_NOT_EXPR)
- op1 = c_common_get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
-
- if (tree_fits_shwi_p (op0) || tree_fits_shwi_p (op1))
{
- tree primop;
- HOST_WIDE_INT constant, mask;
- int unsignedp;
- unsigned int bits;
+ std::swap (op0, op1);
+ std::swap (unsignedp0, unsignedp1);
+ }
- if (tree_fits_shwi_p (op0))
- {
- primop = op1;
- unsignedp = unsignedp1;
- constant = tree_to_shwi (op0);
- }
- else
- {
- primop = op0;
- unsignedp = unsignedp0;
- constant = tree_to_shwi (op1);
- }
+ int unsignedp;
+ arg0 = c_common_get_narrower (TREE_OPERAND (op0, 0), &unsignedp);
- bits = TYPE_PRECISION (TREE_TYPE (primop));
- if (bits < TYPE_PRECISION (result_type)
- && bits < HOST_BITS_PER_LONG && unsignedp)
+ /* For these warnings, we need BIT_NOT_EXPR operand to be
+ zero extended from narrower type to BIT_NOT_EXPR's type.
+ In that case, all those bits above the narrower's type
+ are after BIT_NOT_EXPR set to 1. */
+ if (tree_fits_shwi_p (op1))
+ {
+ HOST_WIDE_INT constant = tree_to_shwi (op1);
+ unsigned int bits = TYPE_PRECISION (TREE_TYPE (arg0));
+ if (unsignedp
+ && bits < TYPE_PRECISION (TREE_TYPE (op0))
+ && bits < HOST_BITS_PER_WIDE_INT)
{
- mask = HOST_WIDE_INT_M1U << bits;
+ HOST_WIDE_INT mask = HOST_WIDE_INT_M1U << bits;
+ if (unsignedp0)
+ {
+ bits = TYPE_PRECISION (TREE_TYPE (op0));
+ if (bits < TYPE_PRECISION (result_type)
+ && bits < HOST_BITS_PER_WIDE_INT)
+ mask &= ~(HOST_WIDE_INT_M1U << bits);
+ }
+ bits = TYPE_PRECISION (result_type);
+ if (bits < HOST_BITS_PER_WIDE_INT)
+ mask &= ~(HOST_WIDE_INT_M1U << bits);
if ((mask & constant) != mask)
{
if (constant == 0)
}
}
}
- else if (unsignedp0 && unsignedp1
- && (TYPE_PRECISION (TREE_TYPE (op0))
- < TYPE_PRECISION (result_type))
+ else if ((TYPE_PRECISION (TREE_TYPE (arg0))
+ < TYPE_PRECISION (TREE_TYPE (op0)))
+ && unsignedp
+ && unsignedp1
+ /* If unsignedp0, the BIT_NOT_EXPR result is
+ zero extended, so say if op0 is unsigned char
+ variable, BIT_NOT_EXPR is unsigned short and
+ result type int and op0 has value 0x55, the
+ int value will be 0xffaa, or for op0 0xaa it
+ will be 0xff55. In these cases, warn if
+ op1 is unsigned and narrower than unsigned short.
+ While if unsignedp0 is false, the BIT_NOT_EXPR
+ result is sign extended and because of the
+ above TYPE_PRECISION comparison we know the
+ MSB of BIT_NOT_EXPR is set (perhaps with some
+ further bits below it). The sign extension will
+ then ensure all bits above BIT_NOT_EXPR up to
+ result_type's precision are set. */
&& (TYPE_PRECISION (TREE_TYPE (op1))
- < TYPE_PRECISION (result_type)))
+ < TYPE_PRECISION (unsignedp0
+ ? TREE_TYPE (op0)
+ : result_type)))
warning_at (location, OPT_Wsign_compare,
"comparison of promoted bitwise complement "
"of an unsigned value with unsigned");
--- /dev/null
+/* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-Wsign-compare" } */
+
+int
+f1 (unsigned char x)
+{
+ return (unsigned short) (~(unsigned short) x) == 0; /* { dg-warning "promoted bitwise complement of an unsigned value is always nonzero" "" { target c } } */
+}
+
+int
+f2 (unsigned char x)
+{
+ return (unsigned short) (~(unsigned short) x) == 5; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with constant" "" { target c } } */
+}
+
+int
+f3 (unsigned char x)
+{
+ return (unsigned int) (~(unsigned short) x) == 0xffff0005U; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+int
+f4 (unsigned char x)
+{
+ return (unsigned int) (~(unsigned short) x) == 0xffff0005ULL; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+int
+f5 (unsigned char x)
+{
+ return (unsigned int) (~(unsigned short) x) == 0xffffff05U; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+int
+f6 (unsigned char x)
+{
+ return (unsigned int) (~(unsigned short) x) == 0xffffff05ULL; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+int
+f7 (unsigned char x)
+{
+ return (unsigned long long) (~(unsigned short) x) == 0xffffffffffffff05ULL; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+typedef unsigned short T;
+
+int
+f8 (T x)
+{
+ return (unsigned short) (~(unsigned short) x) == 0; /* { dg-bogus "promoted bitwise complement of an unsigned value is always nonzero" } */
+}
+
+int
+f9 (T x)
+{
+ return (unsigned short) (~(unsigned short) x) == 5; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with constant" } */
+}
+
+int
+f10 (T x, unsigned char y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}
+
+int
+f11 (T x, unsigned char y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}
+
+int
+f12 (unsigned char x, unsigned char y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with unsigned" "" { target c } } */
+}
+
+int
+f13 (unsigned char x, unsigned char y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with unsigned" "" { target c } } */
+}
+
+int
+f14 (unsigned char x, unsigned int y)
+{
+ return (unsigned long long) (~x) == y; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}
+
+int
+f15 (unsigned short x, unsigned int y)
+{
+ return (long long) (~x) == y; /* { dg-warning "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}
+
+int
+f16 (unsigned char x, unsigned short y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}
+
+int
+f17 (unsigned char x, unsigned short y)
+{
+ return (unsigned short) (~(unsigned short) x) == y; /* { dg-bogus "comparison of promoted bitwise complement of an unsigned value with unsigned" } */
+}