public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Implement -Wduplicated-branches (PR c/64279)
@ 2016-10-19 11:07 Marek Polacek
  2016-10-20 10:28 ` Marek Polacek
                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Marek Polacek @ 2016-10-19 11:07 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jason Merrill, Joseph Myers

This patch introduces a new warning, -Wduplicated-branches.  Its purpose is
to warn for code such as

  if (cond)
    return 0;
  else
    return 0;

as well as e.g.

  r = i ? *p : *p;

The approach I took was to use inchash::add_expr to hash the expressions
and then compare the hashes.  But of course nothing's that easy.  The
warning should stay quiet for various macro usages so I've introduced
expr_from_macro_expansion_r.  But since integer csts and various decls
don't carry location info, this works only partially, so the warning
warns even for e.g.

  if (TREE_STATIC (node) || DECL_EXTERNAL (node))
    max_align = MAX_OFILE_ALIGNMENT;
  else
    max_align = MAX_STACK_ALIGNMENT;

when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the same number.
There's no way to get around this, so the warning isn't enabled by nor
-Wall neither -Wextra, and can't be until we solve the pesky location
horror.  (-Wduplicated-cond is off for the very same reason.)

add_expr didn't handle error_mark_node that can get there from the FEs
(an undeclared variable, etc.), so that's why the change.  But maybe
it'd be better to walk the tree in do_warn_duplicated_branches, and if
if sees an error node, don't attempt to hash the expr.

Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?

2016-10-19  Marek Polacek  <polacek@redhat.com>

	PR c/64279
	* c-common.h (do_warn_duplicated_branches_r,
	do_warn_duplicated_branches): 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 (fold_build_cleanup_point_expr): Use the expression
	location when building CLEANUP_POINT_EXPR.
	* tree.c (add_expr): Handle error_mark_node.

	* c-c++-common/Wduplicated-branches-1.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 (bar): Likewise.
	* g++.dg/gomp/loop-1.C: Likewise.
	* g++.dg/warn/Wduplicated-branches1.C: New test.

diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index bfdbda0..644447e 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -1530,6 +1530,8 @@ 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 *);
+extern void do_warn_duplicated_branches (tree);
 
 /* 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 c18b057..3ed2da8 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 904f6d3..f6e8e71 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -2154,3 +2154,67 @@ maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
 		    "with boolean expression is always false", cst);
     }
 }
+
+/* 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.  */
+
+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;
+
+  /* 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
+      /* 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 82c992c..ad18288 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -434,6 +434,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 f0917ed..6b5056e 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -5162,6 +5162,14 @@ 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
+      && !TREE_SIDE_EFFECTS (op1))
+    do_warn_duplicated_branches (ret);
+
   return ret;
 }
 \f
diff --git gcc/cp/call.c gcc/cp/call.c
index 4c19d2f..f5dec85 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -5234,6 +5234,11 @@ 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 && !TREE_SIDE_EFFECTS (arg2))
+    do_warn_duplicated_branches (result);
+
   /* 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 968f88b..08ae726 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 795ad1b..7089045 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -265,8 +265,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
--Wempty-body  -Wenum-compare -Wno-endif-labels @gol
+-Wno-div-by-zero -Wdouble-promotion -Wduplicated-branches @gol
+-Wduplicated-cond  -Wempty-body  -Wenum-compare -Wno-endif-labels @gol
 -Werror  -Werror=* -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol
 -Wformat-nonliteral @gol
@@ -3673,7 +3673,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
@@ -5020,6 +5020,18 @@ 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.
+
 @item -Wduplicated-cond
 @opindex Wno-duplicated-cond
 @opindex Wduplicated-cond
diff --git gcc/fold-const.c gcc/fold-const.c
index 89ed89d..ec0c990 100644
--- gcc/fold-const.c
+++ gcc/fold-const.c
@@ -14014,7 +14014,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-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..0aaf9e7 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;
+  *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 09263e5..aec3b7ce 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 "will always overflow destination buffer" }
 
 int
 foo ()
@@ -20,7 +20,7 @@ bar ()
 {
   int *p = new int;
   int *q = new int[4];
-  MEMCPY (p, "abcdefghijklmnopqrstuvwxyz", sizeof (int) + 1);		// { dg-warning "will always overflow destination buffer" }
-  MEMCPY (q, "abcdefghijklmnopqrstuvwxyz", 4 * sizeof (int) + 1);	// { dg-warning "will always overflow destination buffer" }
+  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/tree.c gcc/tree.c
index 30d4373..2f586ff 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -7754,7 +7754,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

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-19 11:07 Implement -Wduplicated-branches (PR c/64279) Marek Polacek
@ 2016-10-20 10:28 ` Marek Polacek
  2016-10-24 14:10   ` Implement -Wduplicated-branches (PR c/64279) (v2) Marek Polacek
  2016-10-20 14:12 ` Implement -Wduplicated-branches (PR c/64279) Jason Merrill
  2016-10-20 20:21 ` Martin Sebor
  2 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-20 10:28 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jason Merrill, Joseph Myers

I found a problem with this patch--we can't call do_warn_duplicated_branches in
build_conditional_expr, because that way the C++-specific codes might leak into
the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
that part of the patch.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-19 11:07 Implement -Wduplicated-branches (PR c/64279) Marek Polacek
  2016-10-20 10:28 ` Marek Polacek
@ 2016-10-20 14:12 ` Jason Merrill
  2016-10-20 14:24   ` Marek Polacek
  2016-10-20 20:21 ` Martin Sebor
  2 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2016-10-20 14:12 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Joseph Myers

On Wed, Oct 19, 2016 at 7:07 AM, Marek Polacek <polacek@redhat.com> wrote:
> But since integer csts and various decls
> don't carry location info, this works only partially, so the warning
> warns even for e.g.
>
>   if (TREE_STATIC (node) || DECL_EXTERNAL (node))
>     max_align = MAX_OFILE_ALIGNMENT;
>   else
>     max_align = MAX_STACK_ALIGNMENT;
>
> when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the same number.
> There's no way to get around this, so the warning isn't enabled by nor
> -Wall neither -Wextra, and can't be until we solve the pesky location
> horror.  (-Wduplicated-cond is off for the very same reason.)

Is someone working on this?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-20 14:12 ` Implement -Wduplicated-branches (PR c/64279) Jason Merrill
@ 2016-10-20 14:24   ` Marek Polacek
  2016-10-20 14:37     ` David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-20 14:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Joseph Myers, David Malcolm

