re PR c/64279 (Warning missing for "(cond) ? A : A" / if(cond) expr1; else expr1...
authorMarek Polacek <polacek@redhat.com>
Fri, 20 Jan 2017 12:02:50 +0000 (12:02 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Fri, 20 Jan 2017 12:02:50 +0000 (12:02 +0000)
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.

From-SVN: r244705

34 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.h
gcc/c-family/c-gimplify.c
gcc/c-family/c-warn.c
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/semantics.c
gcc/doc/invoke.texi
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wduplicated-branches-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-10.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-11.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-12.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-5.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-6.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-7.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-8.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wduplicated-branches-9.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-switch.C
gcc/testsuite/g++.dg/ext/builtin-object-size3.C
gcc/testsuite/g++.dg/gomp/loop-1.C
gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C [new file with mode: 0644]
gcc/tree-core.h
gcc/tree.c

index b5bb07590ea3e03015cd2df0f501518847bd4470..38eeb5a21b9af9ca23b2609a044f54c72b38bbee 100644 (file)
@@ -1,3 +1,17 @@
+2017-01-20  Marek Polacek  <polacek@redhat.com>
+
+       PR c/64279
+       * 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.
+
 2017-01-20  Martin Liska  <mliska@suse.cz>
 
        PR lto/69188
index 778f8b187f2ba2cd070d828149bdbe7a87d1527b..8d1a61ef8518ab40a0d3e00576b5485b7d74540f 100644 (file)
@@ -1,3 +1,14 @@
+2017-01-20  Marek Polacek  <polacek@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.
+
 2017-01-17  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/71497
index b838869dc252367824e1dc421634d3e1f4638e12..06918dbaf1fb6652a18e0e7c4599f7b39d4cde9a 100644 (file)
@@ -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);
index c327ca7028f1e29d994f6cf5de2ab5764622402b..57edb41af0f08dfb193965213808d852a5ea53c3 100644 (file)
@@ -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)
index 1dbf47e8cd186f9953c75774054769510b3843af..3c9077c5e804a602651dec78525f4883b0ea9087 100644 (file)
@@ -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;
+}
index 3bb42f6d913ec5d8e1c13501c79d97900c6d51d9..a1b3ae5c0b09c95e9ba1bdd34453b7087fd32181 100644 (file)
@@ -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.
index 5b590b33b8ba30a36932f62bc1a718daa124a6c2..18ef3c2e37e083ab7bf59abfa4b046d58d216a10 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-20  Marek Polacek  <polacek@redhat.com>
+
+       PR c/64279
+       * c-typeck.c (build_conditional_expr): Warn about duplicated branches.
+
 2017-01-13  Richard Biener  <rguenther@suse.de>
 
        * gimple-parser.c (c_parser_gimple_compound_statement): Handle
index 96e7351bf4580788ed2383e26d0aec0d2d6c4fae..ed8ffe4c2e7269232b7c1037ab21c3bab66e7022 100644 (file)
@@ -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;
 }
 \f
index bfd898d874bc574a328cdc7a79c99317d00ff625..6554cb7cc753698f6d386afe3ce24097abd9188b 100644 (file)
@@ -1,3 +1,10 @@
+2017-01-20  Marek Polacek  <polacek@redhat.com>
+
+       PR c/64279
+       * call.c (build_conditional_expr_1): Warn about duplicated branches.
+       * semantics.c (finish_expr_stmt): Build statement using the proper
+       location.
+
 2017-01-19  Jason Merrill  <jason@redhat.com>
 
        US 20 - forwarding references and class template argument deduction
index 0059a395ae4474d370b86e1209f8e6e1e61bdba7..a78e1a9c8a2eb4c2fca25e5c7e08b0a78bee6c9b 100644 (file)
@@ -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.  */
 
index 42024755e4f0808a780f486fe8c26ac200d2e3ab..55710e64c97ea1902087ea3b2e6f826954efd9ba 100644 (file)
@@ -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);
        }
 
index a7b494b76e243b9876d040d31504ba0444c4faca..5b96f362c1acba5f6cd4642d6f6358eba15888d1 100644 (file)
@@ -3734,7 +3734,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
@@ -5263,6 +5263,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 identical 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
index cfd270ce83c2c942b06cc35a22169d8ba47f1c2f..5576d592988fdae47a1b77f64bce4cd3057489a9 100644 (file)
@@ -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 with side-effects
+   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;
     }
@@ -13897,7 +13948,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
index 14ca4e90064af37cff0d84a4ee3387351e1fb8dc..201395d9e55a91c47b7d89ec9d3d1030feb52278 100644 (file)
@@ -1,3 +1,25 @@
+2017-01-20  Marek Polacek  <polacek@redhat.com>
+
+       PR c/64279
+       * 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.
+
 2017-01-20  Martin Liska  <mliska@suse.cz>
 
        PR lto/69188
diff --git a/gcc/testsuite/c-c++-common/Wduplicated-branches-1.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-1.c
new file mode 100644 (file)
index 0000000..c0b93fc
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-10.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-10.c
new file mode 100644 (file)
index 0000000..8d918ef
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-11.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-11.c
new file mode 100644 (file)
index 0000000..70d86cf
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-12.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-12.c
new file mode 100644 (file)
index 0000000..cd746f1
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-2.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-2.c
new file mode 100644 (file)
index 0000000..8669dd6
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-3.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-3.c
new file mode 100644 (file)
index 0000000..e188384
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-4.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-4.c
new file mode 100644 (file)
index 0000000..79af549
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-5.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-5.c
new file mode 100644 (file)
index 0000000..f2eb8ec
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-6.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-6.c
new file mode 100644 (file)
index 0000000..0010693
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-7.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-7.c
new file mode 100644 (file)
index 0000000..03721dc
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-8.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-8.c
new file mode 100644 (file)
index 0000000..c5e8ca0
--- /dev/null
@@ -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 a/gcc/testsuite/c-c++-common/Wduplicated-branches-9.c b/gcc/testsuite/c-c++-common/Wduplicated-branches-9.c
new file mode 100644 (file)
index 0000000..9b21776
--- /dev/null
@@ -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" } */
+}
index 21a158ca14faec108dfb7c92e96a8389caad113f..898e5fa6d465f42a8d64cee7cf2039970d46717d 100644 (file)
@@ -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);
     }
index d71d3ade2ace5411f4ce49bef8c6dfc6d6e1af93..ee87defac9f73d20e36a28e36ea55a22eea65ade 100644 (file)
@@ -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" }
+           };
        }
     }
 }
index 0207f9ab667acffae40068dc51791cf789ad58ea..b2a9170fc30ef1e6aea303f70c897cde5717aed6 100644 (file)
@@ -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);
 }
index de08eb3271d85cc1a848cf172f495ac6774c3db6..b3db0f4736b9e752eb39757eee032c75524dfe74 100644 (file)
@@ -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 a/gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C b/gcc/testsuite/g++.dg/warn/Wduplicated-branches1.C
new file mode 100644 (file)
index 0000000..7ebd55e
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C b/gcc/testsuite/g++.dg/warn/Wduplicated-branches2.C
new file mode 100644 (file)
index 0000000..4da2d54
--- /dev/null
@@ -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);
+};
index b7f8b074156af92c9534e6d5fcbfb0d11135a623..2b1759efcb182bf57b80033a4cc7f1af4dbf22eb 100644 (file)
@@ -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.
index 59fe8d4aff4d8ba951be77326baf2755cc97d6f2..7127bd265de63a37a179b8fd804b42f953e549b5 100644 (file)
@@ -7776,7 +7776,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;