diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index a5fcb35e32f..7b81080a34f 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2015-03-09 Jakub Jelinek + + PR c/65120 + * c-typeck.c (parser_build_binary_op): Don't warn for + !!x == y or !b == y where b is _Bool. + 2015-03-09 Marek Polacek * c-convert.c (convert): Make use of do_ubsan_in_current_function. diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 7c6d974a486..98bff32f17e 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3460,8 +3460,34 @@ parser_build_binary_op (location_t location, enum tree_code code, if (warn_logical_not_paren && code1 == TRUTH_NOT_EXPR - && code2 != TRUTH_NOT_EXPR) - warn_logical_not_parentheses (location, code, arg2.value); + && code2 != TRUTH_NOT_EXPR + /* Avoid warning for !!x == y. */ + && (TREE_CODE (arg1.value) != NE_EXPR + || !integer_zerop (TREE_OPERAND (arg1.value, 1)))) + { + /* Avoid warning for !b == y where b has _Bool type. */ + tree t = integer_zero_node; + if (TREE_CODE (arg1.value) == EQ_EXPR + && integer_zerop (TREE_OPERAND (arg1.value, 1)) + && TREE_TYPE (TREE_OPERAND (arg1.value, 0)) == integer_type_node) + { + t = TREE_OPERAND (arg1.value, 0); + do + { + if (TREE_TYPE (t) != integer_type_node) + break; + if (TREE_CODE (t) == C_MAYBE_CONST_EXPR) + t = C_MAYBE_CONST_EXPR_EXPR (t); + else if (CONVERT_EXPR_P (t)) + t = TREE_OPERAND (t, 0); + else + break; + } + while (1); + } + if (TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE) + warn_logical_not_parentheses (location, code, arg2.value); + } /* Warn about comparisons against string literals, with the exception of testing for equality or inequality of a string literal with NULL. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1e19d6d15a8..cd2d0765998 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2015-03-09 Jakub Jelinek + + PR c/65120 + * parser.c (cp_parser_binary_expression): Don't warn for + !!x == y or !b == y where b is bool. + 2015-03-06 Aldy Hernandez * ptree.c (cxx_print_lambda_node): New. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e0b455c88c5..2a3578fee3c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8270,7 +8270,20 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node; if (warn_logical_not_paren - && current.lhs_type == TRUTH_NOT_EXPR) + && current.lhs_type == TRUTH_NOT_EXPR + /* Avoid warning for !!x == y. */ + && (TREE_CODE (current.lhs) != NE_EXPR + || !integer_zerop (TREE_OPERAND (current.lhs, 1))) + && (TREE_CODE (current.lhs) != TRUTH_NOT_EXPR + || (TREE_CODE (TREE_OPERAND (current.lhs, 0)) != TRUTH_NOT_EXPR + /* Avoid warning for !b == y where b is boolean. */ + && (TREE_TYPE (TREE_OPERAND (current.lhs, 0)) == NULL_TREE + || (TREE_CODE (TREE_TYPE (TREE_OPERAND (current.lhs, 0))) + != BOOLEAN_TYPE)))) + /* Avoid warning for !!b == y where b is boolean. */ + && (!DECL_P (current.lhs) + || TREE_TYPE (current.lhs) == NULL_TREE + || TREE_CODE (TREE_TYPE (current.lhs)) != BOOLEAN_TYPE)) warn_logical_not_parentheses (current.loc, current.tree_type, rhs); overload = NULL; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a17c73f8f79..2287409fb0a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2015-03-09 Jakub Jelinek + + PR c/65120 + * c-c++-common/pr49706.c: Adjust tests for not warning + about !!x == y or !b == y where b is boolean, and add + some further tests. + * c-c++-common/pr62199-2.c: Likewise. + 2015-03-09 Richard Biener PR middle-end/65270 diff --git a/gcc/testsuite/c-c++-common/pr49706.c b/gcc/testsuite/c-c++-common/pr49706.c index 615f3e40a48..f41fa8bb5ff 100644 --- a/gcc/testsuite/c-c++-common/pr49706.c +++ b/gcc/testsuite/c-c++-common/pr49706.c @@ -12,10 +12,13 @@ extern bool foo_b (void); extern int foo_i (void); #ifdef __cplusplus -template bool f1(T t, U u) { return (!t == u); } /* { dg-warning "logical not is only applied to the left hand side of comparison" "" { target c++ } 15 } */ -template bool f2(T t, U u) { return ((!t) == u); } -template bool f3(T t, U u) { return (!g(t) == u); } /* { dg-warning "logical not is only applied to the left hand side of comparison" "" { target c++ } 17 } */ -template bool f4(T t, U u) { return ((!g(t)) == u); } +template bool tfn1(T t, U u) { return (!t == u); } /* { dg-warning "logical not is only applied to the left hand side of comparison" "" { target c++ } 15 } */ +template bool tfn2(T t, U u) { return ((!t) == u); } +template bool tfn3(T t, U u) { return (!g(t) == u); } /* { dg-warning "logical not is only applied to the left hand side of comparison" "" { target c++ } 17 } */ +template bool tfn4(T t, U u) { return ((!g(t)) == u); } +template bool tfn5(T t, U u) { return (!!t == u); } /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ +template bool tfn6(T t, U u) { return (!!g(t) == u); } /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ +template bool tfn7(int i1, int i2) { return (!i1 == i2); } /* { dg-warning "logical not is only applied to the left hand side of comparison" "" { target c++ } 21 } */ #endif void @@ -58,23 +61,42 @@ fn1 (int i1, int i2, bool b1, bool b2) b = !b1 <= b2; b = !b1 >= b2; + b = !b1 == i2; + b = !b1 != i2; + b = !b1 < i2; + b = !b1 > i2; + b = !b1 <= i2; + b = !b1 >= i2; + b = !foo_i () == i1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ b = (!foo_i ()) == i1; b = !foo_b () == b1; - b = !!i1 == i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!i1 != i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!i1 < i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!i1 > i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!i1 <= i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!i1 >= i2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - b = !!foo_i () == i1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 == i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 != i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 < i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 > i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 <= i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 >= i2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!foo_i () == i1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + + b = !!b1 == i2; + b = !!b1 != i2; + b = !!b1 < i2; + b = !!b1 > i2; + b = !!b1 <= i2; + b = !!b1 >= i2; /* Be careful here. */ b = (i1 == 0) != 0; b = (i1 == 0) == 0; b = (i1 != 0) != 0; b = (i1 != 0) == 0; + + b = !5 == 4; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !!5 == 4; /* { dg-bogus "logical not is only applied to the left hand side of comparison" "" { xfail *-*-* } } */ + b = !1 == 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !!1 == 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" "" { xfail *-*-* } } */ } void @@ -100,3 +122,44 @@ fn2 (enum E e) b = (!foo_e ()) == A; b = (!foo_e ()) == foo_e (); } + +void +fn3 (int i1, float f2) +{ + b = !i1 == f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !i1 != f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !i1 < f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !i1 > f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !i1 <= f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = !i1 >= f2; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + + b = i1 == f2; + b = i1 != f2; + b = i1 < f2; + b = i1 > f2; + b = i1 <= f2; + b = i1 >= f2; + + /* Parens suppress the warning. */ + b = (!i1) == f2; + b = (!i1) != f2; + b = (!i1) < f2; + b = (!i1) > f2; + b = (!i1) <= f2; + b = (!i1) >= f2; + + /* ...but not these parens. */ + b = (!i1 == f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = (!i1 != f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = (!i1 < f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = (!i1 > f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = (!i1 <= f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + b = (!i1 >= f2); /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + + b = !!i1 == f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 != f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 < f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 > f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 <= f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + b = !!i1 >= f2; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ +} diff --git a/gcc/testsuite/c-c++-common/pr62199-2.c b/gcc/testsuite/c-c++-common/pr62199-2.c index 7647f16042b..5d25a0ac6d5 100644 --- a/gcc/testsuite/c-c++-common/pr62199-2.c +++ b/gcc/testsuite/c-c++-common/pr62199-2.c @@ -11,10 +11,10 @@ bool r; void foo (bool b) { - r = !b == 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - r = !b != 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - r = !b > 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - r = !b >= 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - r = !b < 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ - r = !b <= 1; /* { dg-warning "logical not is only applied to the left hand side of comparison" } */ + r = !b == 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + r = !b != 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + r = !b > 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + r = !b >= 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + r = !b < 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ + r = !b <= 1; /* { dg-bogus "logical not is only applied to the left hand side of comparison" } */ }