On Thu, Oct 20, 2016 at 10:11:55AM -0400, Jason Merrill wrote:
> On Wed, Oct 19, 2016 at 7:07 AM, Marek Polacek <polacek@redhat.com> wrote:
> > But since integer csts and various decls
> > don't carry location info, this works only partially, so the warning
> > warns even for e.g.
> >
> >   if (TREE_STATIC (node) || DECL_EXTERNAL (node))
> >     max_align = MAX_OFILE_ALIGNMENT;
> >   else
> >     max_align = MAX_STACK_ALIGNMENT;
> >
> > when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the same number.
> > There's no way to get around this, so the warning isn't enabled by nor
> > -Wall neither -Wextra, and can't be until we solve the pesky location
> > horror.  (-Wduplicated-cond is off for the very same reason.)
> 
> Is someone working on this?

Not me, but I think David has been experimenting with this.  David, is that
correct?

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-20 14:24   ` Marek Polacek
@ 2016-10-20 14:37     ` David Malcolm
  2016-10-20 18:56       ` Jeff Law
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2016-10-20 14:37 UTC (permalink / raw)
  To: Marek Polacek, Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Joseph Myers

On Thu, 2016-10-20 at 16:24 +0200, Marek Polacek wrote:
> On Thu, Oct 20, 2016 at 10:11:55AM -0400, Jason Merrill wrote:
> > On Wed, Oct 19, 2016 at 7:07 AM, Marek Polacek <polacek@redhat.com>
> > wrote:
> > > But since integer csts and various decls
> > > don't carry location info, this works only partially, so the
> > > warning
> > > warns even for e.g.
> > > 
> > >   if (TREE_STATIC (node) || DECL_EXTERNAL (node))
> > >     max_align = MAX_OFILE_ALIGNMENT;
> > >   else
> > >     max_align = MAX_STACK_ALIGNMENT;
> > > 
> > > when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the
> > > same number.
> > > There's no way to get around this, so the warning isn't enabled
> > > by nor
> > > -Wall neither -Wextra, and can't be until we solve the pesky
> > > location
> > > horror.  (-Wduplicated-cond is off for the very same reason.)
> > 
> > Is someone working on this?
> 
> Not me, but I think David has been experimenting with this.  David,
> is that
> correct?

I started looking at this, but it's unlikely that I'll have something
ready for gcc 7 (have been focusing on the RTL frontend).



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-20 14:37     ` David Malcolm
@ 2016-10-20 18:56       ` Jeff Law
  2016-10-24 14:03         ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jeff Law @ 2016-10-20 18:56 UTC (permalink / raw)
  To: David Malcolm, Marek Polacek, Jason Merrill
  Cc: GCC Patches, Jakub Jelinek, Joseph Myers

On 10/20/2016 08:37 AM, David Malcolm wrote:
> On Thu, 2016-10-20 at 16:24 +0200, Marek Polacek wrote:
>> On Thu, Oct 20, 2016 at 10:11:55AM -0400, Jason Merrill wrote:
>>> On Wed, Oct 19, 2016 at 7:07 AM, Marek Polacek <polacek@redhat.com>
>>> wrote:
>>>> But since integer csts and various decls
>>>> don't carry location info, this works only partially, so the
>>>> warning
>>>> warns even for e.g.
>>>>
>>>>   if (TREE_STATIC (node) || DECL_EXTERNAL (node))
>>>>     max_align = MAX_OFILE_ALIGNMENT;
>>>>   else
>>>>     max_align = MAX_STACK_ALIGNMENT;
>>>>
>>>> when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the
>>>> same number.
>>>> There's no way to get around this, so the warning isn't enabled
>>>> by nor
>>>> -Wall neither -Wextra, and can't be until we solve the pesky
>>>> location
>>>> horror.  (-Wduplicated-cond is off for the very same reason.)
>>>
>>> Is someone working on this?
>>
>> Not me, but I think David has been experimenting with this.  David,
>> is that
>> correct?
>
> I started looking at this, but it's unlikely that I'll have something
> ready for gcc 7 (have been focusing on the RTL frontend).
Right.  David and I have kicked around some ideas on how we might get to 
a point where constants and decls can carry location information, but we 
agreed that it wasn't likely gcc-7 material.

So the question in my mind is does the warning make sense given we can't 
current disambiguate constants and thus are likely generating a goodly 
number of false positives.

[ Presumably it was good enough to catch the duplicated branch code Jon 
pointed out in tree-ssa-threadupdate.c recently?  Any other real bugs
flagged? ]

jeff

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-19 11:07 Implement -Wduplicated-branches (PR c/64279) Marek Polacek
  2016-10-20 10:28 ` Marek Polacek
  2016-10-20 14:12 ` Implement -Wduplicated-branches (PR c/64279) Jason Merrill
@ 2016-10-20 20:21 ` Martin Sebor
  2016-10-24 13:59   ` Marek Polacek
  2 siblings, 1 reply; 34+ messages in thread
From: Martin Sebor @ 2016-10-20 20:21 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches; +Cc: Jakub Jelinek, Jason Merrill, Joseph Myers

> --- 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;
> +    }

I wonder if this test case (perhaps with a slight modification)
illustrates the concern Jeff raised.  Suppose j is an argument
to the function whose value of zero is determined by constant
propagation.  Such code is not uncommon but will presumably be
diagnosed, which in all likelihood will be considered a false
positive.  I don't have a sense of how pervasive such cases
might be.  Do you have any data from projects other than GCC?
(Since there are no fixes in the patch I assume it didn't find
any bugs in GCC itself.)

Martin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-20 20:21 ` Martin Sebor
@ 2016-10-24 13:59   ` Marek Polacek
  2016-10-24 14:18     ` Martin Sebor
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-24 13:59 UTC (permalink / raw)
  To: Martin Sebor; +Cc: GCC Patches, Jakub Jelinek, Jason Merrill, Joseph Myers

On Thu, Oct 20, 2016 at 02:21:42PM -0600, Martin Sebor wrote:
> > --- 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;
> > +    }
> 
> I wonder if this test case (perhaps with a slight modification)
> illustrates the concern Jeff raised.  Suppose j is an argument
> to the function whose value of zero is determined by constant
> propagation.  Such code is not uncommon but will presumably be
> diagnosed, which in all likelihood will be considered a false
> positive.  I don't have a sense of how pervasive such cases
> might be.  Do you have any data from projects other than GCC?
> (Since there are no fixes in the patch I assume it didn't find
> any bugs in GCC itself.)

