This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Implement -Wduplicated-branches (PR c/64279) (v3)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]