public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C PATCH] Warn if switch has boolean value (PR c/60439)
@ 2014-04-18  5:49 Marek Polacek
  2014-04-18  6:00 ` Marc Glisse
  2014-04-18 11:24 ` Steven Bosscher
  0 siblings, 2 replies; 15+ messages in thread
From: Marek Polacek @ 2014-04-18  5:49 UTC (permalink / raw)
  To: GCC Patches; +Cc: Joseph S. Myers

This patch implements a new warning that warns when controlling
expression of a switch has boolean value.  (Intentionally I don't
warn if the controlling expression is (un)signed:1 bit-field.)
I guess the question is if this should be enabled by default or
deserves some new warning option.  Since clang does the former,
I did it too and currently this warning is enabled by default.

Regtested/bootstrapped on x86_64-linux, ok for trunk?

2014-04-17  Marek Polacek  <polacek@redhat.com>

	PR c/60439
c/
	* c-typeck.c (c_start_case): Warn if switch condition has boolean
	value.
testsuite/
	* gcc.dg/pr60439.c: New test.

diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 65aad45..91b1109 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9344,6 +9344,28 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+	  enum tree_code exp_code;
+
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+	  exp_code = TREE_CODE (e);
+
+	  if (TREE_CODE (type) == BOOLEAN_TYPE
+	      || exp_code == TRUTH_ANDIF_EXPR
+	      || exp_code == TRUTH_AND_EXPR
+	      || exp_code == TRUTH_ORIF_EXPR
+	      || exp_code == TRUTH_OR_EXPR
+	      || exp_code == TRUTH_XOR_EXPR
+	      || exp_code == TRUTH_NOT_EXPR
+	      || exp_code == EQ_EXPR
+	      || exp_code == NE_EXPR
+	      || exp_code == LE_EXPR
+	      || exp_code == GE_EXPR
+	      || exp_code == LT_EXPR
+	      || exp_code == GT_EXPR)
+	    warning_at (switch_cond_loc, 0,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/testsuite/gcc.dg/pr60439.c gcc/testsuite/gcc.dg/pr60439.c
index e69de29..26e7c25 100644
--- gcc/testsuite/gcc.dg/pr60439.c
+++ gcc/testsuite/gcc.dg/pr60439.c
@@ -0,0 +1,112 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+typedef _Bool bool;
+extern _Bool foo (void);
+
+void
+f1 (const _Bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a != 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a > 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a < 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a <= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a >= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    case 1:
+      break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (b++) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    case 0:
+      break;
+  switch ((unsigned int) i)
+    case 0:
+      break;
+  switch ((bool) i) /* { dg-warning "switch condition has boolean value" } */
+    case 0:
+      break;
+}

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18  5:49 [C PATCH] Warn if switch has boolean value (PR c/60439) Marek Polacek
@ 2014-04-18  6:00 ` Marc Glisse
  2014-04-18  6:42   ` Marek Polacek
  2014-04-18  8:03   ` Jakub Jelinek
  2014-04-18 11:24 ` Steven Bosscher
  1 sibling, 2 replies; 15+ messages in thread
From: Marc Glisse @ 2014-04-18  6:00 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph S. Myers

On Fri, 18 Apr 2014, Marek Polacek wrote:

> This patch implements a new warning that warns when controlling
> expression of a switch has boolean value.  (Intentionally I don't
> warn if the controlling expression is (un)signed:1 bit-field.)
> I guess the question is if this should be enabled by default or
> deserves some new warning option.  Since clang does the former,
> I did it too and currently this warning is enabled by default.

It can be enabled by -Wsome-name which is itself enabled by default but
at least gives the possibility to use -Wno-some-name, -Werror=some-name,
etc. No? I believe Manuel insists regularly that no new warning should
use 0 (and old ones should progressively lose it).

-- 
Marc Glisse

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18  6:00 ` Marc Glisse
@ 2014-04-18  6:42   ` Marek Polacek
  2014-04-18  7:09     ` Marek Polacek
  2014-04-18  8:03   ` Jakub Jelinek
  1 sibling, 1 reply; 15+ messages in thread
From: Marek Polacek @ 2014-04-18  6:42 UTC (permalink / raw)
  To: Marc Glisse; +Cc: GCC Patches, Joseph S. Myers

On Fri, Apr 18, 2014 at 07:49:22AM +0200, Marc Glisse wrote:
> On Fri, 18 Apr 2014, Marek Polacek wrote:
> 
> >This patch implements a new warning that warns when controlling
> >expression of a switch has boolean value.  (Intentionally I don't
> >warn if the controlling expression is (un)signed:1 bit-field.)
> >I guess the question is if this should be enabled by default or
> >deserves some new warning option.  Since clang does the former,
> >I did it too and currently this warning is enabled by default.
> 
> It can be enabled by -Wsome-name which is itself enabled by default but
> at least gives the possibility to use -Wno-some-name, -Werror=some-name,
> etc. No? I believe Manuel insists regularly that no new warning should
> use 0 (and old ones should progressively lose it).

Yes, that's the other possibility and exactly what I wanted to
discuss.  I think I'll prepare another version with -Wswitch-bool (and
documentation).

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18  6:42   ` Marek Polacek
@ 2014-04-18  7:09     ` Marek Polacek
  0 siblings, 0 replies; 15+ messages in thread
From: Marek Polacek @ 2014-04-18  7:09 UTC (permalink / raw)
  To: Marc Glisse; +Cc: GCC Patches, Joseph S. Myers

On Fri, Apr 18, 2014 at 08:00:45AM +0200, Marek Polacek wrote:
> On Fri, Apr 18, 2014 at 07:49:22AM +0200, Marc Glisse wrote:
> > On Fri, 18 Apr 2014, Marek Polacek wrote:
> > 
> > >This patch implements a new warning that warns when controlling
> > >expression of a switch has boolean value.  (Intentionally I don't
> > >warn if the controlling expression is (un)signed:1 bit-field.)
> > >I guess the question is if this should be enabled by default or
> > >deserves some new warning option.  Since clang does the former,
> > >I did it too and currently this warning is enabled by default.
> > 
> > It can be enabled by -Wsome-name which is itself enabled by default but
> > at least gives the possibility to use -Wno-some-name, -Werror=some-name,
> > etc. No? I believe Manuel insists regularly that no new warning should
> > use 0 (and old ones should progressively lose it).
> 
> Yes, that's the other possibility and exactly what I wanted to
> discuss.  I think I'll prepare another version with -Wswitch-bool (and
> documentation).