The case above is just a case where with -O GCC can figure out what the value
of a const-qualified variable is, see decl_constant_value_for_optimization.
Since the warning is implemented even before gimplifying, optimizations like
CP don't come into play yet.

I don't have data from anything else than GCC itself.  It hasn't found any
bugs in GCC (yet), but the codebase was recently scanned by the PVS tool
and the bugs were fixed.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-20 18:56       ` Jeff Law
@ 2016-10-24 14:03         ` Marek Polacek
  0 siblings, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2016-10-24 14:03 UTC (permalink / raw)
  To: Jeff Law
  Cc: David Malcolm, Jason Merrill, GCC Patches, Jakub Jelinek, Joseph Myers

On Thu, Oct 20, 2016 at 12:56:12PM -0600, Jeff Law wrote:
> On 10/20/2016 08:37 AM, David Malcolm wrote:
> > On Thu, 2016-10-20 at 16:24 +0200, Marek Polacek wrote:
> > > On Thu, Oct 20, 2016 at 10:11:55AM -0400, Jason Merrill wrote:
> > > > On Wed, Oct 19, 2016 at 7:07 AM, Marek Polacek <polacek@redhat.com>
> > > > wrote:
> > > > > But since integer csts and various decls
> > > > > don't carry location info, this works only partially, so the
> > > > > warning
> > > > > warns even for e.g.
> > > > > 
> > > > >   if (TREE_STATIC (node) || DECL_EXTERNAL (node))
> > > > >     max_align = MAX_OFILE_ALIGNMENT;
> > > > >   else
> > > > >     max_align = MAX_STACK_ALIGNMENT;
> > > > > 
> > > > > when MAX_OFILE_ALIGNMENT and MAX_STACK_ALIGNMENT represent the
> > > > > same number.
> > > > > There's no way to get around this, so the warning isn't enabled
> > > > > by nor
> > > > > -Wall neither -Wextra, and can't be until we solve the pesky
> > > > > location
> > > > > horror.  (-Wduplicated-cond is off for the very same reason.)
> > > > 
> > > > Is someone working on this?
> > > 
> > > Not me, but I think David has been experimenting with this.  David,
> > > is that
> > > correct?
> > 
> > I started looking at this, but it's unlikely that I'll have something
> > ready for gcc 7 (have been focusing on the RTL frontend).
> Right.  David and I have kicked around some ideas on how we might get to a
> point where constants and decls can carry location information, but we
> agreed that it wasn't likely gcc-7 material.
> 
> So the question in my mind is does the warning make sense given we can't
> current disambiguate constants and thus are likely generating a goodly
> number of false positives.

That's the question.  It certainly can't be in -Wall/-Wextra given the
macro problem, but that is also true for other warnings.  Maybe it makes
sense to add it all the same so that people can experiment with it.

> [ Presumably it was good enough to catch the duplicated branch code Jon
> pointed out in tree-ssa-threadupdate.c recently?  Any other real bugs
> flagged? ]

Yeah, it would've found it.  I haven't found any other clear bugs yet.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v2)
  2016-10-20 10:28 ` Marek Polacek
@ 2016-10-24 14:10   ` Marek Polacek
  2016-10-25 13:59     ` Implement -Wduplicated-branches (PR c/64279) (v3) Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-24 14:10 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jason Merrill, Joseph Myers

On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> I found a problem with this patch--we can't call do_warn_duplicated_branches in
> build_conditional_expr, because that way the C++-specific codes might leak into
> the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> that part of the patch.

Thus:

Bootstrapped/regtested on x86_64-linux.

2016-10-24  Marek Polacek  <polacek@redhat.com>

	PR c/64279
	* c-common.h (do_warn_duplicated_branches_r,
	do_warn_duplicated_branches): 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 (fold_build_cleanup_point_expr): Use the expression
	location when building CLEANUP_POINT_EXPR.
	* tree.c (add_expr): Handle error_mark_node.

	* c-c++-common/Wduplicated-branches-1.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 (bar): 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 bfdbda0..e48f69b 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -1530,6 +1530,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 c18b057..3ed2da8 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 904f6d3..fda9b66 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -2154,3 +2154,67 @@ maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
 		    "with boolean expression is always false", cst);
     }
 }
+
+/* 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;
+
+  /* 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
+      /* 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 458d453..035dc68 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -444,6 +444,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 f0917ed..0056088 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -5162,6 +5162,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
diff --git gcc/cp/call.c gcc/cp/call.c
index 4c19d2f..82db79f 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -5234,6 +5234,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 968f88b..08ae726 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 9f57d52..c55a104 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -266,8 +266,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
--Wempty-body  -Wenum-compare -Wno-endif-labels @gol
+-Wno-div-by-zero -Wdouble-promotion -Wduplicated-branches @gol
+-Wduplicated-cond  -Wempty-body  -Wenum-compare -Wno-endif-labels @gol
 -Werror  -Werror=* -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol
 -Wformat-nonliteral @gol
@@ -3674,7 +3674,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
@@ -5088,6 +5088,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 89ed89d..ec0c990 100644
--- gcc/fold-const.c
+++ gcc/fold-const.c
@@ -14014,7 +14014,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-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 09263e5..aec3b7ce 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 "will always overflow destination buffer" }
 
 int
 foo ()
@@ -20,7 +20,7 @@ bar ()
 {
   int *p = new int;
   int *q = new int[4];
-  MEMCPY (p, "abcdefghijklmnopqrstuvwxyz", sizeof (int) + 1);		// { dg-warning "will always overflow destination buffer" }
-  MEMCPY (q, "abcdefghijklmnopqrstuvwxyz", 4 * sizeof (int) + 1);	// { dg-warning "will always overflow destination buffer" }
+  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.c gcc/tree.c
index 30d4373..2f586ff 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -7754,7 +7754,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

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-24 13:59   ` Marek Polacek
@ 2016-10-24 14:18     ` Martin Sebor
  2016-10-24 14:35       ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Martin Sebor @ 2016-10-24 14:18 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jason Merrill, Joseph Myers

On 10/24/2016 07:59 AM, Marek Polacek wrote:
> On Thu, Oct 20, 2016 at 02:21:42PM -0600, Martin Sebor wrote:
>>> --- 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;
>>> +    }
>>
>> I wonder if this test case (perhaps with a slight modification)
>> illustrates the concern Jeff raised.  Suppose j is an argument
>> to the function whose value of zero is determined by constant
>> propagation.  Such code is not uncommon but will presumably be
>> diagnosed, which in all likelihood will be considered a false
>> positive.  I don't have a sense of how pervasive such cases
>> might be.  Do you have any data from projects other than GCC?
>> (Since there are no fixes in the patch I assume it didn't find
>> any bugs in GCC itself.)
>
> The case above is just a case where with -O GCC can figure out what the value
> of a const-qualified variable is, see decl_constant_value_for_optimization.
> Since the warning is implemented even before gimplifying, optimizations like
> CP don't come into play yet.

Ah, okay.  That should limit the number of these false positives.
(I saw -O2 in dg-options and assumed it was important.  It sounds
like the test case should pass even with -O1).

But even without constant propagation there will be similar cases
(though probably less pervasive).  For instance, if j were defined
to something like this:

   const int j = 4 == sizeof (size_t);

Martin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-24 14:18     ` Martin Sebor
@ 2016-10-24 14:35       ` Marek Polacek
  2016-10-24 14:39         ` Jakub Jelinek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-24 14:35 UTC (permalink / raw)
  To: Martin Sebor; +Cc: GCC Patches, Jakub Jelinek, Jason Merrill, Joseph Myers

