Implement -Wduplicated-branches (PR c/64279) (v2)

Marek Polacek polacek@redhat.com
Mon Oct 24 14:10:00 GMT 2016


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



More information about the Gcc-patches mailing list