Here.

2014-04-18  Marek Polacek  <polacek@redhat.com>

	PR c/60439
	* doc/invoke.texi: Document -Wswitch-bool.
c/
	* c-typeck.c (c_start_case): Warn if switch condition has boolean
	value.
c-family/
	* c.opt (Wswitch-bool): New option.
testsuite/
	* gcc.dg/pr60439.c: New test.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index 390c056..9089496 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -529,6 +529,10 @@ Wswitch-enum
 C ObjC C++ ObjC++ Var(warn_switch_enum) Warning
 Warn about all enumerated switches missing a specific case
 
+Wswitch-bool
+C ObjC Warning Init(1)
+Warn about switches with boolean controlling expression
+
 Wmissing-format-attribute
 C ObjC C++ ObjC++ Alias(Wsuggest-attribute=format)
 ;
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 65aad45..44982d3 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9344,6 +9344,28 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+	  enum tree_code exp_code;
+
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+	  exp_code = TREE_CODE (e);
+
+	  if (TREE_CODE (type) == BOOLEAN_TYPE
+	      || exp_code == TRUTH_ANDIF_EXPR
+	      || exp_code == TRUTH_AND_EXPR
+	      || exp_code == TRUTH_ORIF_EXPR
+	      || exp_code == TRUTH_OR_EXPR
+	      || exp_code == TRUTH_XOR_EXPR
+	      || exp_code == TRUTH_NOT_EXPR
+	      || exp_code == EQ_EXPR
+	      || exp_code == NE_EXPR
+	      || exp_code == LE_EXPR
+	      || exp_code == GE_EXPR
+	      || exp_code == LT_EXPR
+	      || exp_code == GT_EXPR)
+	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 8004da8..04e1c41 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -268,7 +268,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
--Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
+-Wswitch  -Wswitch-default  -Wswitch-enum -Wswitch-bool -Wsync-nand @gol
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
@@ -3822,6 +3822,12 @@ between @option{-Wswitch} and this option is that this option gives a
 warning about an omitted enumeration code even if there is a
 @code{default} label.
 
+@item -Wswitch-bool
+@opindex Wswitch-bool
+@opindex Wno-switch-bool
+Warn whenever a @code{switch} statement has an index of boolean type.
+This warning is enabled by default for C programs.
+
 @item -Wsync-nand @r{(C and C++ only)}
 @opindex Wsync-nand
 @opindex Wno-sync-nand
diff --git gcc/testsuite/gcc.dg/pr60439.c gcc/testsuite/gcc.dg/pr60439.c
index e69de29..26e7c25 100644
--- gcc/testsuite/gcc.dg/pr60439.c
+++ gcc/testsuite/gcc.dg/pr60439.c
@@ -0,0 +1,112 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+typedef _Bool bool;
+extern _Bool foo (void);
+
+void
+f1 (const _Bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a != 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a > 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a < 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a <= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a >= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    case 1:
+      break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (b++) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    case 0:
+      break;
+  switch ((unsigned int) i)
+    case 0:
+      break;
+  switch ((bool) i) /* { dg-warning "switch condition has boolean value" } */
+    case 0:
+      break;
+}

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18  6:00 ` Marc Glisse
  2014-04-18  6:42   ` Marek Polacek
@ 2014-04-18  8:03   ` Jakub Jelinek
  1 sibling, 0 replies; 15+ messages in thread
From: Jakub Jelinek @ 2014-04-18  8:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Marek Polacek, Joseph S. Myers

On Fri, Apr 18, 2014 at 07:49:22AM +0200, Marc Glisse wrote:
> On Fri, 18 Apr 2014, Marek Polacek wrote:
> 
> >This patch implements a new warning that warns when controlling
> >expression of a switch has boolean value.  (Intentionally I don't
> >warn if the controlling expression is (un)signed:1 bit-field.)
> >I guess the question is if this should be enabled by default or
> >deserves some new warning option.  Since clang does the former,
> >I did it too and currently this warning is enabled by default.
> 
> It can be enabled by -Wsome-name which is itself enabled by default but
> at least gives the possibility to use -Wno-some-name, -Werror=some-name,
> etc. No? I believe Manuel insists regularly that no new warning should
> use 0 (and old ones should progressively lose it).

Yeah, completely agreed.  It can be enabled by default, but it should still be
constorlled by a warning switch.

	Jakub

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18  5:49 [C PATCH] Warn if switch has boolean value (PR c/60439) Marek Polacek
  2014-04-18  6:00 ` Marc Glisse
@ 2014-04-18 11:24 ` Steven Bosscher
  2014-04-18 12:21   ` Marc Glisse
  2014-04-18 12:41   ` Marek Polacek
  1 sibling, 2 replies; 15+ messages in thread
From: Steven Bosscher @ 2014-04-18 11:24 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph S. Myers

On Fri, Apr 18, 2014 at 7:30 AM, Marek Polacek wrote:
> +         if (TREE_CODE (type) == BOOLEAN_TYPE
> +             || exp_code == TRUTH_ANDIF_EXPR
> +             || exp_code == TRUTH_AND_EXPR
> +             || exp_code == TRUTH_ORIF_EXPR
> +             || exp_code == TRUTH_OR_EXPR
> +             || exp_code == TRUTH_XOR_EXPR
> +             || exp_code == TRUTH_NOT_EXPR
> +             || exp_code == EQ_EXPR
> +             || exp_code == NE_EXPR
> +             || exp_code == LE_EXPR
> +             || exp_code == GE_EXPR
> +             || exp_code == LT_EXPR
> +             || exp_code == GT_EXPR)

Is there a TREE_CODE_CLASS or a #define for this?

Ciao!
Steven

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18 11:24 ` Steven Bosscher
@ 2014-04-18 12:21   ` Marc Glisse
  2014-04-18 12:41   ` Marek Polacek
  1 sibling, 0 replies; 15+ messages in thread
From: Marc Glisse @ 2014-04-18 12:21 UTC (permalink / raw)
  To: Steven Bosscher; +Cc: Marek Polacek, GCC Patches, Joseph S. Myers

On Fri, 18 Apr 2014, Steven Bosscher wrote:

> On Fri, Apr 18, 2014 at 7:30 AM, Marek Polacek wrote:
>> +         if (TREE_CODE (type) == BOOLEAN_TYPE
>> +             || exp_code == TRUTH_ANDIF_EXPR
>> +             || exp_code == TRUTH_AND_EXPR
>> +             || exp_code == TRUTH_ORIF_EXPR
>> +             || exp_code == TRUTH_OR_EXPR
>> +             || exp_code == TRUTH_XOR_EXPR
>> +             || exp_code == TRUTH_NOT_EXPR
>> +             || exp_code == EQ_EXPR
>> +             || exp_code == NE_EXPR
>> +             || exp_code == LE_EXPR
>> +             || exp_code == GE_EXPR
>> +             || exp_code == LT_EXPR
>> +             || exp_code == GT_EXPR)
>
> Is there a TREE_CODE_CLASS or a #define for this?

truth_value_p

-- 
Marc Glisse

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18 11:24 ` Steven Bosscher
  2014-04-18 12:21   ` Marc Glisse
@ 2014-04-18 12:41   ` Marek Polacek
  2014-05-02  5:09     ` Jeff Law
  1 sibling, 1 reply; 15+ messages in thread
From: Marek Polacek @ 2014-04-18 12:41 UTC (permalink / raw)
  To: Steven Bosscher; +Cc: GCC Patches, Joseph S. Myers

On Fri, Apr 18, 2014 at 01:20:59PM +0200, Steven Bosscher wrote:
> On Fri, Apr 18, 2014 at 7:30 AM, Marek Polacek wrote:
> > +         if (TREE_CODE (type) == BOOLEAN_TYPE
> > +             || exp_code == TRUTH_ANDIF_EXPR
> > +             || exp_code == TRUTH_AND_EXPR
> > +             || exp_code == TRUTH_ORIF_EXPR
> > +             || exp_code == TRUTH_OR_EXPR
> > +             || exp_code == TRUTH_XOR_EXPR
> > +             || exp_code == TRUTH_NOT_EXPR
> > +             || exp_code == EQ_EXPR
> > +             || exp_code == NE_EXPR
> > +             || exp_code == LE_EXPR
> > +             || exp_code == GE_EXPR
> > +             || exp_code == LT_EXPR
> > +             || exp_code == GT_EXPR)
> 
> Is there a TREE_CODE_CLASS or a #define for this?

Good question.  I was looking for something nicer and found nothing,
no T_C_C or #define.
But now when I'm looking again, I found truth_value_p...  Thanks.

2014-04-18  Marek Polacek  <polacek@redhat.com>

	PR c/60439
	* doc/invoke.texi: Document -Wswitch-bool.
c/
	* c-typeck.c (c_start_case): Warn if switch condition has boolean
	value.
c-family/
	* c.opt (Wswitch-bool): New option.
testsuite/
	* gcc.dg/pr60439.c: New test.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index 390c056..9089496 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -529,6 +529,10 @@ Wswitch-enum
 C ObjC C++ ObjC++ Var(warn_switch_enum) Warning
 Warn about all enumerated switches missing a specific case
 
+Wswitch-bool
+C ObjC Warning Init(1)
+Warn about switches with boolean controlling expression
+
 Wmissing-format-attribute
 C ObjC C++ ObjC++ Alias(Wsuggest-attribute=format)
 ;
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 65aad45..1b37f83 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9344,6 +9344,15 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+
+	  if (TREE_CODE (type) == BOOLEAN_TYPE
+	      || truth_value_p (TREE_CODE (e)))
+	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 8004da8..04e1c41 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -268,7 +268,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
--Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
+-Wswitch  -Wswitch-default  -Wswitch-enum -Wswitch-bool -Wsync-nand @gol
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
@@ -3822,6 +3822,12 @@ between @option{-Wswitch} and this option is that this option gives a
 warning about an omitted enumeration code even if there is a
 @code{default} label.
 
+@item -Wswitch-bool
+@opindex Wswitch-bool
+@opindex Wno-switch-bool
+Warn whenever a @code{switch} statement has an index of boolean type.
+This warning is enabled by default for C programs.
+
 @item -Wsync-nand @r{(C and C++ only)}
 @opindex Wsync-nand
 @opindex Wno-sync-nand