On Mon, Oct 24, 2016 at 08:18:25AM -0600, Martin Sebor wrote:
> > The case above is just a case where with -O GCC can figure out what the value
> > of a const-qualified variable is, see decl_constant_value_for_optimization.
> > Since the warning is implemented even before gimplifying, optimizations like
> > CP don't come into play yet.
> 
> Ah, okay.  That should limit the number of these false positives.
> (I saw -O2 in dg-options and assumed it was important.  It sounds
> like the test case should pass even with -O1).
 
Yep--even -O is enough.

> But even without constant propagation there will be similar cases
> (though probably less pervasive).  For instance, if j were defined
> to something like this:
> 
>   const int j = 4 == sizeof (size_t);

Well, I think the warning would still be desirable:

  const int j = 4 == sizeof (long);
  if (j == 0)
    {   
      if (i > 10) /* { dg-warning "this condition has identical branches" } */
        *p = j * 2 + 1;
      else
        *p = 1;
    }

Given the j == 0 check, the branches really are duplicated.  This is actually
a distilled version of what I found in gcov-io.c.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-24 14:35       ` Marek Polacek
@ 2016-10-24 14:39         ` Jakub Jelinek
  2016-10-24 14:44           ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jakub Jelinek @ 2016-10-24 14:39 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Martin Sebor, GCC Patches, Jason Merrill, Joseph Myers

On Mon, Oct 24, 2016 at 04:34:40PM +0200, Marek Polacek wrote:
> On Mon, Oct 24, 2016 at 08:18:25AM -0600, Martin Sebor wrote:
> > > The case above is just a case where with -O GCC can figure out what the value
> > > of a const-qualified variable is, see decl_constant_value_for_optimization.
> > > Since the warning is implemented even before gimplifying, optimizations like
> > > CP don't come into play yet.
> > 
> > Ah, okay.  That should limit the number of these false positives.
> > (I saw -O2 in dg-options and assumed it was important.  It sounds
> > like the test case should pass even with -O1).
>  
> Yep--even -O is enough.
> 
> > But even without constant propagation there will be similar cases
> > (though probably less pervasive).  For instance, if j were defined
> > to something like this:
> > 
> >   const int j = 4 == sizeof (size_t);
> 
> Well, I think the warning would still be desirable:
> 
>   const int j = 4 == sizeof (long);
>   if (j == 0)
>     {   
>       if (i > 10) /* { dg-warning "this condition has identical branches" } */
>         *p = j * 2 + 1;
>       else
>         *p = 1;
>     }
> 
> Given the j == 0 check, the branches really are duplicated.  This is actually
> a distilled version of what I found in gcov-io.c.

Are you hashing before folding or after folding?
If before folding, you wouldn't complain about the gcov-io.c test.
With folding, one can imagine something like:
  const int a = sizeof (long);
  const int b = sizeof (long long);
  int c;
  if (cond)
    c = a;
  else
    c = b;
or similar, where a and b can be the same on some targets and different on
others.  I believe the warning is still useful, but it will probably be
never false positive free.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-24 14:39         ` Jakub Jelinek
@ 2016-10-24 14:44           ` Marek Polacek
  2016-10-24 14:59             ` Martin Sebor
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-24 14:44 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Martin Sebor, GCC Patches, Jason Merrill, Joseph Myers

On Mon, Oct 24, 2016 at 04:39:20PM +0200, Jakub Jelinek wrote:
> On Mon, Oct 24, 2016 at 04:34:40PM +0200, Marek Polacek wrote:
> > On Mon, Oct 24, 2016 at 08:18:25AM -0600, Martin Sebor wrote:
> > > > The case above is just a case where with -O GCC can figure out what the value
> > > > of a const-qualified variable is, see decl_constant_value_for_optimization.
> > > > Since the warning is implemented even before gimplifying, optimizations like
> > > > CP don't come into play yet.
> > > 
> > > Ah, okay.  That should limit the number of these false positives.
> > > (I saw -O2 in dg-options and assumed it was important.  It sounds
> > > like the test case should pass even with -O1).
> >  
> > Yep--even -O is enough.
> > 
> > > But even without constant propagation there will be similar cases
> > > (though probably less pervasive).  For instance, if j were defined
> > > to something like this:
> > > 
> > >   const int j = 4 == sizeof (size_t);
> > 
> > Well, I think the warning would still be desirable:
> > 
> >   const int j = 4 == sizeof (long);
> >   if (j == 0)
> >     {   
> >       if (i > 10) /* { dg-warning "this condition has identical branches" } */
> >         *p = j * 2 + 1;
> >       else
> >         *p = 1;
> >     }
> > 
> > Given the j == 0 check, the branches really are duplicated.  This is actually
> > a distilled version of what I found in gcov-io.c.
> 
> Are you hashing before folding or after folding?

After, e.g. I think build_modify_expr c_fully_fold operands.

> If before folding, you wouldn't complain about the gcov-io.c test.
> With folding, one can imagine something like:
>   const int a = sizeof (long);
>   const int b = sizeof (long long);
>   int c;
>   if (cond)
>     c = a;
>   else
>     c = b;
> or similar, where a and b can be the same on some targets and different on
> others.  I believe the warning is still useful, but it will probably be
> never false positive free.

Unfortunately :(.  Maybe tolerable for -Wextra, though.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279)
  2016-10-24 14:44           ` Marek Polacek
