OSDN Git Service

2008-10-24 Manuel López-Ibáñez <manu@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 6b37c34..30acb7d 100644 (file)
@@ -8076,94 +8076,132 @@ warn_array_subscript_with_type_char (tree index)
 /* Implement -Wparentheses for the unexpected C precedence rules, to
    cover cases like x + y << z which readers are likely to
    misinterpret.  We have seen an expression in which CODE is a binary
-   operator used to combine expressions headed by CODE_LEFT and
-   CODE_RIGHT.  CODE_LEFT and CODE_RIGHT may be ERROR_MARK, which
-   means that that side of the expression was not formed using a
-   binary operator, or it was enclosed in parentheses.  */
+   operator used to combine expressions ARG_LEFT and ARG_RIGHT, which
+   before folding had CODE_LEFT and CODE_RIGHT.  CODE_LEFT and
+   CODE_RIGHT may be ERROR_MARK, which means that that side of the
+   expression was not formed using a binary or unary operator, or it
+   was enclosed in parentheses.  */
 
 void
-warn_about_parentheses (enum tree_code code, enum tree_code code_left,
-                       enum tree_code code_right)
+warn_about_parentheses (enum tree_code code,
+                       enum tree_code code_left, tree ARG_UNUSED (arg_left),
+                       enum tree_code code_right, tree arg_right)
 {
   if (!warn_parentheses)
     return;
 
-  if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+  /* This macro tests that the expression ARG with original tree code
+     CODE appears to be a boolean expression. or the result of folding a
+     boolean expression.  */
+#define APPEARS_TO_BE_BOOLEAN_EXPR_P(CODE, ARG)                             \
+       (truth_value_p (TREE_CODE (ARG))                                    \
+        || TREE_CODE (TREE_TYPE (ARG)) == BOOLEAN_TYPE                     \
+        /* Folding may create 0 or 1 integers from other expressions.  */  \
+        || ((CODE) != INTEGER_CST                                          \
+            && (integer_onep (ARG) || integer_zerop (ARG))))
+
+  switch (code) 
     {
-      if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
-         || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+    case LSHIFT_EXPR:
+      if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
        warning (OPT_Wparentheses,
-                "suggest parentheses around + or - inside shift");
-    }
+                "suggest parentheses around %<+%> inside %<<<%>");
+      else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
+       warning (OPT_Wparentheses,
+                "suggest parentheses around %<-%> inside %<<<%>");
+      return;
 
-  if (code == TRUTH_ORIF_EXPR)
-    {
-      if (code_left == TRUTH_ANDIF_EXPR
-         || code_right == TRUTH_ANDIF_EXPR)
+    case RSHIFT_EXPR:
+      if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
        warning (OPT_Wparentheses,
-                "suggest parentheses around && within ||");
-    }
+                "suggest parentheses around %<+%> inside %<>>%>");
+      else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
+       warning (OPT_Wparentheses,
+                "suggest parentheses around %<-%> inside %<>>%>");
+      return;
 
-  if (code == BIT_IOR_EXPR)
-    {
+    case TRUTH_ORIF_EXPR:
+      if (code_left == TRUTH_ANDIF_EXPR || code_right == TRUTH_ANDIF_EXPR)
+       warning (OPT_Wparentheses,
+                "suggest parentheses around %<&&%> within %<||%>");
+      return;
+
+    case BIT_IOR_EXPR:
       if (code_left == BIT_AND_EXPR || code_left == BIT_XOR_EXPR
          || code_left == PLUS_EXPR || code_left == MINUS_EXPR
          || code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR
          || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
        warning (OPT_Wparentheses,
-                "suggest parentheses around arithmetic in operand of |");
+                "suggest parentheses around arithmetic in operand of %<|%>");
       /* Check cases like x|y==z */
-      if (TREE_CODE_CLASS (code_left) == tcc_comparison
-         || TREE_CODE_CLASS (code_right) == tcc_comparison)
+      else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+              || TREE_CODE_CLASS (code_right) == tcc_comparison)
        warning (OPT_Wparentheses,
-                "suggest parentheses around comparison in operand of |");
-    }
+                "suggest parentheses around comparison in operand of %<|%>");
+      /* Check cases like !x | y */
+      else if (code_left == TRUTH_NOT_EXPR
+              && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right))
+       warning (OPT_Wparentheses, "suggest parentheses around operand of"
+                "%<!%> or change %<|%> to %<||%> or %<!%> to %<~%>");
+      return;
 