diff --git gcc/testsuite/gcc.dg/pr60439.c gcc/testsuite/gcc.dg/pr60439.c
index e69de29..26e7c25 100644
--- gcc/testsuite/gcc.dg/pr60439.c
+++ gcc/testsuite/gcc.dg/pr60439.c
@@ -0,0 +1,112 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+typedef _Bool bool;
+extern _Bool foo (void);
+
+void
+f1 (const _Bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!a) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a != 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a > 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a < 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a <= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a >= 3) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    case 1:
+      break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (!b) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+  switch (b++) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has boolean value" } */
+    case 1:
+      break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    case 0:
+      break;
+  switch ((unsigned int) i)
+    case 0:
+      break;
+  switch ((bool) i) /* { dg-warning "switch condition has boolean value" } */
+    case 0:
+      break;
+}

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-04-18 12:41   ` Marek Polacek
@ 2014-05-02  5:09     ` Jeff Law
  2014-05-24  8:01       ` Marek Polacek
  0 siblings, 1 reply; 15+ messages in thread
From: Jeff Law @ 2014-05-02  5:09 UTC (permalink / raw)
  To: Marek Polacek, Steven Bosscher; +Cc: GCC Patches, Joseph S. Myers

On 04/18/14 05:50, Marek Polacek wrote:
> On Fri, Apr 18, 2014 at 01:20:59PM +0200, Steven Bosscher wrote:
>> On Fri, Apr 18, 2014 at 7:30 AM, Marek Polacek wrote:
>>> +         if (TREE_CODE (type) == BOOLEAN_TYPE
>>> +             || exp_code == TRUTH_ANDIF_EXPR
>>> +             || exp_code == TRUTH_AND_EXPR
>>> +             || exp_code == TRUTH_ORIF_EXPR
>>> +             || exp_code == TRUTH_OR_EXPR
>>> +             || exp_code == TRUTH_XOR_EXPR
>>> +             || exp_code == TRUTH_NOT_EXPR
>>> +             || exp_code == EQ_EXPR
>>> +             || exp_code == NE_EXPR
>>> +             || exp_code == LE_EXPR
>>> +             || exp_code == GE_EXPR
>>> +             || exp_code == LT_EXPR
>>> +             || exp_code == GT_EXPR)
>>
>> Is there a TREE_CODE_CLASS or a #define for this?
>
> Good question.  I was looking for something nicer and found nothing,
> no T_C_C or #define.
> But now when I'm looking again, I found truth_value_p...  Thanks.
>
> 2014-04-18  Marek Polacek  <polacek@redhat.com>
>
> 	PR c/60439
> 	* doc/invoke.texi: Document -Wswitch-bool.
> c/
> 	* c-typeck.c (c_start_case): Warn if switch condition has boolean
> 	value.
> c-family/
> 	* c.opt (Wswitch-bool): New option.
> testsuite/
> 	* gcc.dg/pr60439.c: New test.
Looks reasonable, though I do wonder if we should be warning for this in 
the C++ front-end as well?

jeff

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-05-02  5:09     ` Jeff Law
@ 2014-05-24  8:01       ` Marek Polacek
  2014-06-02 22:00         ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Marek Polacek @ 2014-05-24  8:01 UTC (permalink / raw)
  To: Jeff Law; +Cc: Steven Bosscher, GCC Patches, Joseph S. Myers, Jason Merrill

On Thu, May 01, 2014 at 11:09:04PM -0600, Jeff Law wrote:
> Looks reasonable, though I do wonder if we should be warning for this in the
> C++ front-end as well?

Yep, I think so.  Luckily the code for the C++ FE is pretty much the
same and, in fact, simpler.
Two issues came up:
1) I think there should be a way how to suppress the warning.  This
   can be done by casting the value of a controlling expression to
   a type other than bool.  The problem was in the C FE, because the
   type of expressions like && is int - so the cast to int was already
   lost in c_start_case.  I resorted to a not very pretty, but
   hopefully simple enough hack
2) Since the warning is now enabled even for the C++ FE, it's
   exercised during bootstrap.  Turned out that gengtype generates
   code like
   switch (TREE_CODE (...) == INTEGER_TYPE) { ... }
   that would mar the bootstrap - so I tweaked it to generate
   switch ((int) (TREE_CODE (...) == INTEGER_TYPE) { ... })
   instead.  Does that make sense?

Regtested/bootstrapped on x86_64-linux, ok for trunk?

2014-05-24  Marek Polacek  <polacek@redhat.com>

	PR c/60439
	* doc/invoke.texi: Document -Wswitch-bool.
	* function.c (stack_protect_epilogue): Cast controlling expression of
	the switch to int.
	* gengtype.c (walk_type): Generate switch expression with its
	controlling expression cast to int.
c/
	* c-parser.c (c_parser_switch_statement): Pass explicit_cast_p to
	c_start_case.
	* c-tree.h (c_start_case): Update.
	* c-typeck.c (c_start_case): Add new boolean parameter.  Warn if
	switch condition has boolean value.
cp/
	* semantics.c (finish_switch_cond): Warn if switch condition has
	boolean value.
c-family/
	* c.opt (Wswitch-bool): New option.
testsuite/
	* c-c++-common/pr60439.c: New test.
	* g++.dg/eh/scope1.C (f4): Add dg-warning.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index c586e65..5d36a80 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -534,6 +534,10 @@ Wswitch-enum
 C ObjC C++ ObjC++ Var(warn_switch_enum) Warning
 Warn about all enumerated switches missing a specific case
 
+Wswitch-bool
+C ObjC C++ ObjC++ Warning Init(1)
+Warn about switches with boolean controlling expression
+
 Wmissing-format-attribute
 C ObjC C++ ObjC++ Alias(Wsuggest-attribute=format)
 ;
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 88edf36..fc4865e 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -5196,9 +5196,13 @@ c_parser_switch_statement (c_parser *parser)
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
+  bool explicit_cast_p = false;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       switch_cond_loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+	  && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+	explicit_cast_p = true;
       ce = c_parser_expression (parser);
       ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
       expr = ce.value;
@@ -5216,7 +5220,7 @@ c_parser_switch_statement (c_parser *parser)
       switch_cond_loc = UNKNOWN_LOCATION;
       expr = error_mark_node;
     }
-  c_start_case (switch_loc, switch_cond_loc, expr);
+  c_start_case (switch_loc, switch_cond_loc, expr, explicit_cast_p);
   save_break = c_break_label;
   c_break_label = NULL_TREE;
   body = c_parser_c99_block_statement (parser);
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index e7dcb35..133930f 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -614,7 +614,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
 				  struct obstack *);
 extern tree build_compound_literal (location_t, tree, tree, bool);
 extern void check_compound_literal_type (location_t, struct c_type_name *);
-extern tree c_start_case (location_t, location_t, tree);
+extern tree c_start_case (location_t, location_t, tree, bool);
 extern void c_finish_case (tree);
 extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
 extern tree build_asm_stmt (tree, tree);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 74a5ebd..24958c4 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9347,12 +9347,13 @@ struct c_switch *c_switch_stack;
 
 /* Start a C switch statement, testing expression EXP.  Return the new
    SWITCH_EXPR.  SWITCH_LOC is the location of the `switch'.