@ 2016-10-24 14:59             ` Martin Sebor
  0 siblings, 0 replies; 34+ messages in thread
From: Martin Sebor @ 2016-10-24 14:59 UTC (permalink / raw)
  To: Marek Polacek, Jakub Jelinek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

On 10/24/2016 08:44 AM, Marek Polacek wrote:
> On Mon, Oct 24, 2016 at 04:39:20PM +0200, Jakub Jelinek wrote:
>> On Mon, Oct 24, 2016 at 04:34:40PM +0200, Marek Polacek wrote:
>>> On Mon, Oct 24, 2016 at 08:18:25AM -0600, Martin Sebor wrote:
>>>>> The case above is just a case where with -O GCC can figure out what the value
>>>>> of a const-qualified variable is, see decl_constant_value_for_optimization.
>>>>> Since the warning is implemented even before gimplifying, optimizations like
>>>>> CP don't come into play yet.
>>>>
>>>> Ah, okay.  That should limit the number of these false positives.
>>>> (I saw -O2 in dg-options and assumed it was important.  It sounds
>>>> like the test case should pass even with -O1).
>>>
>>> Yep--even -O is enough.
>>>
>>>> But even without constant propagation there will be similar cases
>>>> (though probably less pervasive).  For instance, if j were defined
>>>> to something like this:
>>>>
>>>>   const int j = 4 == sizeof (size_t);
>>>
>>> Well, I think the warning would still be desirable:
>>>
>>>   const int j = 4 == sizeof (long);
>>>   if (j == 0)
>>>     {
>>>       if (i > 10) /* { dg-warning "this condition has identical branches" } */
>>>         *p = j * 2 + 1;
>>>       else
>>>         *p = 1;
>>>     }
>>>
>>> Given the j == 0 check, the branches really are duplicated.  This is actually
>>> a distilled version of what I found in gcov-io.c.
>>
>> Are you hashing before folding or after folding?
>
> After, e.g. I think build_modify_expr c_fully_fold operands.
>
>> If before folding, you wouldn't complain about the gcov-io.c test.
>> With folding, one can imagine something like:
>>   const int a = sizeof (long);
>>   const int b = sizeof (long long);
>>   int c;
>>   if (cond)
>>     c = a;
>>   else
>>     c = b;
>> or similar, where a and b can be the same on some targets and different on
>> others.  I believe the warning is still useful, but it will probably be
>> never false positive free.
>
> Unfortunately :(.  Maybe tolerable for -Wextra, though.

That's why I wondered about data.  I've seen examples like the one
above but it's hard to judge how common they are and what their
overall proportion is among all code like that where the warning
would be justified.  But to be clear, I don't raise this to suggest
the warning shouldn't be added or is never useful but rather in
hopes that the data might lead to insights into how to reduce the
false positive rate (if it's even a problem).  For instance, I
imagine it should be fairly easy to avoid warning on the simple
example above.

Martin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-10-24 14:10   ` Implement -Wduplicated-branches (PR c/64279) (v2) Marek Polacek
@ 2016-10-25 13:59     ` Marek Polacek
  2016-11-01 13:41       ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-10-25 13:59 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jason Merrill, Joseph Myers

On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
> > build_conditional_expr, because that way the C++-specific codes might leak into
> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> > that part of the patch.
> 
> Thus:

And one more thing, let's not warn for if { } else { }, either.
Thanks Tobias for testing.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-10-25  Marek Polacek  <polacek@redhat.com>

	PR c/64279
	* c-common.h (do_warn_duplicated_branches_r,
	do_warn_duplicated_branches): 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 (fold_build_cleanup_point_expr): Use the expression
	location when building CLEANUP_POINT_EXPR.
	* tree.c (add_expr): Handle error_mark_node.

	* c-c++-common/Wduplicated-branches-1.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/Wduplicated-branches-10.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 (bar): 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 547bab2..46e9d2e 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -1530,6 +1530,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 c18b057..3ed2da8 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 904f6d3..433f5c3 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -2154,3 +2154,72 @@ maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
 		    "with boolean expression is always false", cst);
     }
 }
+
+/* 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
+      /* 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 458d453..035dc68 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -444,6 +444,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 f0917ed..0056088 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -5162,6 +5162,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
diff --git gcc/cp/call.c gcc/cp/call.c
index 4c19d2f..82db79f 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -5234,6 +5234,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 1a7c478..19e7c07 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 5ccd424..ec01256 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -266,8 +266,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
--Wempty-body  -Wenum-compare -Wno-endif-labels @gol
+-Wno-div-by-zero -Wdouble-promotion -Wduplicated-branches @gol
+-Wduplicated-cond  -Wempty-body  -Wenum-compare -Wno-endif-labels @gol
 -Werror  -Werror=* -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-length=@var{n} @gol
 -Wformat-nonliteral @gol
@@ -3674,7 +3674,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
@@ -5088,6 +5088,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 89ed89d..ec0c990 100644
--- gcc/fold-const.c
+++ gcc/fold-const.c
@@ -14014,7 +14014,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-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 09263e5..aec3b7ce 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 "will always overflow destination buffer" }
 
 int
 foo ()
@@ -20,7 +20,7 @@ bar ()
 {
   int *p = new int;
   int *q = new int[4];
-  MEMCPY (p, "abcdefghijklmnopqrstuvwxyz", sizeof (int) + 1);		// { dg-warning "will always overflow destination buffer" }
-  MEMCPY (q, "abcdefghijklmnopqrstuvwxyz", 4 * sizeof (int) + 1);	// { dg-warning "will always overflow destination buffer" }
+  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.c gcc/tree.c
index 30d4373..2f586ff 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -7754,7 +7754,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

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-10-25 13:59     ` Implement -Wduplicated-branches (PR c/64279) (v3) Marek Polacek
@ 2016-11-01 13:41       ` Jason Merrill
  2016-11-01 13:54         ` Jakub Jelinek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2016-11-01 13:41 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Joseph Myers

On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
>> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
>> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
>> > build_conditional_expr, because that way the C++-specific codes might leak into
>> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
>> > that part of the patch.

Hmm, is there a reason not to use operand_equal_p for
do_warn_duplicated_branches as well?  I'm concerned about hash
collisions leading to false positives.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-01 13:41       ` Jason Merrill
@ 2016-11-01 13:54         ` Jakub Jelinek
  2016-11-03 11:24           ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jakub Jelinek @ 2016-11-01 13:54 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Marek Polacek, GCC Patches, Joseph Myers

On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
> On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
> >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> >> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
> >> > build_conditional_expr, because that way the C++-specific codes might leak into
> >> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> >> > that part of the patch.
> 
> Hmm, is there a reason not to use operand_equal_p for
> do_warn_duplicated_branches as well?  I'm concerned about hash
> collisions leading to false positives.

