On Mon, 9 Jan 2017, Marek Polacek wrote: > On Thu, Jan 05, 2017 at 04:41:28PM +0100, Jakub Jelinek wrote: > > On Thu, Jan 05, 2017 at 04:39:40PM +0100, Marek Polacek wrote: > > > Coming back to this... > > > > > > Right, after h0 == h1 is missing && operand_equal_p (thenb, elseb, 0) > > > > or so (the exact last operand needs to be figured out). > > > > OEP_ONLY_CONST is certainly wrong, we want the same VAR_DECLs to mean > > > > the > > > > same thing. 0 is a tiny bit better, but still it will give up on e.g. > > > > pure > > > > and other calls. OEP_PURE_SAME is tiny bit better than that, but still > > > > calls with the same arguments to the same function will not be > > > > considered > > > > equal, plus likely operand_equal_p doesn't handle STATEMENT_LIST etc. > > > > So maybe we need another OEP_* mode for this. > > > > > > Yea, if I add "&& operand_equal_p (thenb, elseb, 0)" then this warning > > > doesn't > > > trigger for certain cases, such as MODIFY_EXPR, RETURN_EXPR, probably > > > STATEMENT_LIST and others. So I suppose I could introduce a new OEP_ > > > mode for > > > this (names? OEP_EXTENDED?) and then in operand_equal_p in case > > > tcc_expression > > > do > > > > > > case MODIFY_EXPR: > > > if (flags & OEP_EXTENDED) > > > // compare LHS and RHS of both > > > > > > ? > > > > Yeah. Not sure what is the best name for that. Maybe Richi has some clever > > ideas. > > Here it is. The changes in operand_equal_p should only trigger with the new > OEP_LEXICOGRAPHIC, and given the macro location issue, the warning isn't yet > enabled by neither -Wall nor -Wextra, so this all should be safe. > > Bootstrapped/regtested on x86_64-linux, ok for trunk?
@@ -2722,6 +2722,9 @@ combine_comparisons (location_t loc, If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects, not values of expressions. + If OEP_LEXICOGRAPHIC is set, then also handle expressions such as + MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs. + I'd say "also handle expressions with side-effects such as ..." otherwise the middle-end changes look good to me - I'll defer to C FE maintainers for the rest. Thanks, Richard. > 2017-01-09 Marek Polacek <pola...@redhat.com> > > PR c/64279 > * c-common.h (do_warn_duplicated_branches_r): Declare. > * c-gimplify.c (c_genericize): Walk the function tree calling > do_warn_duplicated_branches_r. > * c-warn.c (expr_from_macro_expansion_r): New. > (do_warn_duplicated_branches): New. > (do_warn_duplicated_branches_r): New. > * c.opt (Wduplicated-branches): New option. > > * c-typeck.c (build_conditional_expr): Warn about duplicated branches. > > * call.c (build_conditional_expr_1): Warn about duplicated branches. > * semantics.c (finish_expr_stmt): Build statement using the proper > location. > > * doc/invoke.texi: Document -Wduplicated-branches. > * fold-const.c (operand_equal_p): Handle MODIFY_EXPR, INIT_EXPR, > COMPOUND_EXPR, PREDECREMENT_EXPR, PREINCREMENT_EXPR, > POSTDECREMENT_EXPR, POSTINCREMENT_EXPR, CLEANUP_POINT_EXPR, EXPR_STMT, > STATEMENT_LIST, and RETURN_EXPR. For non-pure non-const functions > return 0 only when not OEP_LEXICOGRAPHIC. > (fold_build_cleanup_point_expr): Use the expression > location when building CLEANUP_POINT_EXPR. > * tree-core.h (enum operand_equal_flag): Add OEP_LEXICOGRAPHIC. > * tree.c (add_expr): Handle error_mark_node. > > * c-c++-common/Wduplicated-branches-1.c: New test. > * c-c++-common/Wduplicated-branches-10.c: New test. > * c-c++-common/Wduplicated-branches-11.c: New test. > * c-c++-common/Wduplicated-branches-12.c: New test. > * c-c++-common/Wduplicated-branches-2.c: New test. > * c-c++-common/Wduplicated-branches-3.c: New test. > * c-c++-common/Wduplicated-branches-4.c: New test. > * c-c++-common/Wduplicated-branches-5.c: New test. > * c-c++-common/Wduplicated-branches-6.c: New test. > * c-c++-common/Wduplicated-branches-7.c: New test. > * c-c++-common/Wduplicated-branches-8.c: New test. > * c-c++-common/Wduplicated-branches-9.c: New test. > * c-c++-common/Wimplicit-fallthrough-7.c: Coalesce dg-warning. > * g++.dg/cpp0x/lambda/lambda-switch.C: Move dg-warning. > * g++.dg/ext/builtin-object-size3.C: Likewise. > * g++.dg/gomp/loop-1.C: Likewise. > * g++.dg/warn/Wduplicated-branches1.C: New test. > * g++.dg/warn/Wduplicated-branches2.C: New test. > > diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h > index b838869..06918db 100644 > --- gcc/c-family/c-common.h > +++ gcc/c-family/c-common.h > @@ -1537,6 +1537,7 @@ extern void maybe_warn_bool_compare (location_t, enum > tree_code, tree, tree); > extern bool maybe_warn_shift_overflow (location_t, tree, tree); > extern void warn_duplicated_cond_add_or_warn (location_t, tree, vec<tree> > **); > extern bool diagnose_mismatched_attributes (tree, tree); > +extern tree do_warn_duplicated_branches_r (tree *, int *, void *); > > /* In c-attribs.c. */ > extern bool attribute_takes_identifier_p (const_tree); > diff --git gcc/c-family/c-gimplify.c gcc/c-family/c-gimplify.c > index c327ca7..57edb41 100644 > --- gcc/c-family/c-gimplify.c > +++ gcc/c-family/c-gimplify.c > @@ -125,6 +125,10 @@ c_genericize (tree fndecl) > &pset); > } > > + if (warn_duplicated_branches) > + walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), > + do_warn_duplicated_branches_r, NULL); > + > /* Dump the C-specific tree IR. */ > dump_orig = get_dump_info (TDI_original, &local_dump_flags); > if (dump_orig) > diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c > index 1dbf47e..3c9077c 100644 > --- gcc/c-family/c-warn.c > +++ gcc/c-family/c-warn.c > @@ -2217,3 +2217,73 @@ warn_for_restrict (unsigned param_pos, vec<tree, > va_gc> *args) > > free (arg_positions); > } > + > +/* Callback function to determine whether an expression TP or one of its > + subexpressions comes from macro expansion. Used to suppress bogus > + warnings. */ > + > +static tree > +expr_from_macro_expansion_r (tree *tp, int *, void *) > +{ > + if (CAN_HAVE_LOCATION_P (*tp) > + && from_macro_expansion_at (EXPR_LOCATION (*tp))) > + return integer_zero_node; > + > + return NULL_TREE; > +} > + > +/* Possibly warn when an if-else has identical branches. */ > + > +static void > +do_warn_duplicated_branches (tree expr) > +{ > + tree thenb = COND_EXPR_THEN (expr); > + tree elseb = COND_EXPR_ELSE (expr); > + > + /* Don't bother if there's no else branch. */ > + if (elseb == NULL_TREE) > + return; > + > + /* And don't warn for empty statements. */ > + if (TREE_CODE (thenb) == NOP_EXPR > + && TREE_TYPE (thenb) == void_type_node > + && TREE_OPERAND (thenb, 0) == size_zero_node) > + return; > + > + /* ... or empty branches. */ > + if (TREE_CODE (thenb) == STATEMENT_LIST > + && STATEMENT_LIST_HEAD (thenb) == NULL) > + return; > + > + /* Compute the hash of the then branch. */ > + inchash::hash hstate0 (0); > + inchash::add_expr (thenb, hstate0); > + hashval_t h0 = hstate0.end (); > + > + /* Compute the hash of the else branch. */ > + inchash::hash hstate1 (0); > + inchash::add_expr (elseb, hstate1); > + hashval_t h1 = hstate1.end (); > + > + /* Compare the hashes. */ > + if (h0 == h1 > + && operand_equal_p (thenb, elseb, OEP_LEXICOGRAPHIC) > + /* Don't warn if any of the branches or their subexpressions comes > + from a macro. */ > + && !walk_tree_without_duplicates (&thenb, expr_from_macro_expansion_r, > + NULL) > + && !walk_tree_without_duplicates (&elseb, expr_from_macro_expansion_r, > + NULL)) > + warning_at (EXPR_LOCATION (expr), OPT_Wduplicated_branches, > + "this condition has identical branches"); > +} > + > +/* Callback for c_genericize to implement -Wduplicated-branches. */ > + > +tree > +do_warn_duplicated_branches_r (tree *tp, int *, void *) > +{ > + if (TREE_CODE (*tp) == COND_EXPR) > + do_warn_duplicated_branches (*tp); > + return NULL_TREE; > +} > diff --git gcc/c-family/c.opt gcc/c-family/c.opt > index 0b74aba..4b86695 100644 > --- gcc/c-family/c.opt > +++ gcc/c-family/c.opt > @@ -468,6 +468,10 @@ Wdiv-by-zero > C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) Warning > Warn about compile-time integer division by zero. > > +Wduplicated-branches > +C ObjC C++ ObjC++ Var(warn_duplicated_branches) Init(0) Warning > +Warn about duplicated branches in if-else statements. > + > Wduplicated-cond > C ObjC C++ ObjC++ Var(warn_duplicated_cond) Init(0) Warning > Warn about duplicated conditions in an if-else-if chain. > diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c > index 96e7351..ed8ffe4 100644 > --- gcc/c/c-typeck.c > +++ gcc/c/c-typeck.c > @@ -5193,6 +5193,15 @@ build_conditional_expr (location_t colon_loc, tree > ifexp, bool ifexp_bcp, > ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret); > > protected_set_expr_location (ret, colon_loc); > + > + /* If the OP1 and OP2 are the same and don't have side-effects, > + warn here, because the COND_EXPR will be turned into OP1. */ > + if (warn_duplicated_branches > + && TREE_CODE (ret) == COND_EXPR > + && (op1 == op2 || operand_equal_p (op1, op2, 0))) > + warning_at (EXPR_LOCATION (ret), OPT_Wduplicated_branches, > + "this condition has identical branches"); > + > return ret; > } > > diff --git gcc/cp/call.c gcc/cp/call.c > index e431221..84931fb 100644 > --- gcc/cp/call.c > +++ gcc/cp/call.c > @@ -5302,6 +5302,13 @@ build_conditional_expr_1 (location_t loc, tree arg1, > tree arg2, tree arg3, > valid_operands: > result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3); > > + /* If the ARG2 and ARG3 are the same and don't have side-effects, > + warn here, because the COND_EXPR will be turned into ARG2. */ > + if (warn_duplicated_branches > + && (arg2 == arg3 || operand_equal_p (arg2, arg3, 0))) > + warning_at (EXPR_LOCATION (result), OPT_Wduplicated_branches, > + "this condition has identical branches"); > + > /* We can't use result_type below, as fold might have returned a > throw_expr. */ > > diff --git gcc/cp/semantics.c gcc/cp/semantics.c > index 2ab0723..49999ca 100644 > --- gcc/cp/semantics.c > +++ gcc/cp/semantics.c > @@ -670,6 +670,7 @@ tree > finish_expr_stmt (tree expr) > { > tree r = NULL_TREE; > + location_t loc = EXPR_LOCATION (expr); > > if (expr != NULL_TREE) > { > @@ -694,7 +695,7 @@ finish_expr_stmt (tree expr) > if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) > { > if (TREE_CODE (expr) != EXPR_STMT) > - expr = build_stmt (input_location, EXPR_STMT, expr); > + expr = build_stmt (loc, EXPR_STMT, expr); > expr = maybe_cleanup_point_expr_void (expr); > } > > diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi > index 83ac135..845c708 100644 > --- gcc/doc/invoke.texi > +++ gcc/doc/invoke.texi > @@ -271,7 +271,8 @@ Objective-C and Objective-C++ Dialects}. > -Wno-deprecated -Wno-deprecated-declarations -Wno-designated-init @gol > -Wdisabled-optimization @gol > -Wno-discarded-qualifiers -Wno-discarded-array-qualifiers @gol > --Wno-div-by-zero -Wdouble-promotion -Wduplicated-cond @gol > +-Wno-div-by-zero -Wdouble-promotion -Wduplicated-branches @gol > +-Wduplicated-cond @gol > -Wempty-body -Wenum-compare -Wno-endif-labels -Wexpansion-to-defined @gol > -Werror -Werror=* -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol > -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol > @@ -3726,7 +3727,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect > Options}. > -Warray-bounds=1 @r{(only with} @option{-O2}@r{)} @gol > -Wbool-compare @gol > -Wbool-operation @gol > --Wc++11-compat -Wc++14-compat@gol > +-Wc++11-compat -Wc++14-compat @gol > -Wchar-subscripts @gol > -Wcomment @gol > -Wduplicate-decl-specifier @r{(C and Objective-C only)} @gol > @@ -5229,6 +5230,22 @@ Incrementing a boolean is invalid in C++1z, and > deprecated otherwise.) > > This warning is enabled by @option{-Wall}. > > +@item -Wduplicated-branches > +@opindex Wno-duplicated-branches > +@opindex Wduplicated-branches > +Warn when an if-else has indentical branches. This warning detects cases > like > +@smallexample > +if (p != NULL) > + return 0; > +else > + return 0; > +@end smallexample > +It doesn't warn when both branches contain just a null statement. This > warning > +also warn for conditional operators: > +@smallexample > + int i = x ? *p : *p; > +@end smallexample > + > @item -Wduplicated-cond > @opindex Wno-duplicated-cond > @opindex Wduplicated-cond > diff --git gcc/fold-const.c gcc/fold-const.c > index 73ebd76..b5375a8 100644 > --- gcc/fold-const.c > +++ gcc/fold-const.c > @@ -2722,6 +2722,9 @@ combine_comparisons (location_t loc, > If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects, > not values of expressions. > > + If OEP_LEXICOGRAPHIC is set, then also handle expressions such as > + MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs. > + > Unless OEP_MATCH_SIDE_EFFECTS is set, the function returns false on > any operand with side effect. This is unnecesarily conservative in the > case we know that arg0 and arg1 are in disjoint code paths (such as in > @@ -3154,6 +3157,23 @@ operand_equal_p (const_tree arg0, const_tree arg1, > unsigned int flags) > case BIT_INSERT_EXPR: > return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); > > + case MODIFY_EXPR: > + case INIT_EXPR: > + case COMPOUND_EXPR: > + case PREDECREMENT_EXPR: > + case PREINCREMENT_EXPR: > + case POSTDECREMENT_EXPR: > + case POSTINCREMENT_EXPR: > + if (flags & OEP_LEXICOGRAPHIC) > + return OP_SAME (0) && OP_SAME (1); > + return 0; > + > + case CLEANUP_POINT_EXPR: > + case EXPR_STMT: > + if (flags & OEP_LEXICOGRAPHIC) > + return OP_SAME (0); > + return 0; > + > default: > return 0; > } > @@ -3190,7 +3210,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, > unsigned int flags) > cef &= ECF_CONST | ECF_PURE; > else > cef &= ECF_CONST; > - if (!cef) > + if (!cef && !(flags & OEP_LEXICOGRAPHIC)) > return 0; > } > > @@ -3269,8 +3289,39 @@ operand_equal_p (const_tree arg0, const_tree arg1, > unsigned int flags) > } > return 1; > } > + else if (TREE_CODE (arg0) == STATEMENT_LIST > + && (flags & OEP_LEXICOGRAPHIC)) > + { > + /* Compare the STATEMENT_LISTs. */ > + tree_stmt_iterator tsi1, tsi2; > + tree body1 = CONST_CAST_TREE (arg0); > + tree body2 = CONST_CAST_TREE (arg1); > + for (tsi1 = tsi_start (body1), tsi2 = tsi_start (body2); ; > + tsi_next (&tsi1), tsi_next (&tsi2)) > + { > + /* The lists don't have the same number of statements. */ > + if (tsi_end_p (tsi1) ^ tsi_end_p (tsi2)) > + return 0; > + if (tsi_end_p (tsi1) && tsi_end_p (tsi2)) > + return 1; > + if (!operand_equal_p (tsi_stmt (tsi1), tsi_stmt (tsi2), > + OEP_LEXICOGRAPHIC)) > + return 0; > + } > + } > return 0; > > + case tcc_statement: > + switch (TREE_CODE (arg0)) > + { > + case RETURN_EXPR: > + if (flags & OEP_LEXICOGRAPHIC) > + return OP_SAME_WITH_NULL (0); > + return 0; > + default: > + return 0; > + } > + > default: > return 0; > } > @@ -13896,7 +13947,7 @@ fold_build_cleanup_point_expr (tree type, tree expr) > return expr; > } > > - return build1 (CLEANUP_POINT_EXPR, type, expr); > + return build1_loc (EXPR_LOCATION (expr), CLEANUP_POINT_EXPR, type, expr); > } > > /* Given a pointer value OP0 and a type TYPE, return a simplified version > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-1.c > gcc/testsuite/c-c++-common/Wduplicated-branches-1.c > index e69de29..c0b93fc 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-1.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-1.c > @@ -0,0 +1,187 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches -O2" } */ > + > +extern void foo (int); > +extern int g; > +extern int a[10]; > + > +int > +f (int i, int *p) > +{ > + const int j = 0; > + if (j == 0) > + { > + if (i > 10) /* { dg-warning "this condition has identical branches" } > */ > + /* Optimizers can figure out that this is 1. */ > + *p = j * 2 + 1; > + else > + *p = 1; > + } > + > + if (i) > + ; > + else > + ; > + > + if (i == 0) /* { dg-warning "this condition has identical branches" } */ > + return 0; > + else > + return 0; > + > + if (i == 1) /* { dg-warning "this condition has identical branches" } */ > + { > + g = 10; > + } > + else > + { > + g = 10; > + } > + > + const char *s; > + if (i == 2) /* { dg-warning "this condition has identical branches" } */ > + s = "foo"; > + else > + s = "foo"; > + > + if (i == 3) /* { dg-warning "this condition has identical branches" } */ > + g = a[i]; > + else > + g = a[i]; > + > + if (i == 4) /* { dg-warning "this condition has identical branches" } */ > + return i ? 1 : g; > + else > + return i ? 1 : g; > + > + if (i == 5) /* { dg-warning "this condition has identical branches" } */ > + { > + { > + { > + { > + g++; > + } > + } > + } > + } > + else > + { > + { > + { > + { > + g++; > + } > + } > + } > + } > + > + if (i == 6) /* { dg-warning "this condition has identical branches" } */ > + g = i * 6; > + else > + g = i * 6; > + > + /* Don't warn. */ > + if (i == 7) > + g = i / 6; > + else > + g = 6 / i; > + > + if (i == 8) /* { dg-warning "this condition has identical branches" } */ > + return i * 8 * i * 8; > + else > + return 8 * i * 8 * i; > + > + > + if (i == 9) /* { dg-warning "this condition has identical branches" } */ > + { > + p++; > + return *p; > + } > + else > + { > + p++; > + return *p; > + } > + > + /* Don't warn. */ > + if (i == 10) > + return *++p; > + else > + return ++*p; > + > + if (i == 11) /* { dg-warning "this condition has identical branches" } */ > + { > + foo (6); > + } > + else > + { > + foo (6); > + } > + > + if (i == 12) /* { dg-warning "this condition has identical branches" } */ > + { > + foo (6 + i), foo (2); > + } > + else > + { > + foo (6 + i), foo (2); > + } > + > + if (i == 13) /* { dg-warning "this condition has identical branches" } */ > + p += (g + 1); > + else > + p += (g + 1); > + > + if (i == 14) /* { dg-warning "this condition has identical branches" } */ > + { > + foo (7); > + *p = 0; > + foo (9); > + } > + else > + { > + foo (7); > + *p = 0; > + foo (9); > + } > + > + if (i == 15) /* { dg-warning "this condition has identical branches" } */ > + p += (g + (1 + 2)); > + else > + p += (g + (1 + 1 + 1)); > + > + if (i == 16) /* { dg-warning "this condition has identical branches" } */ > + foo (10 + g); > + else > + foo (g + 10); > + > + if (i == 17) /* { dg-warning "this condition has identical branches" } */ > + ({ foo (i); }); > + else > + ({ foo (i); }); > + > + if (i == 18) > + { > + if (i == 19) > + { > + if (i == 20) /* { dg-warning "this condition has identical branches" > } */ > + foo (++i); > + else > + foo (++i); > + } > + } > + > + /* Don't warn. */ > + if (i == 21) > + { > + foo (1); > + foo (2); > + } > + else > + { > + foo (2); > + foo (1); > + } > + > + return 0; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-10.c > gcc/testsuite/c-c++-common/Wduplicated-branches-10.c > index e69de29..8d918ef 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-10.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-10.c > @@ -0,0 +1,18 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +#define DEBUG(msg) ; > + > +void > +f (int i) > +{ > + if (i > 9) > + { > + DEBUG ("foo"); > + } > + else > + { > + DEBUG ("bar"); > + } > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-11.c > gcc/testsuite/c-c++-common/Wduplicated-branches-11.c > index e69de29..70d86cf 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-11.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-11.c > @@ -0,0 +1,75 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +int > +f (int p) > +{ > + if (p == 0) > + { > + p += 1, ++p; > + } > + else > + { > + p -= 1, ++p; > + } > + > + if (p == 1) > + { > + } > + else > + p++; > + > + if (p == 2) > + p++; > + else > + { > + } > + > + if (p == 3) > + { > + } > + else > + { > + } > + > + if (p == 4) > + { > + ++p; > + return p; > + } > + else > + { > + p++; > + return p; > + } > + > + if (p == 5) > + ++p; > + else > + p++; > + > + if (p == 6) > + { > + ++p; > + ++p; > + return p; > + } > + else > + { > + ++p; > + return p; > + } > + > + if (p == 7) > + { > + ++p; > + return p; > + } > + else > + { > + ++p; > + ++p; > + return p; > + } > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-12.c > gcc/testsuite/c-c++-common/Wduplicated-branches-12.c > index e69de29..cd746f1 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-12.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-12.c > @@ -0,0 +1,16 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +void > +f (int i) > +{ > + if (i) /* { dg-warning "this condition has identical branches" } */ > + return 0; > +/* { dg-warning ".return. with a value" "" { target c } .-1 } */ > +/* { dg-error "return-statement with a value" "" { target c++ } .-2 } */ > + else > + return 0; > +/* { dg-warning ".return. with a value" "" { target c } .-1 } */ > +/* { dg-error "return-statement with a value" "" { target c++ } .-2 } */ > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-2.c > gcc/testsuite/c-c++-common/Wduplicated-branches-2.c > index e69de29..8669dd6 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-2.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-2.c > @@ -0,0 +1,114 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches -O2" } */ > + > +void > +f (int *p) > +{ > + if (*p > 0) > + { > + if (x == 0) /* { dg-error "undeclared|not declared" } */ > + *p = 5; > + else > + *p = 6; > + } > +} > + > +void > +f2 (int *p) > +{ > + if (*p > 0) > + { > + if (*p > 2) > + *p = x; /* { dg-error "undeclared|not declared" } */ > + else > + *p = 6; > + } > +} > + > +void > +f3 (int *p) > +{ > + if (*p > 0) > + { > + if (*p > 2) > + *p = 8; > + else > + *p = x; /* { dg-error "undeclared|not declared" } */ > + } > +} > + > +void > +f4 (int *p) > +{ > + if (*p > 0) > + { > + if (x == 0) /* { dg-error "undeclared|not declared" } */ > + *p = 5; > + else > + *p = 6; > + } > + else > + { > + if (x == 0) /* { dg-error "not declared" "" { target c++ } } */ > + *p = 7; > + else > + *p = 6; > + } > +} > + > +void > +f5 (int *p) > +{ > + if (*p > 0) > + { > + if (*p > 2) > + *p = x; /* { dg-error "undeclared|not declared" } */ > + else > + *p = 6; > + } > + else > + { > + if (x == 0) /* { dg-error "not declared" "" { target c++ } } */ > + *p = 5; > + else > + *p = 6; > + } > +} > + > +void > +f6 (int *p) > +{ > + if (*p > 0) > + { > + if (*p > 2) > + *p = 8; > + else > + *p = x; /* { dg-error "undeclared|not declared" } */ > + } > + else > + { > + if (x == 0) /* { dg-error "not declared" "" { target c++ } } */ > + *p = 5; > + else > + *p = 6; > + } > +} > + > +void > +f7 (int i) > +{ > + if (i > 5) > + ({ x++; }); /* { dg-error "undeclared|not declared" } */ > + else > + ({ i++; }); > +} > + > +void > +f8 (int i) > +{ > + if (i > 5) > + ({ i++; }); > + else > + ({ x++; }); /* { dg-error "undeclared|not declared" } */ > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-3.c > gcc/testsuite/c-c++-common/Wduplicated-branches-3.c > index e69de29..e188384 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-3.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-3.c > @@ -0,0 +1,19 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +extern int *g; > + > +void > +f (short int i) > +{ > + if (i == 0) /* { dg-warning "this condition has identical branches" } */ > + *g = (int) i; > + else > + *g = (int) i; > + > + if (i == 1) > + *g = (unsigned char) i; > + else > + *g = (signed char) i; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-4.c > gcc/testsuite/c-c++-common/Wduplicated-branches-4.c > index e69de29..79af549 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-4.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-4.c > @@ -0,0 +1,35 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +extern int *g; > +extern const int *q; > + > +void > +f (int i) > +{ > + int j; > + > + if (i == 0) > + for (j = 0; j < 10; j++) > + ++*g; > + else > + for (j = 0; j < 10; j++) > + ++*g; > + > + if (i == 1) > + { > + int i = 10; > + *g = i; > + } > + else > + { > + int i = 10; > + *g = i; > + } > + > + if (i == 3) > + q = (const int []){1}; > + else > + q = (const int []){1}; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-5.c > gcc/testsuite/c-c++-common/Wduplicated-branches-5.c > index e69de29..f2eb8ec 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-5.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-5.c > @@ -0,0 +1,24 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +extern int g; > +extern void foo (); > +#define A g = i > +#define B g = i > +#define DOIT() foo() > +#define DOIT2() foo() > + > +void > +f (int i) > +{ > + if (i == 0) > + A; > + else > + B; > + > + if (i == 1) > + DOIT(); > + else > + DOIT2(); > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-6.c > gcc/testsuite/c-c++-common/Wduplicated-branches-6.c > index e69de29..0010693 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-6.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-6.c > @@ -0,0 +1,12 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +void > +f (int i) > +{ > + if (i == 0) > + ; > + else if (i == 1) > + ; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-7.c > gcc/testsuite/c-c++-common/Wduplicated-branches-7.c > index e69de29..03721dc 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-7.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-7.c > @@ -0,0 +1,36 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +struct S > +{ > + int x; > +} s; > +int a[10]; > + > +#define XMEM(R) ((R).x) > +#define XSTR(R) ((R).x) > + > +void > +f (int i) > +{ > + if (i) > + XMEM(s) = 1; > + else > + XSTR(s) = 1; > + > + if (i) /* { dg-warning "this condition has identical branches" } */ > + s.x = 1; > + else > + s.x = 1; > + > + if (i) > + XMEM(s) = 1; > + else > + s.x = 1; > + > + if (i) > + s.x = 1; > + else > + XMEM(s) = 1; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-8.c > gcc/testsuite/c-c++-common/Wduplicated-branches-8.c > index e69de29..c5e8ca0 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-8.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-8.c > @@ -0,0 +1,73 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +#define A 5 > +#define B 5 > +#define I i > +extern int a[10]; > +extern int g; > + > +int > +f (int i) > +{ > + if (i == 1) /* { dg-warning "this condition has identical branches" } */ > + return a[5]; > + else > + return a[5]; > + > + if (i == 2) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + return a[A]; > + else > + return a[5]; > + > + if (i == 3) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + return a[5]; > + else > + return a[A]; > + > + if (i == 4) /* { dg-warning "this condition has identical branches" } */ > + return a[A]; > + else > + return a[A]; > + > + if (i == 5) /* { dg-warning "this condition has identical branches" } */ > + return a[i]; > + else > + return a[i]; > + > + if (i == 6) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + return a[I]; > + else > + return a[i]; > + > + if (i == 7) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + return a[i]; > + else > + return a[I]; > + > + if (i == 8) /* { dg-warning "this condition has identical branches" } */ > + return a[I]; > + else > + return a[I]; > + > + if (i == 10) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + g += A; > + else > + g += B; > + > + if (i == 11) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + g += B; > + else > + g += A; > + > + if (i == 12) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + g += A; > + else > + g += 5; > + > + if (i == 12) /* { dg-bogus "this condition has identical branches" "" { > xfail *-*-* } } */ > + g += 5; > + else > + g += A; > +} > diff --git gcc/testsuite/c-c++-common/Wduplicated-branches-9.c > gcc/testsuite/c-c++-common/Wduplicated-branches-9.c > index e69de29..9b21776 100644 > --- gcc/testsuite/c-c++-common/Wduplicated-branches-9.c > +++ gcc/testsuite/c-c++-common/Wduplicated-branches-9.c > @@ -0,0 +1,46 @@ > +/* PR c/64279 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wduplicated-branches" } */ > + > +extern int *p, foo (void), a[10]; > +#define N 5 > +#define M 5 > +#define I i > + > +void > +f (int i) > +{ > + *p += i ? 1 : 1; /* { dg-warning "this condition has identical branches" } > */ > + *p += i ? N : M; /* { dg-bogus "this condition has identical branches" "" > { xfail *-*-* } } */ > + *p += i ? M : N; /* { dg-bogus "this condition has identical branches" "" > { xfail *-*-* } } */ > + *p += i ? i : i; /* { dg-warning "this condition has identical branches" } > */ > + *p += i ? i++ : i++; /* { dg-warning "this condition has identical > branches" } */ > + *p += i ? foo () : foo (); /* { dg-warning "this condition has identical > branches" } */ > + *p += i ? ({ i++; }) : ({ i++; }); /* { dg-warning "this condition has > identical branches" } */ > + *p += i ? a[i] : a[i]; /* { dg-warning "this condition has identical > branches" } */ > + *p += i ? a[5] : a[5]; /* { dg-warning "this condition has identical > branches" } */ > + *p += i ? a[N] : a[M]; /* { dg-bogus "this condition has identical > branches" "" { xfail *-*-* } } */ > + *p += i ? a[5] : a[M]; /* { dg-bogus "this condition has identical > branches" "" { xfail *-*-* } } */ > + *p += i ? a[M] : a[5]; /* { dg-bogus "this condition has identical > branches" "" { xfail *-*-* } } */ > + *p += i ? a[I] : a[I]; /* { dg-warning "this condition has identical > branches" } */ > + *p += i ? a[i] : a[I]; /* { dg-bogus "this condition has identical > branches" "" { xfail *-*-* } } */ > + *p += i ? a[I] : a[i]; /* { dg-bogus "this condition has identical > branches" "" { xfail *-*-* } } */ > + > + *p += i ?: 1; > + *p += i ?: M; > + *p += i ?: N; > + *p += i ?: i; /* { dg-warning "this condition has identical branches" "" { > target c++ } } */ > + *p += i ?: i++; > + *p += i ?: foo (); > + *p += i ?: ({ i++; }); > + *p += i ?: a[i]; > + *p += i ?: a[5]; > + *p += i ?: a[M]; > + *p += i ?: a[M]; > + *p += i ?: a[5]; > + *p += i ?: a[I]; > + *p += i ?: a[I]; > + *p += i ?: a[i]; > + > + *p += (i > 5 ? (i > 10 ? i : i) : i); /* { dg-warning "this condition has > identical branches" } */ > +} > diff --git gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c > gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c > index 21a158c..898e5fa 100644 > --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c > +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c > @@ -39,9 +39,9 @@ f (int i) > switch (i) > { > case 1: > - do /* { dg-warning "statement may fall through" "" { target c++ } 42 } > */ > + do > bar (2); > - while (--i); /* { dg-warning "statement may fall through" "" { target > c } 44 } */ > + while (--i); /* { dg-warning "statement may fall through" } */ > case 2: > bar (99); > } > diff --git gcc/testsuite/g++.dg/cpp0x/lambda/lambda-switch.C > gcc/testsuite/g++.dg/cpp0x/lambda/lambda-switch.C > index d71d3ad..ee87def 100644 > --- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-switch.C > +++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-switch.C > @@ -16,11 +16,11 @@ main () > break; // { dg-error "break" } > } > }; > - l = []() > + l = []() // { dg-warning "statement will never be > executed" } > { > case 3: // { dg-error "case" } > break; // { dg-error "break" } > - }; // { dg-warning "statement will never be > executed" } > + }; > } > } > } > diff --git gcc/testsuite/g++.dg/ext/builtin-object-size3.C > gcc/testsuite/g++.dg/ext/builtin-object-size3.C > index 0207f9a..b2a9170 100644 > --- gcc/testsuite/g++.dg/ext/builtin-object-size3.C > +++ gcc/testsuite/g++.dg/ext/builtin-object-size3.C > @@ -3,7 +3,7 @@ > > void baz (int *, int *); > > -#define MEMCPY(d,s,l) __builtin___memcpy_chk (d, s, l, __builtin_object_size > (d, 0)) > +#define MEMCPY(d,s,l) __builtin___memcpy_chk (d, s, l, __builtin_object_size > (d, 0)) // { dg-warning "writing" } > > int > foo () > @@ -20,7 +20,7 @@ bar () > { > int *p = new int; > int *q = new int[4]; > - MEMCPY (p, "abcdefghijklmnopqrstuvwxyz", sizeof (int) + 1); > // { dg-warning "writing" } > - MEMCPY (q, "abcdefghijklmnopqrstuvwxyz", 4 * sizeof (int) + 1); // { > dg-warning "writing" } > + MEMCPY (p, "abcdefghijklmnopqrstuvwxyz", sizeof (int) + 1); // { > dg-message "in expansion of macro" } > + MEMCPY (q, "abcdefghijklmnopqrstuvwxyz", 4 * sizeof (int) + 1); // { > dg-message "in expansion of macro" } > baz (p, q); > } > diff --git gcc/testsuite/g++.dg/gomp/loop-1.C > gcc/testsuite/g++.dg/gomp/loop-1.C > index de08eb3..b3db0f4 100644 > --- gcc/testsuite/g++.dg/gomp/loop-1.C > +++ gcc/testsuite/g++.dg/gomp/loop-1.C > @@ -82,8 +82,8 @@ f1 (int x) > for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression > refers to iteration variable" } */ > ; > #pragma omp for collapse(2) > - for (i = 0; i < 16; i++) /* { dg-error "initializer expression refers to > iteration variable" } */ > - for (j = baz (&i); j < 16; j += 2) > + for (i = 0; i < 16; i++) > + for (j = baz (&i); j < 16; j += 2) /* { dg-error "initializer expression > refers to iteration variable" } */ > ; > #pragma omp for collapse(2) > for (i = 0; i < 16; i++) > @@ -215,8 +215,8 @@ f2 (int x) > for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer > expression refers to iteration variable" } */ > ; > #pragma omp for collapse(2) > - for (int i = 0; i < 16; i++) /* { dg-error "initializer expression refers > to iteration variable" } */ > - for (int j = baz (&i); j < 16; j += 2) > + for (int i = 0; i < 16; i++) > + for (int j = baz (&i); j < 16; j += 2) /* { dg-error "initializer > expression refers to iteration variable" } */ > ; > #pragma omp for collapse(2) > for (int i = 0; i < 16; i++) > diff --git gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C > gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C > index e69de29..7ebd55e 100644 > --- gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C > +++ gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C > @@ -0,0 +1,21 @@ > +// PR c/64279 > +// { dg-do compile } > +// { dg-options "-Wduplicated-branches" } > + > +template <typename T> > +void > +f (char i, int *p) > +{ > + if (i) > + *p = (signed short) i; > + else > + *p = (unsigned short) i; > + > + if (i) // { dg-warning "this condition has identical branches" } > + *p = (T) i; > + else > + *p = (unsigned short) i; > +} > + > +template void f<unsigned short>(char, int *); // { dg-message "required from > here" } > +template void f<signed short>(char, int *); > diff --git gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C > gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C > index e69de29..4da2d54 100644 > --- gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C > +++ gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C > @@ -0,0 +1,8 @@ > +// PR c/6427 > +// { dg-do compile { target c++11 } } > +// { dg-options "-Wduplicated-branches" } > + > +template<typename _ITp> > +struct S { > + static constexpr int i = sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : > alignof(_ITp); > +}; > diff --git gcc/tree-core.h gcc/tree-core.h > index 37a52c3..6a02d28 100644 > --- gcc/tree-core.h > +++ gcc/tree-core.h > @@ -814,7 +814,9 @@ enum operand_equal_flag { > /* Internal within operand_equal_p: */ > OEP_NO_HASH_CHECK = 16, > /* Internal within inchash::add_expr: */ > - OEP_HASH_CHECK = 32 > + OEP_HASH_CHECK = 32, > + /* Makes operand_equal_p handle more expressions: */ > + OEP_LEXICOGRAPHIC = 64 > }; > > /* Enum and arrays used for tree allocation stats. > diff --git gcc/tree.c gcc/tree.c > index 1934301..ddb9152 100644 > --- gcc/tree.c > +++ gcc/tree.c > @@ -7773,7 +7773,7 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned > int flags) > enum tree_code code; > enum tree_code_class tclass; > > - if (t == NULL_TREE) > + if (t == NULL_TREE || t == error_mark_node) > { > hstate.merge_hash (0); > return; > > Marek > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)