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