-  if (code == BIT_XOR_EXPR)
-    {
+    case BIT_XOR_EXPR:
       if (code_left == BIT_AND_EXPR
          || code_left == PLUS_EXPR || code_left == MINUS_EXPR
          || code_right == BIT_AND_EXPR
          || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
        warning (OPT_Wparentheses,
-                "suggest parentheses around arithmetic in operand of ^");
+                "suggest parentheses around arithmetic in operand of %<^%>");
       /* Check cases like x^y==z */
-      if (TREE_CODE_CLASS (code_left) == tcc_comparison
-         || TREE_CODE_CLASS (code_right) == tcc_comparison)
+      else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+              || TREE_CODE_CLASS (code_right) == tcc_comparison)
        warning (OPT_Wparentheses,
-                "suggest parentheses around comparison in operand of ^");
-    }
+                "suggest parentheses around comparison in operand of %<^%>");
+      return;
 
-  if (code == BIT_AND_EXPR)
-    {
-      if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
-         || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+    case BIT_AND_EXPR:
+      if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
+       warning (OPT_Wparentheses,
+                "suggest parentheses around %<+%> in operand of %<&%>");
+      else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
        warning (OPT_Wparentheses,
-                "suggest parentheses around + or - in operand of &");
+                "suggest parentheses around %<-%> in operand of %<&%>");
       /* Check cases like x&y==z */
-      if (TREE_CODE_CLASS (code_left) == tcc_comparison
-         || TREE_CODE_CLASS (code_right) == tcc_comparison)
+      else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+              || TREE_CODE_CLASS (code_right) == tcc_comparison)
        warning (OPT_Wparentheses,
-                "suggest parentheses around comparison in operand of &");
-    }
+                "suggest parentheses around comparison in operand of %<&%>");
+      /* Check cases like !x & y */
+      else if (code_left == TRUTH_NOT_EXPR
+              && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right))
+       warning (OPT_Wparentheses, "suggest parentheses around operand of"
+                "%<!%> or change %<&%> to %<&&%> or %<!%> to %<~%>");
+      return;
 
-  if (code == EQ_EXPR || code == NE_EXPR)
-    {
+    case EQ_EXPR:
       if (TREE_CODE_CLASS (code_left) == tcc_comparison
           || TREE_CODE_CLASS (code_right) == tcc_comparison)
        warning (OPT_Wparentheses,
-                "suggest parentheses around comparison in operand of %s",
-                 code == EQ_EXPR ? "==" : "!=");
-    }
-  else if (TREE_CODE_CLASS (code) == tcc_comparison)
-    {
-      if ((TREE_CODE_CLASS (code_left) == tcc_comparison
-          && code_left != NE_EXPR && code_left != EQ_EXPR)
-         || (TREE_CODE_CLASS (code_right) == tcc_comparison
-             && code_right != NE_EXPR && code_right != EQ_EXPR))
-       warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
+                "suggest parentheses around comparison in operand of %<==%>");
+      return;
+    case NE_EXPR:
+      if (TREE_CODE_CLASS (code_left) == tcc_comparison
+          || TREE_CODE_CLASS (code_right) == tcc_comparison)
+       warning (OPT_Wparentheses,
+                "suggest parentheses around comparison in operand of %<!=%>");
+      return;
+
+    default:
+      if (TREE_CODE_CLASS (code) == tcc_comparison
+          && ((TREE_CODE_CLASS (code_left) == tcc_comparison
+               && code_left != NE_EXPR && code_left != EQ_EXPR)
+              || (TREE_CODE_CLASS (code_right) == tcc_comparison
+                  && code_right != NE_EXPR && code_right != EQ_EXPR)))
+       warning (OPT_Wparentheses, "comparisons like %<X<=Y<=Z%> do not "
                 "have their mathematical meaning");
+      return;
     }
+#undef NOT_A_BOOLEAN_EXPR_P
 }
 
 /* If LABEL (a LABEL_DECL) has not been used, issue a warning.  */