If the hashing function is iterative_hash_expr / inchash::add_expr, then
that is supposed to pair together with operand_equal_p, we even have
checking verification of that.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-01 13:54         ` Jakub Jelinek
@ 2016-11-03 11:24           ` Marek Polacek
  2016-11-03 13:28             ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2016-11-03 11:24 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, GCC Patches, Joseph Myers

On Tue, Nov 01, 2016 at 02:53:58PM +0100, Jakub Jelinek wrote:
> On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
> > On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
> > >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> > >> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
> > >> > build_conditional_expr, because that way the C++-specific codes might leak into
> > >> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> > >> > that part of the patch.
> > 
> > Hmm, is there a reason not to use operand_equal_p for
> > do_warn_duplicated_branches as well?  I'm concerned about hash
> > collisions leading to false positives.
> 
> If the hashing function is iterative_hash_expr / inchash::add_expr, then
> that is supposed to pair together with operand_equal_p, we even have
> checking verification of that.

Yes, I use inchash::add_expr.

So any opinions as to what to do with this patch?

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-03 11:24           ` Marek Polacek
@ 2016-11-03 13:28             ` Jason Merrill
  2016-11-03 13:38               ` Jakub Jelinek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2016-11-03 13:28 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jakub Jelinek, GCC Patches, Joseph Myers

On Thu, Nov 3, 2016 at 7:24 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Nov 01, 2016 at 02:53:58PM +0100, Jakub Jelinek wrote:
>> On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
>> > On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
>> > >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
>> > >> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
>> > >> > build_conditional_expr, because that way the C++-specific codes might leak into
>> > >> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
>> > >> > that part of the patch.
>> >
>> > Hmm, is there a reason not to use operand_equal_p for
>> > do_warn_duplicated_branches as well?  I'm concerned about hash
>> > collisions leading to false positives.
>>
>> If the hashing function is iterative_hash_expr / inchash::add_expr, then
>> that is supposed to pair together with operand_equal_p, we even have
>> checking verification of that.

Yes, but there could still be hash collisions; we can't guarantee that
everything that compares unequal also hashes unequal.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-03 13:28             ` Jason Merrill
@ 2016-11-03 13:38               ` Jakub Jelinek
  2017-01-04  6:49                 ` Eric Gallager
  2017-01-05 15:39                 ` Marek Polacek
  0 siblings, 2 replies; 34+ messages in thread
From: Jakub Jelinek @ 2016-11-03 13:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Marek Polacek, GCC Patches, Joseph Myers

On Thu, Nov 03, 2016 at 09:27:55AM -0400, Jason Merrill wrote:
> On Thu, Nov 3, 2016 at 7:24 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Tue, Nov 01, 2016 at 02:53:58PM +0100, Jakub Jelinek wrote:
> >> On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
> >> > On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> >> > > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
> >> > >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> >> > >> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
> >> > >> > build_conditional_expr, because that way the C++-specific codes might leak into
> >> > >> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> >> > >> > that part of the patch.
> >> >
> >> > Hmm, is there a reason not to use operand_equal_p for
> >> > do_warn_duplicated_branches as well?  I'm concerned about hash
> >> > collisions leading to false positives.
> >>
> >> If the hashing function is iterative_hash_expr / inchash::add_expr, then
> >> that is supposed to pair together with operand_equal_p, we even have
> >> checking verification of that.
> 
> Yes, but there could still be hash collisions; we can't guarantee that
> everything that compares unequal also hashes unequal.

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.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-03 13:38               ` Jakub Jelinek
@ 2017-01-04  6:49                 ` Eric Gallager
  2017-01-05 15:39                 ` Marek Polacek
  1 sibling, 0 replies; 34+ messages in thread
From: Eric Gallager @ 2017-01-04  6:49 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Marek Polacek, GCC Patches, Joseph Myers

On 11/3/16, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Nov 03, 2016 at 09:27:55AM -0400, Jason Merrill wrote:
>> On Thu, Nov 3, 2016 at 7:24 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Tue, Nov 01, 2016 at 02:53:58PM +0100, Jakub Jelinek wrote:
>> >> On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
>> >> > On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com>
>> >> > wrote:
>> >> > > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
>> >> > >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
>> >> > >> > I found a problem with this patch--we can't call
>> >> > >> > do_warn_duplicated_branches in
>> >> > >> > build_conditional_expr, because that way the C++-specific codes
>> >> > >> > might leak into
>> >> > >> > the hasher.  Instead, I should use operand_equal_p, I think.
>> >> > >> > Let me rework
>> >> > >> > that part of the patch.
>> >> >
>> >> > Hmm, is there a reason not to use operand_equal_p for
>> >> > do_warn_duplicated_branches as well?  I'm concerned about hash
>> >> > collisions leading to false positives.
>> >>
>> >> If the hashing function is iterative_hash_expr / inchash::add_expr,
>> >> then
>> >> that is supposed to pair together with operand_equal_p, we even have
>> >> checking verification of that.
>>
>> Yes, but there could still be hash collisions; we can't guarantee that
>> everything that compares unequal also hashes unequal.
>
> 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.
>
> 	Jakub
>

Pinging this conversation for the new year. Any chances of
-Wduplicated-branches making it in in time for GCC 7?

Thanks,
Eric

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2016-11-03 13:38               ` Jakub Jelinek
  2017-01-04  6:49                 ` Eric Gallager
@ 2017-01-05 15:39                 ` Marek Polacek
  2017-01-05 15:41                   ` Jakub Jelinek
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2017-01-05 15:39 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, GCC Patches, Joseph Myers

Coming back to this...

On Thu, Nov 03, 2016 at 02:38:50PM +0100, Jakub Jelinek wrote:
> On Thu, Nov 03, 2016 at 09:27:55AM -0400, Jason Merrill wrote:
> > On Thu, Nov 3, 2016 at 7:24 AM, Marek Polacek <polacek@redhat.com> wrote:
> > > On Tue, Nov 01, 2016 at 02:53:58PM +0100, Jakub Jelinek wrote:
> > >> On Tue, Nov 01, 2016 at 09:41:20AM -0400, Jason Merrill wrote:
> > >> > On Tue, Oct 25, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > >> > > On Mon, Oct 24, 2016 at 04:10:21PM +0200, Marek Polacek wrote:
> > >> > >> On Thu, Oct 20, 2016 at 12:28:36PM +0200, Marek Polacek wrote:
> > >> > >> > I found a problem with this patch--we can't call do_warn_duplicated_branches in
> > >> > >> > build_conditional_expr, because that way the C++-specific codes might leak into
> > >> > >> > the hasher.  Instead, I should use operand_equal_p, I think.  Let me rework
> > >> > >> > that part of the patch.
> > >> >
> > >> > Hmm, is there a reason not to use operand_equal_p for
> > >> > do_warn_duplicated_branches as well?  I'm concerned about hash
> > >> > collisions leading to false positives.
> > >>
> > >> If the hashing function is iterative_hash_expr / inchash::add_expr, then
> > >> that is supposed to pair together with operand_equal_p, we even have
> > >> checking verification of that.
> > 
> > Yes, but there could still be hash collisions; we can't guarantee that
> > everything that compares unequal also hashes unequal.
> 
> 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
     