-   SWITCH_COND_LOC is the location of the switch's condition.  */
+   SWITCH_COND_LOC is the location of the switch's condition.
+   EXPLICIT_CAST_P is true if the expression EXP has explicit cast.  */
 
 tree
 c_start_case (location_t switch_loc,
 	      location_t switch_cond_loc,
-	      tree exp)
+	      tree exp, bool explicit_cast_p)
 {
   tree orig_type = error_mark_node;
   struct c_switch *cs;
@@ -9373,6 +9374,19 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+
+	  /* Warn if the condition has boolean value.  */
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+
+	  if ((TREE_CODE (type) == BOOLEAN_TYPE
+	       || truth_value_p (TREE_CODE (e)))
+	      /* Explicit cast to int suppresses this warning.  */
+	      && !(TREE_CODE (type) == INTEGER_TYPE
+		   && explicit_cast_p))
+	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index edab330..0f65ace 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -1129,6 +1129,17 @@ finish_switch_cond (tree cond, tree switch_stmt)
       orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
 	{
+	  /* Warn if the condition has boolean value.  */
+	  tree e = cond;
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+
+	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
+	      || (truth_value_p (TREE_CODE (e))
+		  && TREE_CODE (orig_type) != INTEGER_TYPE))
+	    warning_at (input_location, OPT_Wswitch_bool,
+			"switch condition has boolean value");
+
 	  /* [stmt.switch]
 
 	     Integral promotions are performed.  */
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 34ba721..b1f36bf 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -271,7 +271,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
--Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
+-Wswitch  -Wswitch-default  -Wswitch-enum -Wswitch-bool -Wsync-nand @gol
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
@@ -3845,6 +3845,22 @@ between @option{-Wswitch} and this option is that this option gives a
 warning about an omitted enumeration code even if there is a
 @code{default} label.
 
+@item -Wswitch-bool
+@opindex Wswitch-bool
+@opindex Wno-switch-bool
+Warn whenever a @code{switch} statement has an index of boolean type.
+It is possible to suppress this warning by casting the controlling
+expression to a type other than @code{bool}.  For example:
+@smallexample
+@group
+switch ((int) (a == 4))
+  @{
+  ...
+  @}
+@end group
+@end smallexample
+This warning is enabled by default for C and C++ programs.
+
 @item -Wsync-nand @r{(C and C++ only)}
 @opindex Wsync-nand
 @opindex Wno-sync-nand
diff --git gcc/function.c gcc/function.c
index ec2ea26..922f567 100644
--- gcc/function.c
+++ gcc/function.c
@@ -4649,7 +4649,7 @@ stack_protect_epilogue (void)
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch (HAVE_stack_protect_test != 0)
+  switch ((int) (HAVE_stack_protect_test != 0))
     {
     case 1:
       tmp = gen_stack_protect_test (x, y, label);
diff --git gcc/gengtype.c gcc/gengtype.c
index 808ef45..9da6545 100644
--- gcc/gengtype.c
+++ gcc/gengtype.c
@@ -3099,9 +3099,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       t->u.s.tag);
 		desc = "1";
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	  }
@@ -3121,9 +3121,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       "missing `tag' option for type `%s'",
 			       t->u.s.tag);
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	    oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
diff --git gcc/testsuite/c-c++-common/pr60439.c gcc/testsuite/c-c++-common/pr60439.c
index e69de29..89288d7 100644
--- gcc/testsuite/c-c++-common/pr60439.c
+++ gcc/testsuite/c-c++-common/pr60439.c
@@ -0,0 +1,108 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+extern bool foo (void);
+
+void
+f1 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  /* No warnings on following.  */
+  switch ((int) (a && b))
+    break;
+  switch ((unsigned int) (a && b))
+    break;
+  switch ((unsigned short int) (a && b))
+    break;
+  switch ((char) (a && b))
+    break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (!a) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a != 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a > 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a < 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a <= 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a >= 3) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    break;
+  switch ((int) (a == 3))
+    break;
+  switch ((int) (a != 3))
+    break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (!b) /* { dg-warning "switch condition has boolean value" } */
+    break;
+  switch (b++) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    break;
+  switch ((int) i)
+    break;
+  switch ((unsigned int) i)
+    break;
+  switch ((bool) i) /* { dg-warning "switch condition has boolean value" } */
+    break;
+}
diff --git gcc/testsuite/g++.dg/eh/scope1.C gcc/testsuite/g++.dg/eh/scope1.C
index 276e0d6..4884ec7 100644
--- gcc/testsuite/g++.dg/eh/scope1.C
+++ gcc/testsuite/g++.dg/eh/scope1.C
@@ -31,7 +31,7 @@ void f3 ()
 
 void f4 ()
 {
-  switch (C br = C())
+  switch (C br = C()) /* { dg-warning "switch condition has boolean value" } */
     {
     default:
       abort ();

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-05-24  8:01       ` Marek Polacek
@ 2014-06-02 22:00         ` Jason Merrill
  2014-06-03 14:57           ` Marek Polacek
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2014-06-02 22:00 UTC (permalink / raw)
  To: Marek Polacek, Jeff Law; +Cc: Steven Bosscher, GCC Patches, Joseph S. Myers

On 05/24/2014 04:00 AM, Marek Polacek wrote:
> +	  /* Warn if the condition has boolean value.  */
> +	  tree e = cond;
> +	  while (TREE_CODE (e) == COMPOUND_EXPR)
> +	    e = TREE_OPERAND (e, 1);
> +
> +	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
> +	      || (truth_value_p (TREE_CODE (e))
> +		  && TREE_CODE (orig_type) != INTEGER_TYPE))
> +	    warning_at (input_location, OPT_Wswitch_bool,
> +			"switch condition has boolean value");

For C++ it should be "type bool", not "boolean value".  And it should be 
enough to just check for BOOLEAN_TYPE, without looking through 
COMPOUND_EXPR.

> 2) Since the warning is now enabled even for the C++ FE, it's
>    exercised during bootstrap.  Turned out that gengtype generates
>    code like
>    switch (TREE_CODE (...) == INTEGER_TYPE) { ... }
>    that would mar the bootstrap - so I tweaked it to generate
>    switch ((int) (TREE_CODE (...) == INTEGER_TYPE) { ... })
>    instead.  Does that make sense?

Makes sense to me.

Jason

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-06-02 22:00         ` Jason Merrill
@ 2014-06-03 14:57           ` Marek Polacek
  2014-06-03 15:46             ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Marek Polacek @ 2014-06-03 14:57 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Steven Bosscher, GCC Patches, Joseph S. Myers

On Mon, Jun 02, 2014 at 06:00:04PM -0400, Jason Merrill wrote:
> On 05/24/2014 04:00 AM, Marek Polacek wrote:
> >+	  /* Warn if the condition has boolean value.  */
> >+	  tree e = cond;
> >+	  while (TREE_CODE (e) == COMPOUND_EXPR)
> >+	    e = TREE_OPERAND (e, 1);
> >+
> >+	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
> >+	      || (truth_value_p (TREE_CODE (e))
> >+		  && TREE_CODE (orig_type) != INTEGER_TYPE))
> >+	    warning_at (input_location, OPT_Wswitch_bool,
> >+			"switch condition has boolean value");
> 
> For C++ it should be "type bool", not "boolean value".  And it should be

Ok, changed (but not for C), and adjusted the testcase.

> enough to just check for BOOLEAN_TYPE, without looking through
> COMPOUND_EXPR.
 
Nice.  I dropped looking through COMPOUND_EXPR.

> >2) Since the warning is now enabled even for the C++ FE, it's
> >   exercised during bootstrap.  Turned out that gengtype generates
> >   code like
> >   switch (TREE_CODE (...) == INTEGER_TYPE) { ... }
> >   that would mar the bootstrap - so I tweaked it to generate
> >   switch ((int) (TREE_CODE (...) == INTEGER_TYPE) { ... })
> >   instead.  Does that make sense?
> 
> Makes sense to me.

Thanks.  I regtested the following, bootstrap is still in progress, but
I don't expect any issues.

Ok?

2014-06-03  Marek Polacek  <polacek@redhat.com>

	PR c/60439
	* doc/invoke.texi: Document -Wswitch-bool.
	* function.c (stack_protect_epilogue): Cast controlling expression of
	the switch to int.
	* gengtype.c (walk_type): Generate switch expression with its
	controlling expression cast to int.
c/
	* c-parser.c (c_parser_switch_statement): Pass explicit_cast_p to
	c_start_case.
	* c-tree.h (c_start_case): Update.
	* c-typeck.c (c_start_case): Add new boolean parameter.  Warn if
	switch condition has boolean value.
cp/
	* semantics.c (finish_switch_cond): Warn if switch condition has
	boolean value.
c-family/
	* c.opt (Wswitch-bool): New option.
testsuite/
	* c-c++-common/pr60439.c: New test.
	* g++.dg/eh/scope1.C (f4): Add dg-warning.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index c586e65..5d36a80 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -534,6 +534,10 @@ Wswitch-enum
 C ObjC C++ ObjC++ Var(warn_switch_enum) Warning
 Warn about all enumerated switches missing a specific case
 
+Wswitch-bool
+C ObjC C++ ObjC++ Warning Init(1)
+Warn about switches with boolean controlling expression
+
 Wmissing-format-attribute
 C ObjC C++ ObjC++ Alias(Wsuggest-attribute=format)
 ;
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 1d9780e..abd636c 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -5197,9 +5197,13 @@ c_parser_switch_statement (c_parser *parser)
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
+  bool explicit_cast_p = false;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       switch_cond_loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+	  && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+	explicit_cast_p = true;
       ce = c_parser_expression (parser);
       ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
       expr = ce.value;
@@ -5217,7 +5221,7 @@ c_parser_switch_statement (c_parser *parser)
       switch_cond_loc = UNKNOWN_LOCATION;
       expr = error_mark_node;
     }
-  c_start_case (switch_loc, switch_cond_loc, expr);
+  c_start_case (switch_loc, switch_cond_loc, expr, explicit_cast_p);
   save_break = c_break_label;
   c_break_label = NULL_TREE;
   body = c_parser_c99_block_statement (parser);
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index e7dcb35..133930f 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -614,7 +614,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
 				  struct obstack *);
 extern tree build_compound_literal (location_t, tree, tree, bool);
 extern void check_compound_literal_type (location_t, struct c_type_name *);
-extern tree c_start_case (location_t, location_t, tree);
+extern tree c_start_case (location_t, location_t, tree, bool);
 extern void c_finish_case (tree);
 extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
 extern tree build_asm_stmt (tree, tree);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 6ca584b..a98ce07 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9361,12 +9361,13 @@ struct c_switch *c_switch_stack;
 
 /* Start a C switch statement, testing expression EXP.  Return the new
    SWITCH_EXPR.  SWITCH_LOC is the location of the `switch'.
-   SWITCH_COND_LOC is the location of the switch's condition.  */
+   SWITCH_COND_LOC is the location of the switch's condition.
+   EXPLICIT_CAST_P is true if the expression EXP has explicit cast.  */
 
 tree
 c_start_case (location_t switch_loc,
 	      location_t switch_cond_loc,
-	      tree exp)
+	      tree exp, bool explicit_cast_p)
 {
   tree orig_type = error_mark_node;
   struct c_switch *cs;
@@ -9387,6 +9388,19 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+
+	  /* Warn if the condition has boolean value.  */
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+
+	  if ((TREE_CODE (type) == BOOLEAN_TYPE
+	       || truth_value_p (TREE_CODE (e)))
+	      /* Explicit cast to int suppresses this warning.  */
+	      && !(TREE_CODE (type) == INTEGER_TYPE
+		   && explicit_cast_p))
+	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 21920b4..abd668e 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -1130,6 +1130,13 @@ finish_switch_cond (tree cond, tree switch_stmt)
       orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
 	{
+	  /* Warn if the condition has boolean value.  */
+	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
+	      || (truth_value_p (TREE_CODE (cond))
+		  && TREE_CODE (orig_type) != INTEGER_TYPE))
+	    warning_at (input_location, OPT_Wswitch_bool,
+			"switch condition has type bool");
+
 	  /* [stmt.switch]
 
 	     Integral promotions are performed.  */
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 6db0d55..1c2e079 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -271,7 +271,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
--Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
+-Wswitch  -Wswitch-default  -Wswitch-enum -Wswitch-bool -Wsync-nand @gol
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
@@ -3846,6 +3846,22 @@ between @option{-Wswitch} and this option is that this option gives a
 warning about an omitted enumeration code even if there is a
 @code{default} label.
 
+@item -Wswitch-bool
+@opindex Wswitch-bool
+@opindex Wno-switch-bool
+Warn whenever a @code{switch} statement has an index of boolean type.
+It is possible to suppress this warning by casting the controlling
+expression to a type other than @code{bool}.  For example:
+@smallexample
+@group
+switch ((int) (a == 4))
+  @{
+  ...
+  @}
+@end group
+@end smallexample
+This warning is enabled by default for C and C++ programs.
+
 @item -Wsync-nand @r{(C and C++ only)}
 @opindex Wsync-nand
 @opindex Wno-sync-nand
diff --git gcc/function.c gcc/function.c
index ec2ea26..922f567 100644
--- gcc/function.c
+++ gcc/function.c
@@ -4649,7 +4649,7 @@ stack_protect_epilogue (void)
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch (HAVE_stack_protect_test != 0)
+  switch ((int) (HAVE_stack_protect_test != 0))
     {
     case 1:
       tmp = gen_stack_protect_test (x, y, label);
diff --git gcc/gengtype.c gcc/gengtype.c
index bc8f701..ffe3f94 100644
--- gcc/gengtype.c
+++ gcc/gengtype.c
@@ -3099,9 +3099,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       t->u.s.tag);
 		desc = "1";
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	  }
@@ -3121,9 +3121,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       "missing `tag' option for type `%s'",
 			       t->u.s.tag);
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	    oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
diff --git gcc/testsuite/c-c++-common/pr60439.c gcc/testsuite/c-c++-common/pr60439.c
index e69de29..3368a0b 100644
--- gcc/testsuite/c-c++-common/pr60439.c
+++ gcc/testsuite/c-c++-common/pr60439.c
@@ -0,0 +1,108 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+extern bool foo (void);
+
+void
+f1 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has" } */
+    break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has" } */
+    break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has" } */
+    break;
+  /* No warnings on following.  */
+  switch ((int) (a && b))
+    break;
+  switch ((unsigned int) (a && b))
+    break;
+  switch ((unsigned short int) (a && b))
+    break;
+  switch ((char) (a && b))
+    break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has" } */
+    break;
+  switch (!a) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a != 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a > 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a < 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a <= 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a >= 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    break;
+  switch ((int) (a == 3))
+    break;
+  switch ((int) (a != 3))
+    break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has" } */
+    break;
+  switch (!b) /* { dg-warning "switch condition has" } */
+    break;
+  switch (b++) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    break;
+  switch ((int) i)
+    break;
+  switch ((unsigned int) i)
+    break;
+  switch ((bool) i) /* { dg-warning "switch condition has" } */
+    break;
+}
diff --git gcc/testsuite/g++.dg/eh/scope1.C gcc/testsuite/g++.dg/eh/scope1.C
index 276e0d6..4884ec7 100644
--- gcc/testsuite/g++.dg/eh/scope1.C
+++ gcc/testsuite/g++.dg/eh/scope1.C
@@ -31,7 +31,7 @@ void f3 ()
 
 void f4 ()
 {
-  switch (C br = C())
+  switch (C br = C()) /* { dg-warning "switch condition has" } */
     {
     default:
       abort ();

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-06-03 14:57           ` Marek Polacek
@ 2014-06-03 15:46             ` Jason Merrill
  2014-06-03 16:00               ` Marek Polacek
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2014-06-03 15:46 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jeff Law, Steven Bosscher, GCC Patches, Joseph S. Myers

On 06/03/2014 10:57 AM, Marek Polacek wrote:
> +	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
> +	      || (truth_value_p (TREE_CODE (cond))
> +		  && TREE_CODE (orig_type) != INTEGER_TYPE))

I don't think you need the truth_value_p check, either, just the 
BOOLEAN_TYPE check.

Jason

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-06-03 15:46             ` Jason Merrill
@ 2014-06-03 16:00               ` Marek Polacek
  2014-06-03 17:21                 ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Marek Polacek @ 2014-06-03 16:00 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Steven Bosscher, GCC Patches, Joseph S. Myers

On Tue, Jun 03, 2014 at 11:46:35AM -0400, Jason Merrill wrote:
> On 06/03/2014 10:57 AM, Marek Polacek wrote:
> >+	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE
> >+	      || (truth_value_p (TREE_CODE (cond))
> >+		  && TREE_CODE (orig_type) != INTEGER_TYPE))
> 
> I don't think you need the truth_value_p check, either, just the
> BOOLEAN_TYPE check.

Oh yeah, since the type of &&, ||, etc. exprs is in C++ bool...
Done in the following, the testcases still passes.  Otherwise no
changes.

2014-06-03  Marek Polacek  <polacek@redhat.com>

	PR c/60439
	* doc/invoke.texi: Document -Wswitch-bool.
	* function.c (stack_protect_epilogue): Cast controlling expression of
	the switch to int.
	* gengtype.c (walk_type): Generate switch expression with its
	controlling expression cast to int.
c/
	* c-parser.c (c_parser_switch_statement): Pass explicit_cast_p to
	c_start_case.
	* c-tree.h (c_start_case): Update.
	* c-typeck.c (c_start_case): Add new boolean parameter.  Warn if
	switch condition has boolean value.
cp/
	* semantics.c (finish_switch_cond): Warn if switch condition has
	boolean value.
c-family/
	* c.opt (Wswitch-bool): New option.
testsuite/
	* c-c++-common/pr60439.c: New test.
	* g++.dg/eh/scope1.C (f4): Add dg-warning.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index c586e65..5d36a80 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -534,6 +534,10 @@ Wswitch-enum
 C ObjC C++ ObjC++ Var(warn_switch_enum) Warning
 Warn about all enumerated switches missing a specific case
 
+Wswitch-bool
+C ObjC C++ ObjC++ Warning Init(1)
+Warn about switches with boolean controlling expression
+
 Wmissing-format-attribute
 C ObjC C++ ObjC++ Alias(Wsuggest-attribute=format)
 ;
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 1d9780e..abd636c 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -5197,9 +5197,13 @@ c_parser_switch_statement (c_parser *parser)
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
+  bool explicit_cast_p = false;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       switch_cond_loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+	  && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+	explicit_cast_p = true;
       ce = c_parser_expression (parser);
       ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
       expr = ce.value;
@@ -5217,7 +5221,7 @@ c_parser_switch_statement (c_parser *parser)
       switch_cond_loc = UNKNOWN_LOCATION;
       expr = error_mark_node;
     }
-  c_start_case (switch_loc, switch_cond_loc, expr);
+  c_start_case (switch_loc, switch_cond_loc, expr, explicit_cast_p);
   save_break = c_break_label;
   c_break_label = NULL_TREE;
   body = c_parser_c99_block_statement (parser);
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index e7dcb35..133930f 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -614,7 +614,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
 				  struct obstack *);
 extern tree build_compound_literal (location_t, tree, tree, bool);
 extern void check_compound_literal_type (location_t, struct c_type_name *);
-extern tree c_start_case (location_t, location_t, tree);
+extern tree c_start_case (location_t, location_t, tree, bool);
 extern void c_finish_case (tree);
 extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
 extern tree build_asm_stmt (tree, tree);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 6ca584b..a98ce07 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9361,12 +9361,13 @@ struct c_switch *c_switch_stack;
 
 /* Start a C switch statement, testing expression EXP.  Return the new
    SWITCH_EXPR.  SWITCH_LOC is the location of the `switch'.
-   SWITCH_COND_LOC is the location of the switch's condition.  */
+   SWITCH_COND_LOC is the location of the switch's condition.
+   EXPLICIT_CAST_P is true if the expression EXP has explicit cast.  */
 
 tree
 c_start_case (location_t switch_loc,
 	      location_t switch_cond_loc,
-	      tree exp)
+	      tree exp, bool explicit_cast_p)
 {
   tree orig_type = error_mark_node;
   struct c_switch *cs;
@@ -9387,6 +9388,19 @@ c_start_case (location_t switch_loc,
       else
 	{
 	  tree type = TYPE_MAIN_VARIANT (orig_type);
+	  tree e = exp;
+
+	  /* Warn if the condition has boolean value.  */
+	  while (TREE_CODE (e) == COMPOUND_EXPR)
+	    e = TREE_OPERAND (e, 1);
+
+	  if ((TREE_CODE (type) == BOOLEAN_TYPE
+	       || truth_value_p (TREE_CODE (e)))
+	      /* Explicit cast to int suppresses this warning.  */
+	      && !(TREE_CODE (type) == INTEGER_TYPE
+		   && explicit_cast_p))
+	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
+			"switch condition has boolean value");
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 21920b4..c1c16f4 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -1130,6 +1130,11 @@ finish_switch_cond (tree cond, tree switch_stmt)
       orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
 	{
+	  /* Warn if the condition has boolean value.  */
+	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE)
+	    warning_at (input_location, OPT_Wswitch_bool,
+			"switch condition has type bool");
+
 	  /* [stmt.switch]
 
 	     Integral promotions are performed.  */
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 6db0d55..1c2e079 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -271,7 +271,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
--Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
+-Wswitch  -Wswitch-default  -Wswitch-enum -Wswitch-bool -Wsync-nand @gol
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
@@ -3846,6 +3846,22 @@ between @option{-Wswitch} and this option is that this option gives a
 warning about an omitted enumeration code even if there is a
 @code{default} label.
 
+@item -Wswitch-bool
+@opindex Wswitch-bool
+@opindex Wno-switch-bool
+Warn whenever a @code{switch} statement has an index of boolean type.
+It is possible to suppress this warning by casting the controlling
+expression to a type other than @code{bool}.  For example:
+@smallexample
+@group
+switch ((int) (a == 4))
+  @{
+  ...
+  @}
+@end group
+@end smallexample
+This warning is enabled by default for C and C++ programs.
+
 @item -Wsync-nand @r{(C and C++ only)}
 @opindex Wsync-nand
 @opindex Wno-sync-nand
diff --git gcc/function.c gcc/function.c
index ec2ea26..922f567 100644
--- gcc/function.c
+++ gcc/function.c
@@ -4649,7 +4649,7 @@ stack_protect_epilogue (void)
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch (HAVE_stack_protect_test != 0)
+  switch ((int) (HAVE_stack_protect_test != 0))
     {
     case 1:
       tmp = gen_stack_protect_test (x, y, label);
diff --git gcc/gengtype.c gcc/gengtype.c
index bc8f701..ffe3f94 100644
--- gcc/gengtype.c
+++ gcc/gengtype.c
@@ -3099,9 +3099,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       t->u.s.tag);
 		desc = "1";
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	  }
@@ -3121,9 +3121,9 @@ walk_type (type_p t, struct walk_type_data *d)
 			       "missing `tag' option for type `%s'",
 			       t->u.s.tag);
 	      }
