public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C/C++ PATCH] Improve -Wlogical-op (PR c/63357)
@ 2015-04-21 11:16 Marek Polacek
  2015-04-21 14:19 ` Manuel López-Ibáñez
  2015-04-23 22:02 ` Jeff Law
  0 siblings, 2 replies; 12+ messages in thread
From: Marek Polacek @ 2015-04-21 11:16 UTC (permalink / raw)
  To: GCC Patches

This patch improves -Wlogical-op so that it also warns about cases such as
P && P or P || P.  I made use of what merge_ranges computes: if we have equal
operands with the same ranges, warn -- that seems to work well.
(-Wlogical-op still isn't enabled neither by -Wall nor by -Wextra.)

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

2015-04-21  Marek Polacek  <polacek@redhat.com>

	PR c/63357
	* c-common.c (warn_logical_operator): Warn if the operands have the
	same expressions.

	* doc/invoke.texi: Update description of -Wlogical-op.

	* c-c++-common/Wlogical-op-1.c: New test.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index 7fe7fa6..6eecc73 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -1772,22 +1772,35 @@ warn_logical_operator (location_t location, enum tree_code code, tree type,
     return;
 
   /* If both expressions have the same operand, if we can merge the
-     ranges, and if the range test is always false, then warn.  */
+     ranges, ...  */
   if (operand_equal_p (lhs, rhs, 0)
       && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
-		       in1_p, low1, high1)
-      && 0 != (tem = build_range_check (UNKNOWN_LOCATION,
-					type, lhs, in_p, low, high))
-      && integer_zerop (tem))
+		       in1_p, low1, high1))
     {
-      if (or_op)
-        warning_at (location, OPT_Wlogical_op,
-                    "logical %<or%> "
-                    "of collectively exhaustive tests is always true");
-      else
-        warning_at (location, OPT_Wlogical_op,
-                    "logical %<and%> "
-                    "of mutually exclusive tests is always false");
+      tem = build_range_check (UNKNOWN_LOCATION, type, lhs, in_p, low, high);
+      /* ... and if the range test is always false, then warn.  */
+      if (tem && integer_zerop (tem))
+	{
+	  if (or_op)
+	    warning_at (location, OPT_Wlogical_op,
+			"logical %<or%> of collectively exhaustive tests is "
+			"always true");
+	  else
+	    warning_at (location, OPT_Wlogical_op,
+			"logical %<and%> of mutually exclusive tests is "
+			"always false");
+	}
+      /* Or warn if the operands have exactly the same range, e.g.
+	 A > 0 && A > 0.  */
+      else if (low0 == low1 && high0 == high1)
+	{
+	  if (or_op)
+	    warning_at (location, OPT_Wlogical_op,
+			"logical %<or%> of equal expressions");
+	  else
+	    warning_at (location, OPT_Wlogical_op,
+			"logical %<and%> of equal expressions");
+	}
     }
 }
 
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index c20dd4d..8ce233b 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -4936,7 +4936,12 @@ programmer intended to use @code{strcmp}.  This warning is enabled by
 @opindex Wno-logical-op
 Warn about suspicious uses of logical operators in expressions.
 This includes using logical operators in contexts where a
-bit-wise operator is likely to be expected.
+bit-wise operator is likely to be expected.  Also warns when
+the operands of a logical operator are the same:
+@smallexample
+extern int a;
+if (a < 0 && a < 0) @{ @dots{} @}
+@end smallexample
 
 @item -Wlogical-not-parentheses
 @opindex Wlogical-not-parentheses
