Starting with revision 206620, if we have LHS op= RHS and RHS has
side effects, we preevaluate RHS first, which means that we wrap it
in C_MAYBE_CONST_EXPR_EXPR + SAVE_EXPR.  This regressed -Wconversion,
since we now issue bogus warnings.  The reason is that conversion_warning
doesn't grok C_MAYBE_CONST_EXPR_EXPR/SAVE_EXPR, meaning that it
just calls unsafe_conversion_p on it that warns.  But for e.g. relational
and equality operators that's useless as those always yield 0 or 1.
This patch fixes this by unwrapping the expr first.

Regtested/bootstrapped on x86_64-linux, ok for trunk?

2014-02-04  Marek Polacek  <pola...@redhat.com>

        PR c/60036
c-family/
        * c-common.c (conversion_warning): Unwrap C_MAYBE_CONST_EXPR and/or
        SAVE_EXPR.
testsuite/
        * gcc.dg/pr60036.c: New test.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index fc12788..007e727 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -2714,6 +2714,14 @@ conversion_warning (location_t loc, tree type, tree expr)
   if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
     return;
 
+  /* This may happen, because for LHS op= RHS we preevaluate
+     RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
+     means we could no longer see the code of the EXPR.  */
+  if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
+    expr = C_MAYBE_CONST_EXPR_EXPR (expr);
+  if (TREE_CODE (expr) == SAVE_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+
   switch (TREE_CODE (expr))
     {
     case EQ_EXPR:
diff --git gcc/testsuite/gcc.dg/pr60036.c gcc/testsuite/gcc.dg/pr60036.c
index e69de29..07eb6ac 100644
--- gcc/testsuite/gcc.dg/pr60036.c
+++ gcc/testsuite/gcc.dg/pr60036.c
@@ -0,0 +1,28 @@
+/* PR c/60036 */
+/* { dg-do compile } */
+/* { dg-options "-Wconversion" } */
+
+extern int fn (void);
+
+void
+foo (int i)
+{
+  unsigned int f = 9;
+
+  /* Don't warn on these.  */
+  f += fn () || i;
+  f += fn () && i;
+  f += ! fn ();
+  f -= fn () == i;
+  f |= fn () != i;
+  f &= fn () < i;
+  f ^= fn () > i;
+  f &= fn () <= i;
+  f ^= fn () >= i;
+
+  /* But warn on the following.  */
+  f += fn (); /* { dg-warning "conversion" } */
+  f += fn () | i; /* { dg-warning "conversion" } */
+  f += fn () & i; /* { dg-warning "conversion" } */
+  f += fn () ^ i; /* { dg-warning "conversion" } */
+}

        Marek

Reply via email to