-	    oprintf (d->of, "%*sswitch (", d->indent, "");
+	    oprintf (d->of, "%*sswitch ((int) (", d->indent, "");
 	    output_escaped_param (d, desc, "desc");
-	    oprintf (d->of, ")\n");
+	    oprintf (d->of, "))\n");
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	    oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
diff --git gcc/testsuite/c-c++-common/pr60439.c gcc/testsuite/c-c++-common/pr60439.c
index e69de29..3368a0b 100644
--- gcc/testsuite/c-c++-common/pr60439.c
+++ gcc/testsuite/c-c++-common/pr60439.c
@@ -0,0 +1,108 @@
+/* PR c/60439 */
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+extern bool foo (void);
+
+void
+f1 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f2 (int a, int b)
+{
+  switch (a && b) /* { dg-warning "switch condition has" } */
+    break;
+  switch ((bool) (a && b)) /* { dg-warning "switch condition has" } */
+    break;
+  switch ((a && b) || a) /* { dg-warning "switch condition has" } */
+    break;
+  /* No warnings on following.  */
+  switch ((int) (a && b))
+    break;
+  switch ((unsigned int) (a && b))
+    break;
+  switch ((unsigned short int) (a && b))
+    break;
+  switch ((char) (a && b))
+    break;
+}
+
+void
+f3 (int a)
+{
+  switch (!!a) /* { dg-warning "switch condition has" } */
+    break;
+  switch (!a) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f4 (void)
+{
+  switch (foo ()) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f5 (int a)
+{
+  switch (a == 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a != 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a > 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a < 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a <= 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a >= 3) /* { dg-warning "switch condition has" } */
+    break;
+  switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has" } */
+    break;
+  switch (a == 3, a & 4, a ^ 5, a)
+    break;
+  switch ((int) (a == 3))
+    break;
+  switch ((int) (a != 3))
+    break;
+}
+
+void
+f6 (bool b)
+{
+  switch (b) /* { dg-warning "switch condition has" } */
+    break;
+  switch (!b) /* { dg-warning "switch condition has" } */
+    break;
+  switch (b++) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f7 (void)
+{
+  bool b;
+  switch (b = 1) /* { dg-warning "switch condition has" } */
+    break;
+}
+
+void
+f8 (int i)
+{
+  switch (i)
+    break;
+  switch ((int) i)
+    break;
+  switch ((unsigned int) i)
+    break;
+  switch ((bool) i) /* { dg-warning "switch condition has" } */
+    break;
+}
diff --git gcc/testsuite/g++.dg/eh/scope1.C gcc/testsuite/g++.dg/eh/scope1.C
index 276e0d6..8d553d8 100644
--- gcc/testsuite/g++.dg/eh/scope1.C
+++ gcc/testsuite/g++.dg/eh/scope1.C
@@ -31,7 +31,7 @@ void f3 ()
 
 void f4 ()
 {
-  switch (C br = C())
+  switch (C br = C()) /* { dg-warning "switch condition has" } */
     {
     default:
       abort ();

	Marek

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

* Re: [C PATCH] Warn if switch has boolean value (PR c/60439)
  2014-06-03 16:00               ` Marek Polacek
@ 2014-06-03 17:21                 ` Jason Merrill
  0 siblings, 0 replies; 15+ messages in thread
From: Jason Merrill @ 2014-06-03 17:21 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jeff Law, Steven Bosscher, GCC Patches, Joseph S. Myers

OK.

Jason

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

end of thread, other threads:[~2014-06-03 17:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-18  5:49 [C PATCH] Warn if switch has boolean value (PR c/60439) Marek Polacek
2014-04-18  6:00 ` Marc Glisse
2014-04-18  6:42   ` Marek Polacek
2014-04-18  7:09     ` Marek Polacek
2014-04-18  8:03   ` Jakub Jelinek
2014-04-18 11:24 ` Steven Bosscher
2014-04-18 12:21   ` Marc Glisse
2014-04-18 12:41   ` Marek Polacek
2014-05-02  5:09     ` Jeff Law
2014-05-24  8:01       ` Marek Polacek
2014-06-02 22:00         ` Jason Merrill
2014-06-03 14:57           ` Marek Polacek
2014-06-03 15:46             ` Jason Merrill
2014-06-03 16:00               ` Marek Polacek
2014-06-03 17:21                 ` Jason Merrill

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