diff --git gcc/testsuite/c-c++-common/Wlogical-op-1.c gcc/testsuite/c-c++-common/Wlogical-op-1.c
index e69de29..33d4f38 100644
--- gcc/testsuite/c-c++-common/Wlogical-op-1.c
+++ gcc/testsuite/c-c++-common/Wlogical-op-1.c
@@ -0,0 +1,109 @@
+/* PR c/63357 */
+/* { dg-do compile } */
+/* { dg-options "-Wlogical-op" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+# define true 1
+# define false 0
+#endif
+
+extern int bar (void);
+extern int *p;
+struct R { int a, b; } S;
+
+void
+andfn (int a, int b)
+{
+  if (a && a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if (!a && !a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if (!!a && !!a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if (a > 0 && a > 0) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (a < 0 && a < 0) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (a == 0 && a == 0) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (a <= 0 && a <= 0) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (a >= 0 && a >= 0) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (a == 0 && !(a != 0)) {}	/* { dg-warning "logical .and. of equal expressions" } */
+
+  if (a && a && a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if ((a + 1) && (a + 1)) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if ((10 * a) && (a * 10)) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if (!!a && a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+
+  if (*p && *p) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if (p[0] && p[0]) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if (S.a && S.a) {}		/* { dg-warning "logical .and. of equal expressions" } */
+  if ((bool) a && (bool) a) {}	/* { dg-warning "logical .and. of equal expressions" } */
+  if ((unsigned) a && a) {}	/* { dg-warning "logical .and. of equal expressions" } */
+
+  /* Stay quiet here.  */
+  if (a && b) {}
+  if (!a && !b) {}
+  if (!!a && !!b) {}
+  if (a > 0 && b > 0) {}
+  if (a < 0 && b < 0) {}
+  if (a == 0 && b == 0) {}
+  if (a <= 0 && b <= 0) {}
+  if (a >= 0 && b >= 0) {}
+
+  if (a > 0 && a > 1) {}
+  if (a > -2 && a > 1) {}
+  if (a && (short) a) {}
+  if ((char) a && a) {}
+  if (++a && a) {}
+  if (++a && ++a) {}
+  if (a && --a) {}
+  if (a && a / 2) {}
+  if (bar () && bar ()) {}
+  if (p && *p) {}
+  if (p[0] && p[1]) {}
+  if (S.a && S.b) {}
+}
+
+void
+orfn (int a, int b)
+{
+  if (a || a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if (!a || !a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if (!!a || !!a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if (a > 0 || a > 0) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (a < 0 || a < 0) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (a == 0 || a == 0) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (a <= 0 || a <= 0) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (a >= 0 || a >= 0) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (a == 0 || !(a != 0)) {}	/* { dg-warning "logical .or. of equal expressions" } */
+
+  if (a || a || a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if ((a + 1) || (a + 1)) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if ((10 * a) || (a * 10)) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if (!!a || a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+
+  if (*p || *p) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if (p[0] || p[0]) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if (S.a || S.a) {}		/* { dg-warning "logical .or. of equal expressions" } */
+  if ((bool) a || (bool) a) {}	/* { dg-warning "logical .or. of equal expressions" } */
+  if ((unsigned) a || a) {}	/* { dg-warning "logical .or. of equal expressions" } */
+
+  /* Stay quiet here.  */
+  if (a || b) {}
+  if (!a || !b) {}
+  if (!!a || !!b) {}
+  if (a > 0 || b > 0) {}
+  if (a < 0 || b < 0) {}
+  if (a == 0 || b == 0) {}
+  if (a <= 0 || b <= 0) {}
+  if (a >= 0 || b >= 0) {}
+
+  if (a > 0 || a > 1) {}
+  if (a > -2 || a > 1) {}
+  if (a || (short) a) {}
+  if ((char) a || a) {}
+  if (++a || a) {}
+  if (++a || ++a) {}
+  if (a || --a) {}
+  if (a || a / 2) {}
+  if (bar () || bar ()) {}
+  if (p || *p) {}
+  if (p[0] || p[1]) {}
+  if (S.a || S.b) {}
+}

	Marek

^ permalink raw reply	[flat|nested] 12+ messages in thread
* Re: [C/C++ PATCH] Improve -Wlogical-op (PR c/63357)
@ 2015-04-25 20:19 Gerald Pfeifer
  2015-04-27 14:47 ` Marek Polacek
  0 siblings, 1 reply; 12+ messages in thread
From: Gerald Pfeifer @ 2015-04-25 20:19 UTC (permalink / raw)
  To: Marek Polacek, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1427 bytes --]


> 2015-04-21  Marek Polacek  <polacek@redhat.com>
>
>	PR c/63357
>	* c-common.c (warn_logical_operator): Warn if the operands have the
>	same expressions.

This is nice!  It really helped me find an issue or two in the 
Wine project.

Unfortunately it also causes false positives:

  int report (unsigned t)
  {
    typedef int r_fun_t (int);

    static r_fun_t * text_funcs[7];
    static r_fun_t * GUI_funcs[7];

    return (t < sizeof text_funcs / sizeof text_funcs[0] &&
            t < sizeof GUI_funcs / sizeof GUI_funcs[0]);
  }

Where we now warn as follows:

  input: In function Β‘reportΒ’:
  input:8:58: warning: logical Β‘andΒ’ of equal expressions [-Wlogical-op]
     return (t < sizeof text_funcs / sizeof text_funcs[0] &&
                                                          ^

In case this example feels too contrived (even though it is an
excerpt of Wine code), we now also warn about the following where
the two types and variables are defined in different places and
the size of one is set implicitly:

  typedef int r_fun_t (int);

  r_fun_t * text_funcs[] = {0,0,0};

  int report (unsigned t)
  {
    typedef int s_fun_t (long, char);

    static s_fun_t * GUI_funcs[3];

    return (t < sizeof text_funcs / sizeof text_funcs[0] &&
            t < sizeof GUI_funcs / sizeof GUI_funcs[0]);
  }

(I also filed this as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65891
so that we keep track.)

Gerald

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

end of thread, other threads:[~2015-04-27 16:10 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-21 11:16 [C/C++ PATCH] Improve -Wlogical-op (PR c/63357) Marek Polacek
2015-04-21 14:19 ` Manuel López-Ibáñez
2015-04-22  8:59   ` Marek Polacek
2015-04-22  9:51     ` Manuel López-Ibáñez
2015-04-22  9:54       ` Manuel López-Ibáñez
2015-04-22 11:12       ` Marek Polacek
2015-04-23 22:02 ` Jeff Law
2015-04-25 20:19 Gerald Pfeifer
2015-04-27 14:47 ` Marek Polacek
2015-04-27 14:50   ` Marek Polacek
2015-04-27 16:06   ` Jeff Law
2015-04-27 16:10     ` Marek Polacek

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