diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 78661833f54..406179f1764 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,13 @@ -2014-06-03 Vishnu K S +2014-06-03 Marek Polacek + + 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. + +2014-06-03 Vishnu K S * config/avr/avr-mcus.def: Add new avr25 devices attiny441, attiny828 and attiny841. @@ -6,8 +15,8 @@ * config/avr/t-multilib: Regenerate. * doc/avr-mmcu.texi: Regenerate. -2014-06-03 Vishnu K S - Pitchumani Sivanupandi +2014-06-03 Vishnu K S + Pitchumani Sivanupandi * config/avr/avr-mcus.def (ata6616c): Add new avr25 device. (ata6617c, ata664251): Add new avr35 devices. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 675a66e9482..86267f4b33f 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2014-06-03 Marek Polacek + + PR c/60439 + * c.opt (Wswitch-bool): New option. + 2014-05-22 Thomas Schwinge * c-common.h (c_omp_sharing_predetermined, c_omp_remap_decl): diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index c586e659e0f..5d36a80408d 100644 --- a/gcc/c-family/c.opt +++ b/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 a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 536e07e38d9..1047a65b636 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,12 @@ +2014-06-03 Marek Polacek + + PR c/60439 + * 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. + 2014-06-02 Andrew MacLeod * c-decl.c: Include builtins.h. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 1d9780edf4e..abd636c5436 100644 --- a/gcc/c/c-parser.c +++ b/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 a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e7dcb355e9c..133930f4a09 100644 --- a/gcc/c/c-tree.h +++ b/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 a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 6ca584bf38c..a98ce0786f3 100644 --- a/gcc/c/c-typeck.c +++ b/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 a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f356caa6c84..2fa1549f963 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2014-06-03 Marek Polacek + + PR c/60439 + * semantics.c (finish_switch_cond): Warn if switch condition has + boolean value. + 2014-06-03 Jason Merrill PR c++/60992 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 21920b41ca5..c1c16f49f93 100644 --- a/gcc/cp/semantics.c +++ b/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 a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6db0d5587e7..1c2e0795334 100644 --- a/gcc/doc/invoke.texi +++ b/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 a/gcc/function.c b/gcc/function.c index ec2ea26628b..922f567734e 100644 --- a/gcc/function.c +++ b/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 a/gcc/gengtype.c b/gcc/gengtype.c index bc8f7010e83..ffe3f94a6ae 100644 --- a/gcc/gengtype.c +++ b/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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 14d79e1842f..c409d99f211 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-06-03 Marek Polacek + + PR c/60439 + * c-c++-common/pr60439.c: New test. + * g++.dg/eh/scope1.C (f4): Add dg-warning. + 2014-06-03 Martin Jambor PR ipa/61160 diff --git a/gcc/testsuite/c-c++-common/pr60439.c b/gcc/testsuite/c-c++-common/pr60439.c new file mode 100644 index 00000000000..3368a0b944d --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/eh/scope1.C b/gcc/testsuite/g++.dg/eh/scope1.C index 276e0d6e588..8d553d8295b 100644 --- a/gcc/testsuite/g++.dg/eh/scope1.C +++ b/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 ();