re PR c++/34198 (-Wconversion gives apparent erroneous warning with g++ 4.3-20071109)
authorJakub Jelinek <jakub@redhat.com>
Fri, 23 Nov 2007 13:39:44 +0000 (14:39 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 23 Nov 2007 13:39:44 +0000 (14:39 +0100)
PR c++/34198
* c-common.c (conversion_warning): For INTEGER_TYPE to
INTEGER_TYPE conversions call get_narrower on expr to avoid
spurious warnings from binop shortening or when the implicit
conversion can't change the value.

* gcc.dg/Wconversion-5.c: New test.
* g++.dg/Wconversion3.C: New test.

From-SVN: r130377

gcc/ChangeLog
gcc/c-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wconversion3.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wconversion-5.c [new file with mode: 0644]

index e6f36406f0df773c1f9d87948cf86c8cdee503e7..722ec42882c475213cab58857a14736f40b7d278 100644 (file)
@@ -1,3 +1,11 @@
+2007-11-23  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/34198
+       * c-common.c (conversion_warning): For INTEGER_TYPE to
+       INTEGER_TYPE conversions call get_narrower on expr to avoid
+       spurious warnings from binop shortening or when the implicit
+       conversion can't change the value.
+
 2007-11-22  Joseph Myers  <joseph@codesourcery.com>
 
        PR c/14050
index edc9b2c17fb356590a6b03c171fd4b2222ee7735..6872e3acef94498ca7ad9fecb89a7d33440f8ccb 100644 (file)
@@ -1280,6 +1280,14 @@ conversion_warning (tree type, tree expr)
       else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
                && TREE_CODE (type) == INTEGER_TYPE)
         {
+         /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
+         int uns;
+         tree orig_expr = expr;
+         expr = get_narrower (expr, &uns);
+
+         if (expr == orig_expr)
+           uns = TYPE_UNSIGNED (TREE_TYPE (expr));
+
           /* Warn for integer types converted to smaller integer types.  */
           if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))) 
            give_warning = true;
@@ -1287,14 +1295,31 @@ conversion_warning (tree type, tree expr)
          /* When they are the same width but different signedness,
             then the value may change.  */
          else if ((formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
-                   && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
+                   && uns != TYPE_UNSIGNED (type))
                   /* Even when converted to a bigger type, if the type is
                      unsigned but expr is signed, then negative values
                      will be changed.  */
-                  || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
-           warning (OPT_Wsign_conversion,
-                    "conversion to %qT from %qT may change the sign of the result",
-                    type, TREE_TYPE (expr));
+                  || (TYPE_UNSIGNED (type) && !uns))
+           {
+             if (uns != TYPE_UNSIGNED (TREE_TYPE (expr)))
+               {
+                 /* For signed char s1, s2 = (int) (unsigned char) s1;
+                    get_narrower returns s1, but uns = 1.  Find the
+                    narrowest type with uns == TYPE_UNSIGNED (type).  */
+                 tree unsexpr = orig_expr;
+
+                 while (TREE_CODE (unsexpr) == NOP_EXPR
+                        && unsexpr != expr
+                        && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (unsexpr,
+                                                                   0)))
+                           == uns)
+                   unsexpr = TREE_OPERAND (unsexpr, 0);
+                 expr = unsexpr;
+               }
+             warning (OPT_Wsign_conversion,
+                      "conversion to %qT from %qT may change the sign of the result",
+                      type, TREE_TYPE (expr));
+           }
         }
 
       /* Warn for integer types converted to real types if and only if
index d9aee04b5137a09b0ee8b73c956b47de5b032ad6..7f0c52bcc22abfe1e95a6d2067bb26ac237ac1e4 100644 (file)
@@ -1,3 +1,9 @@
+2007-11-23  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/34198
+       * gcc.dg/Wconversion-5.c: New test.
+       * g++.dg/Wconversion3.C: New test.
+
 2007-11-23  Richard Guenther  <rguenther@suse.de>
 
        * gcc.dg/tree-ssa/alias-17.c: New testcase.
diff --git a/gcc/testsuite/g++.dg/warn/Wconversion3.C b/gcc/testsuite/g++.dg/warn/Wconversion3.C
new file mode 100644 (file)
index 0000000..24202b7
--- /dev/null
@@ -0,0 +1,35 @@
+// PR c++/34198
+// { dg-do compile }
+// { dg-options "-O2 -Wconversion -Wsign-conversion" }
+
+signed char sc;
+unsigned char uc;
+short int ss;
+unsigned short int us;
+int si;
+unsigned int ui;
+
+void test1 (void)
+{
+  int a = uc & 0xff;
+  int b = sc & 0x7f;
+  int c = 0xff & uc;
+  int d = 0x7f & sc;
+  int e = uc & sc;
+  unsigned char f = (int) uc;
+  signed char g = (int) sc;
+  unsigned char h = (unsigned int) (short int) uc;
+  signed char i = (int) (unsigned short int) sc;       // { dg-warning "may alter its value" }
+  unsigned char j = (unsigned int) (short int) us;     // { dg-warning "may alter its value" }
+  signed char k = (int) (unsigned short int) ss;       // { dg-warning "may alter its value" }
+}
+
+void test2 (void)
+{
+  signed char a = (unsigned char) sc;          // { dg-warning "may change the sign" }
+  unsigned char b = (signed char) uc;          // { dg-warning "may change the sign" }
+  signed char c = (int) (unsigned char) sc;    // { dg-warning "may change the sign" }
+  unsigned char d = (int) (signed char) uc;    // { dg-warning "may change the sign" }
+  int e = (unsigned int) si;                   // { dg-warning "may change the sign" }
+  unsigned int f = (int) ui;                   // { dg-warning "may change the sign" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wconversion-5.c b/gcc/testsuite/gcc.dg/Wconversion-5.c
new file mode 100644 (file)
index 0000000..a09caae
--- /dev/null
@@ -0,0 +1,35 @@
+/* PR c++/34198 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wconversion" } */
+
+signed char sc;
+unsigned char uc;
+short int ss;
+unsigned short int us;
+int si;
+unsigned int ui;
+
+void test1 (void)
+{
+  int a = uc & 0xff;
+  int b = sc & 0x7f;
+  int c = 0xff & uc;
+  int d = 0x7f & sc;
+  int e = uc & sc;
+  unsigned char f = (int) uc;
+  signed char g = (int) sc;
+  unsigned char h = (unsigned int) (short int) uc;
+  signed char i = (int) (unsigned short int) sc;       /* { dg-warning "may alter its value" } */
+  unsigned char j = (unsigned int) (short int) us;     /* { dg-warning "may alter its value" } */
+  signed char k = (int) (unsigned short int) ss;       /* { dg-warning "may alter its value" } */
+}
+
+void test2 (void)
+{
+  signed char a = (unsigned char) sc;          /* { dg-warning "may change the sign" } */
+  unsigned char b = (signed char) uc;          /* { dg-warning "may change the sign" } */
+  signed char c = (int) (unsigned char) sc;    /* { dg-warning "may change the sign" } */
+  unsigned char d = (int) (signed char) uc;    /* { dg-warning "may change the sign" } */
+  int e = (unsigned int) si;                   /* { dg-warning "may change the sign" } */
+  unsigned int f = (int) ui;                   /* { dg-warning "may change the sign" } */
+}