?

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-05 15:39                 ` Marek Polacek
@ 2017-01-05 15:41                   ` Jakub Jelinek
  2017-01-05 16:39                     ` Richard Biener
  2017-01-09  9:21                     ` Marek Polacek
  0 siblings, 2 replies; 34+ messages in thread
From: Jakub Jelinek @ 2017-01-05 15:41 UTC (permalink / raw)
  To: Marek Polacek, Richard Biener; +Cc: Jason Merrill, GCC Patches, Joseph Myers

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.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-05 15:41                   ` Jakub Jelinek
@ 2017-01-05 16:39                     ` Richard Biener
  2017-01-09  9:21                     ` Marek Polacek
  1 sibling, 0 replies; 34+ messages in thread
From: Richard Biener @ 2017-01-05 16:39 UTC (permalink / raw)
  To: Jakub Jelinek, Marek Polacek; +Cc: Jason Merrill, GCC Patches, Joseph Myers

On January 5, 2017 4:41:28 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> 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.

OEP_LEXICOGRAPHIC?

Richard.

>
>	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-05 15:41                   ` Jakub Jelinek
  2017-01-05 16:39                     ` Richard Biener
@ 2017-01-09  9:21                     ` Marek Polacek
  2017-01-09 10:58                       ` Richard Biener
                                         ` (2 more replies)
  1 sibling, 3 replies; 34+ messages in thread
From: Marek Polacek @ 2017-01-09  9:21 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

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?

2017-01-09  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.

	* 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;
 }
 \f
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

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09  9:21                     ` Marek Polacek
@ 2017-01-09 10:58                       ` Richard Biener
  2017-01-09 11:01                         ` Marek Polacek
  2017-01-09 11:18                       ` Jakub Jelinek
  2017-01-16 22:33                       ` Jeff Law
  2 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2017-01-09 10:58 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jakub Jelinek, Jason Merrill, GCC Patches, Joseph Myers

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  <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.
> 
> 	* 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;
>  }
>  \f
> 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 <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09 10:58                       ` Richard Biener
@ 2017-01-09 11:01                         ` Marek Polacek
  0 siblings, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2017-01-09 11:01 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Jason Merrill, GCC Patches, Joseph Myers

On Mon, Jan 09, 2017 at 11:57:48AM +0100, Richard Biener wrote:
> 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, I'll fix it up.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09  9:21                     ` Marek Polacek
  2017-01-09 10:58                       ` Richard Biener
@ 2017-01-09 11:18                       ` Jakub Jelinek
  2017-01-09 13:39                         ` Marek Polacek
  2017-01-16 22:33                       ` Jeff Law
  2 siblings, 1 reply; 34+ messages in thread
From: Jakub Jelinek @ 2017-01-09 11:18 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On Mon, Jan 09, 2017 at 10:21:47AM +0100, Marek Polacek wrote:
> +/* 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;
> +}

I know this is hard issue, but won't it disable the warning way too often?

Perhaps it is good enough for the initial version (GCC 7), but doesn't it stop
whenever one uses NULL in the branches, or some other trivial macros like
that?  Perhaps we want to do the analysis if there is anything from macro
expansion side-by-side on both the expressions and if you find something
from a macro expansion, then still warn if both corresponding expressions
are from the same macro expansion (either only non-function like one, or
perhaps also function-like one with the same arguments, if it is possible
to figure out those somehow)?  And perhaps it would be nice to choose
warning level, whether you want to warn only under these rules (no macros
or something smarter if implemented) vs. some certainly non-default more
aggressive mode that will just warn no matter what macros there are.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09 11:18                       ` Jakub Jelinek
@ 2017-01-09 13:39                         ` Marek Polacek
  2017-01-19 16:53                           ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2017-01-09 13:39 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On Mon, Jan 09, 2017 at 12:18:01PM +0100, Jakub Jelinek wrote:
> On Mon, Jan 09, 2017 at 10:21:47AM +0100, Marek Polacek wrote:
> > +/* 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;
> > +}
> 
> I know this is hard issue, but won't it disable the warning way too often?
> 
> Perhaps it is good enough for the initial version (GCC 7), but doesn't it stop
> whenever one uses NULL in the branches, or some other trivial macros like
> that?  Perhaps we want to do the analysis if there is anything from macro
> expansion side-by-side on both the expressions and if you find something
> from a macro expansion, then still warn if both corresponding expressions
> are from the same macro expansion (either only non-function like one, or
> perhaps also function-like one with the same arguments, if it is possible
> to figure out those somehow)?  And perhaps it would be nice to choose
> warning level, whether you want to warn only under these rules (no macros
> or something smarter if implemented) vs. some certainly non-default more
> aggressive mode that will just warn no matter what macros there are.

I agree that not warning for 
  if (foo)
    return NULL;
  else
    return NULL;
is bad.  But how can I compare those expressions side-by-side?  I'm not finding
anything. :(

As for the idea of multiple levels, sure, I could do that, although I'd prefer
to get the initial version in first.

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09  9:21                     ` Marek Polacek
  2017-01-09 10:58                       ` Richard Biener
  2017-01-09 11:18                       ` Jakub Jelinek
@ 2017-01-16 22:33                       ` Jeff Law
  2017-01-20 11:16                         ` Marek Polacek
  2 siblings, 1 reply; 34+ messages in thread
From: Jeff Law @ 2017-01-16 22:33 UTC (permalink / raw)
  To: Marek Polacek, Jakub Jelinek
  Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On 01/09/2017 02:21 AM, 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?
>
> 2017-01-09  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.
>
> 	* 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.
s/indentical/identical in the doc/invoke.texi changes.

>

> 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)))
Did you want OEP_LEXICOGRAPHIC here, or in this context do we not have 
to worry about the more complex forms?  What about a statement 
expressions?  Have we lowered those at this point already?

> 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)))
Likewise.

So, typo fix in invoke.texi and change to use OEP_LEXICOGRAPHIC in those 
two spots if needed and then OK for the trunk.

jeff

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-09 13:39                         ` Marek Polacek
@ 2017-01-19 16:53                           ` Marek Polacek
  2017-01-19 16:58                             ` Jakub Jelinek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2017-01-19 16:53 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On Mon, Jan 09, 2017 at 02:39:30PM +0100, Marek Polacek wrote:
> On Mon, Jan 09, 2017 at 12:18:01PM +0100, Jakub Jelinek wrote:
> > On Mon, Jan 09, 2017 at 10:21:47AM +0100, Marek Polacek wrote:
> > > +/* 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;
> > > +}
> > 
> > I know this is hard issue, but won't it disable the warning way too often?
> > 
> > Perhaps it is good enough for the initial version (GCC 7), but doesn't it stop
> > whenever one uses NULL in the branches, or some other trivial macros like
> > that?  Perhaps we want to do the analysis if there is anything from macro
> > expansion side-by-side on both the expressions and if you find something
> > from a macro expansion, then still warn if both corresponding expressions
> > are from the same macro expansion (either only non-function like one, or
> > perhaps also function-like one with the same arguments, if it is possible
> > to figure out those somehow)?  And perhaps it would be nice to choose
> > warning level, whether you want to warn only under these rules (no macros
> > or something smarter if implemented) vs. some certainly non-default more
> > aggressive mode that will just warn no matter what macros there are.
> 
> I agree that not warning for 
>   if (foo)
>     return NULL;
>   else
>     return NULL;
> is bad.  But how can I compare those expressions side-by-side?  I'm not finding
> anything. :(

Seems like ENOTIME to address this; will you be ok with the patch as-is
(modulo Jeff comments), if I open a PR about the above test case?

Thanks,

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-19 16:53                           ` Marek Polacek
@ 2017-01-19 16:58                             ` Jakub Jelinek
  0 siblings, 0 replies; 34+ messages in thread
From: Jakub Jelinek @ 2017-01-19 16:58 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On Thu, Jan 19, 2017 at 05:52:14PM +0100, Marek Polacek wrote:
> > I agree that not warning for 
> >   if (foo)
> >     return NULL;
> >   else
> >     return NULL;
> > is bad.  But how can I compare those expressions side-by-side?  I'm not finding
> > anything. :(
> 
> Seems like ENOTIME to address this; will you be ok with the patch as-is
> (modulo Jeff comments), if I open a PR about the above test case?

Yeah.

	Jakub

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Implement -Wduplicated-branches (PR c/64279) (v3)
  2017-01-16 22:33                       ` Jeff Law
@ 2017-01-20 11:16                         ` Marek Polacek
  0 siblings, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2017-01-20 11:16 UTC (permalink / raw)
  To: Jeff Law
  Cc: Jakub Jelinek, Richard Biener, Jason Merrill, GCC Patches, Joseph Myers

On Mon, Jan 16, 2017 at 03:32:59PM -0700, Jeff Law wrote:
> s/indentical/identical in the doc/invoke.texi changes.
 
Fixed.

> > 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)))
> Did you want OEP_LEXICOGRAPHIC here, or in this context do we not have to
> worry about the more complex forms?  What about a statement expressions?
> Have we lowered those at this point already?
 
I think we do not want OEP_LEXICOGRAPHIC here, because if the op0 or op1
of ?: have side-effects, they'll survive until c_genericize, so the warning
will warn.  With OEP_LEXICOGRAPHIC, it'd warn twice.

Simple statement expressions are handled (there are a few tests).  More
complicated ({})s are represented as BIND_EXPRs and those aren't handled.

> > 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)))
> Likewise.
 
Same as above.

> So, typo fix in invoke.texi and change to use OEP_LEXICOGRAPHIC in those two
> spots if needed and then OK for the trunk.

Thanks!

This is the patch with the typo fixed.  I'll commit it today after regtesting.

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.

	* 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 3bb42f6..a1b3ae5 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;
 }
 \f
diff --git gcc/cp/call.c gcc/cp/call.c
index 0059a39..a78e1a9 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 4202475..55710e6 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 a7b494b..5b96f36 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -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
diff --git gcc/fold-const.c gcc/fold-const.c
index cfd270c..5576d59 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 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
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 b7f8b07..2b1759e 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 59fe8d4..7127bd2 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -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;

	Marek

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2017-01-20 11:11 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-19 11:07 Implement -Wduplicated-branches (PR c/64279) Marek Polacek
2016-10-20 10:28 ` Marek Polacek
2016-10-24 14:10   ` Implement -Wduplicated-branches (PR c/64279) (v2) Marek Polacek
2016-10-25 13:59     ` Implement -Wduplicated-branches (PR c/64279) (v3) Marek Polacek
2016-11-01 13:41       ` Jason Merrill
2016-11-01 13:54         ` Jakub Jelinek
2016-11-03 11:24           ` Marek Polacek
2016-11-03 13:28             ` Jason Merrill
2016-11-03 13:38               ` Jakub Jelinek
2017-01-04  6:49                 ` Eric Gallager
2017-01-05 15:39                 ` Marek Polacek
2017-01-05 15:41                   ` Jakub Jelinek
2017-01-05 16:39                     ` Richard Biener
2017-01-09  9:21                     ` Marek Polacek
2017-01-09 10:58                       ` Richard Biener
2017-01-09 11:01                         ` Marek Polacek
2017-01-09 11:18                       ` Jakub Jelinek
2017-01-09 13:39                         ` Marek Polacek
2017-01-19 16:53                           ` Marek Polacek
2017-01-19 16:58                             ` Jakub Jelinek
2017-01-16 22:33                       ` Jeff Law
2017-01-20 11:16                         ` Marek Polacek
2016-10-20 14:12 ` Implement -Wduplicated-branches (PR c/64279) Jason Merrill
2016-10-20 14:24   ` Marek Polacek
2016-10-20 14:37     ` David Malcolm
2016-10-20 18:56       ` Jeff Law
2016-10-24 14:03         ` Marek Polacek
2016-10-20 20:21 ` Martin Sebor
2016-10-24 13:59   ` Marek Polacek
2016-10-24 14:18     ` Martin Sebor
2016-10-24 14:35       ` Marek Polacek
2016-10-24 14:39         ` Jakub Jelinek
2016-10-24 14:44           ` Marek Polacek
2016-10-24 14:59             ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).