* [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
@ 2014-09-19 13:29 Marek Polacek
2014-09-19 13:33 ` Jakub Jelinek
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Marek Polacek @ 2014-09-19 13:29 UTC (permalink / raw)
To: GCC Patches, Jason Merrill, Joseph S. Myers, Jakub Jelinek, Jan Hubicka
This patch makes -Wswitch{,-enum} work even with enum bit-fields (we got
several bugreports about that).
The problem is that enum e:2; has an integral type with precision 2,
and c_do_switch_warnings doesn't like that:
6195 /* From here on, we only care about about enumerated types. */
6196 if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
6197 return;
(we need to look at TYPE_VALUES of the type).
But there's a way how to get the enum.
For C, the original type is saved in ce.original_type after
c_parser_expression has done its job - and it seems viable to just
pass this down to c_finish_case. Though this original type can be
NULL, in that case I pass the type of cs->switch_expr to
c_do_switch_warnings - the same what we did before. (Setting
cs->original_type didn't pan out - the code elsewhere doesn't seem
to be ready to handle that.)
For C++, I think easiest would be to handle enum bit-fields specially:
set SWITCH_STMT_TYPE to the enum type. The rest of the code seems to
cope with this well, at least I haven't seen any regressions.
With this I had to tweak several places in the compiler. E.g.
DECL_FUNCTION_CODE is defined as an enum bit-field, meaning that we
started to warn on switches such as switch (DECL_FUNCTION_CODE (x)).
Adding default case fixes this. But we also started to warn on
CPP_KEYWORD and two others: "case value not in enumerated type".
Fixed by moving CPP_KEYWORD, CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER
into enum cpp_ttype. Not sure if this is going to hurt something else.
In lto-streamer-out.c we started to warn with "may be uninitialized"
for some reason - seems bogus.
Jason, does the C++ part look sane?
Joseph, does the C part look sane?
Jakub, does the asan.c change look ok?
Honza, does the IPA/predict/lto changes look ok?
Thanks.
Bootstrapped/regtested on x86_64-linux.
2014-09-19 Marek Polacek <polacek@redhat.com>
PR c/61405
PR c/53874
gcc/
* asan.c (maybe_instrument_call): Add default case.
* ipa-pure-const.c (special_builtin_state): Likewise.
* predict.c (expr_expected_value_1): Likewise.
* lto-streamer-out.c (write_symbol): Initialize variable.
gcc/c-family/
* c-common.h (struct c_common_resword): Don't define CPP_KEYWORD,
CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER.
gcc/c/
* c-parser.c (c_parser_switch_statement): Pass original type to
c_finish_case.
* c-tree.h (c_finish_case): Update declaration.
* c-typeck.c (c_finish_case): Add TYPE parameter. Pass it
conditionally to c_do_switch_warnings.
gcc/cp/
* semantics.c (finish_switch_cond): Handle enum bit-fields.
* tree.c (bot_manip): Add default case.
gcc/testsuite/
* c-c++-common/pr53874.c: New test.
* c-c++-common/pr61405.c: New test.
libcpp/
* include/cpplib.h (enum cpp_ttype): Define CPP_KEYWORD,
CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER.
diff --git gcc/gcc/asan.c gcc/gcc/asan.c
index 2a90d86..bca95df 100644
--- gcc/gcc/asan.c
+++ gcc/gcc/asan.c
@@ -2024,6 +2024,8 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
case BUILT_IN_TRAP:
/* Don't instrument these. */
return false;
+ default:
+ break;
}
}
tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 993a97b..c9f38f3 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -327,22 +327,6 @@ struct c_common_resword
/* Extra cpp_ttype values for C++. */
-/* A token type for keywords, as opposed to ordinary identifiers. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
-/* A token type for template-ids. If a template-id is processed while
- parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
- the value of the CPP_TEMPLATE_ID is whatever was returned by
- cp_parser_template_id. */
-#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
-
-/* A token type for nested-name-specifiers. If a
- nested-name-specifier is processed while parsing tentatively, it is
- replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
- CPP_NESTED_NAME_SPECIFIER is whatever was returned by
- cp_parser_nested_name_specifier_opt. */
-#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
-
/* A token type for pre-parsed C++0x decltype. */
#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 3f4a92b..551fd7f 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -5232,7 +5232,7 @@ c_parser_switch_statement (c_parser *parser)
save_break = c_break_label;
c_break_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
- c_finish_case (body);
+ c_finish_case (body, ce.original_type);
if (c_break_label)
{
location_t here = c_parser_peek_token (parser)->location;
diff --git gcc/gcc/c/c-tree.h gcc/gcc/c/c-tree.h
index 6004d50..fc145a85 100644
--- gcc/gcc/c/c-tree.h
+++ gcc/gcc/c/c-tree.h
@@ -618,7 +618,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
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, bool);
-extern void c_finish_case (tree);
+extern void c_finish_case (tree, tree);
extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
extern tree build_asm_stmt (tree, tree);
extern int c_types_compatible_p (tree, tree);
diff --git gcc/gcc/c/c-typeck.c gcc/gcc/c/c-typeck.c
index da71ab2..f69c28b 100644
--- gcc/gcc/c/c-typeck.c
+++ gcc/gcc/c/c-typeck.c
@@ -9486,10 +9486,11 @@ do_case (location_t loc, tree low_value, tree high_value)
return label;
}
-/* Finish the switch statement. */
+/* Finish the switch statement. TYPE is the original type of the
+ controlling expression of the switch, or NULL_TREE. */
void
-c_finish_case (tree body)
+c_finish_case (tree body, tree type)
{
struct c_switch *cs = c_switch_stack;
location_t switch_location;
@@ -9499,7 +9500,7 @@ c_finish_case (tree body)
/* Emit warnings as needed. */
switch_location = EXPR_LOCATION (cs->switch_expr);
c_do_switch_warnings (cs->cases, switch_location,
- TREE_TYPE (cs->switch_expr),
+ type ? type : TREE_TYPE (cs->switch_expr),
SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
diff --git gcc/gcc/cp/semantics.c gcc/gcc/cp/semantics.c
index bcf161b..a8d26ed 100644
--- gcc/gcc/cp/semantics.c
+++ gcc/gcc/cp/semantics.c
@@ -1127,7 +1127,15 @@ finish_switch_cond (tree cond, tree switch_stmt)
error ("switch quantity not an integer");
cond = error_mark_node;
}
- orig_type = TREE_TYPE (cond);
+ /* Handle enum bit-fields. */
+ tree field;
+ if (TREE_CODE (cond) == COMPONENT_REF
+ && (field = TREE_OPERAND (cond, 1))
+ && DECL_BIT_FIELD_TYPE (field)
+ && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE)
+ orig_type = DECL_BIT_FIELD_TYPE (field);
+ else
+ orig_type = TREE_TYPE (cond);
if (cond != error_mark_node)
{
/* Warn if the condition has boolean value. */
diff --git gcc/gcc/cp/tree.c gcc/gcc/cp/tree.c
index d0e1180..a7bb38b 100644
--- gcc/gcc/cp/tree.c
+++ gcc/gcc/cp/tree.c
@@ -2345,6 +2345,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
case BUILT_IN_FILE:
case BUILT_IN_LINE:
SET_EXPR_LOCATION (*tp, input_location);
+ default:
+ break;
}
}
return t;
diff --git gcc/gcc/ipa-pure-const.c gcc/gcc/ipa-pure-const.c
index 459d08d..b5ded3e 100644
--- gcc/gcc/ipa-pure-const.c
+++ gcc/gcc/ipa-pure-const.c
@@ -451,6 +451,8 @@ special_builtin_state (enum pure_const_state_e *state, bool *looping,
*looping = true;
*state = IPA_CONST;
return true;
+ default:
+ break;
}
return false;
}
diff --git gcc/gcc/lto-streamer-out.c gcc/gcc/lto-streamer-out.c
index b516c7b..cff48ee 100644
--- gcc/gcc/lto-streamer-out.c
+++ gcc/gcc/lto-streamer-out.c
@@ -2422,7 +2422,7 @@ write_symbol (struct streamer_tree_cache_d *cache,
{
const char *name;
enum gcc_plugin_symbol_kind kind;
- enum gcc_plugin_symbol_visibility visibility;
+ enum gcc_plugin_symbol_visibility visibility = GCCPV_DEFAULT;
unsigned slot_num;
uint64_t size;
const char *comdat;
diff --git gcc/gcc/predict.c gcc/gcc/predict.c
index eb5db2a..4e38d0e 100644
--- gcc/gcc/predict.c
+++ gcc/gcc/predict.c
@@ -1902,6 +1902,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
if (predictor)
*predictor = PRED_COMPARE_AND_SWAP;
return boolean_true_node;
+ default:
+ break;
}
}
diff --git gcc/gcc/testsuite/c-c++-common/pr53874.c gcc/gcc/testsuite/c-c++-common/pr53874.c
index e69de29..153f997 100644
--- gcc/gcc/testsuite/c-c++-common/pr53874.c
+++ gcc/gcc/testsuite/c-c++-common/pr53874.c
@@ -0,0 +1,35 @@
+/* PR c/53874 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch-enum" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
diff --git gcc/gcc/testsuite/c-c++-common/pr61405.c gcc/gcc/testsuite/c-c++-common/pr61405.c
index e69de29..9c05a84 100644
--- gcc/gcc/testsuite/c-c++-common/pr61405.c
+++ gcc/gcc/testsuite/c-c++-common/pr61405.c
@@ -0,0 +1,31 @@
+/* PR c/61405 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index 62d271b..bd6e0f4 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -153,6 +153,22 @@ enum cpp_ttype
TTYPE_TABLE
N_TTYPES,
+ /* A token type for keywords, as opposed to ordinary identifiers. */
+ CPP_KEYWORD = N_TTYPES + 1,
+
+ /* A token type for template-ids. If a template-id is processed while
+ parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
+ the value of the CPP_TEMPLATE_ID is whatever was returned by
+ cp_parser_template_id. */
+ CPP_TEMPLATE_ID = CPP_KEYWORD + 1,
+
+ /* A token type for nested-name-specifiers. If a
+ nested-name-specifier is processed while parsing tentatively, it is
+ replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
+ CPP_NESTED_NAME_SPECIFIER is whatever was returned by
+ cp_parser_nested_name_specifier_opt. */
+ CPP_NESTED_NAME_SPECIFIER = CPP_TEMPLATE_ID + 1,
+
/* Positions in the table. */
CPP_LAST_EQ = CPP_LSHIFT,
CPP_FIRST_DIGRAPH = CPP_HASH,
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
2014-09-19 13:29 [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874) Marek Polacek
@ 2014-09-19 13:33 ` Jakub Jelinek
2014-09-19 15:19 ` Jason Merrill
2014-09-19 19:39 ` Jason Merrill
2 siblings, 0 replies; 7+ messages in thread
From: Jakub Jelinek @ 2014-09-19 13:33 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches, Jason Merrill, Joseph S. Myers, Jan Hubicka
On Fri, Sep 19, 2014 at 03:29:44PM +0200, Marek Polacek wrote:
> Jakub, does the asan.c change look ok?
> --- gcc/gcc/asan.c
> +++ gcc/gcc/asan.c
> @@ -2024,6 +2024,8 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
> case BUILT_IN_TRAP:
> /* Don't instrument these. */
> return false;
> + default:
> + break;
> }
> }
> tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
This hunk is fine, separately or together with the rest.
Jakub
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
2014-09-19 13:29 [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874) Marek Polacek
2014-09-19 13:33 ` Jakub Jelinek
@ 2014-09-19 15:19 ` Jason Merrill
2014-09-19 17:43 ` Marek Polacek
2014-09-19 19:39 ` Jason Merrill
2 siblings, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2014-09-19 15:19 UTC (permalink / raw)
To: Marek Polacek, GCC Patches, Joseph S. Myers, Jakub Jelinek, Jan Hubicka
On 09/19/2014 09:29 AM, Marek Polacek wrote:
> - orig_type = TREE_TYPE (cond);
> + /* Handle enum bit-fields. */
> + tree field;
> + if (TREE_CODE (cond) == COMPONENT_REF
> + && (field = TREE_OPERAND (cond, 1))
> + && DECL_BIT_FIELD_TYPE (field)
> + && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE)
> + orig_type = DECL_BIT_FIELD_TYPE (field);
> + else
> + orig_type = TREE_TYPE (cond);
You want unlowered_expr_type here.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
2014-09-19 15:19 ` Jason Merrill
@ 2014-09-19 17:43 ` Marek Polacek
0 siblings, 0 replies; 7+ messages in thread
From: Marek Polacek @ 2014-09-19 17:43 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches, Joseph S. Myers, Jakub Jelinek, Jan Hubicka
On Fri, Sep 19, 2014 at 11:19:14AM -0400, Jason Merrill wrote:
> On 09/19/2014 09:29 AM, Marek Polacek wrote:
> >- orig_type = TREE_TYPE (cond);
> >+ /* Handle enum bit-fields. */
> >+ tree field;
> >+ if (TREE_CODE (cond) == COMPONENT_REF
> >+ && (field = TREE_OPERAND (cond, 1))
> >+ && DECL_BIT_FIELD_TYPE (field)
> >+ && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE)
> >+ orig_type = DECL_BIT_FIELD_TYPE (field);
> >+ else
> >+ orig_type = TREE_TYPE (cond);
>
> You want unlowered_expr_type here.
Nice. So like this?
2014-09-19 Marek Polacek <polacek@redhat.com>
PR c/61405
PR c/53874
gcc/
* asan.c (maybe_instrument_call): Add default case.
* ipa-pure-const.c (special_builtin_state): Likewise.
* predict.c (expr_expected_value_1): Likewise.
* lto-streamer-out.c (write_symbol): Initialize variable.
gcc/c-family/
* c-common.h (struct c_common_resword): Don't define CPP_KEYWORD,
CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER.
gcc/c/
* c-parser.c (c_parser_switch_statement): Pass original type to
c_finish_case.
* c-tree.h (c_finish_case): Update declaration.
* c-typeck.c (c_finish_case): Add TYPE parameter. Pass it
conditionally to c_do_switch_warnings.
gcc/cp/
* semantics.c (finish_switch_cond): Call unlowered_expr_type.
* tree.c (bot_manip): Add default case.
gcc/testsuite/
* c-c++-common/pr53874.c: New test.
* c-c++-common/pr61405.c: New test.
libcpp/
* include/cpplib.h (enum cpp_ttype): Define CPP_KEYWORD,
CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER.
diff --git gcc/gcc/asan.c gcc/gcc/asan.c
index 2a90d86..bca95df 100644
--- gcc/gcc/asan.c
+++ gcc/gcc/asan.c
@@ -2024,6 +2024,8 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
case BUILT_IN_TRAP:
/* Don't instrument these. */
return false;
+ default:
+ break;
}
}
tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 993a97b..c9f38f3 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -327,22 +327,6 @@ struct c_common_resword
/* Extra cpp_ttype values for C++. */
-/* A token type for keywords, as opposed to ordinary identifiers. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
-/* A token type for template-ids. If a template-id is processed while
- parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
- the value of the CPP_TEMPLATE_ID is whatever was returned by
- cp_parser_template_id. */
-#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
-
-/* A token type for nested-name-specifiers. If a
- nested-name-specifier is processed while parsing tentatively, it is
- replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
- CPP_NESTED_NAME_SPECIFIER is whatever was returned by
- cp_parser_nested_name_specifier_opt. */
-#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
-
/* A token type for pre-parsed C++0x decltype. */
#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 3f4a92b..551fd7f 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -5232,7 +5232,7 @@ c_parser_switch_statement (c_parser *parser)
save_break = c_break_label;
c_break_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
- c_finish_case (body);
+ c_finish_case (body, ce.original_type);
if (c_break_label)
{
location_t here = c_parser_peek_token (parser)->location;
diff --git gcc/gcc/c/c-tree.h gcc/gcc/c/c-tree.h
index 6004d50..fc145a85 100644
--- gcc/gcc/c/c-tree.h
+++ gcc/gcc/c/c-tree.h
@@ -618,7 +618,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
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, bool);
-extern void c_finish_case (tree);
+extern void c_finish_case (tree, tree);
extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
extern tree build_asm_stmt (tree, tree);
extern int c_types_compatible_p (tree, tree);
diff --git gcc/gcc/c/c-typeck.c gcc/gcc/c/c-typeck.c
index da71ab2..f69c28b 100644
--- gcc/gcc/c/c-typeck.c
+++ gcc/gcc/c/c-typeck.c
@@ -9486,10 +9486,11 @@ do_case (location_t loc, tree low_value, tree high_value)
return label;
}
-/* Finish the switch statement. */
+/* Finish the switch statement. TYPE is the original type of the
+ controlling expression of the switch, or NULL_TREE. */
void
-c_finish_case (tree body)
+c_finish_case (tree body, tree type)
{
struct c_switch *cs = c_switch_stack;
location_t switch_location;
@@ -9499,7 +9500,7 @@ c_finish_case (tree body)
/* Emit warnings as needed. */
switch_location = EXPR_LOCATION (cs->switch_expr);
c_do_switch_warnings (cs->cases, switch_location,
- TREE_TYPE (cs->switch_expr),
+ type ? type : TREE_TYPE (cs->switch_expr),
SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
diff --git gcc/gcc/cp/semantics.c gcc/gcc/cp/semantics.c
index bcf161b..4974706 100644
--- gcc/gcc/cp/semantics.c
+++ gcc/gcc/cp/semantics.c
@@ -1127,7 +1127,8 @@ finish_switch_cond (tree cond, tree switch_stmt)
error ("switch quantity not an integer");
cond = error_mark_node;
}
- orig_type = TREE_TYPE (cond);
+ /* We want unlowered type here to handle enum bit-fields. */
+ orig_type = unlowered_expr_type (cond);
if (cond != error_mark_node)
{
/* Warn if the condition has boolean value. */
diff --git gcc/gcc/cp/tree.c gcc/gcc/cp/tree.c
index d0e1180..a7bb38b 100644
--- gcc/gcc/cp/tree.c
+++ gcc/gcc/cp/tree.c
@@ -2345,6 +2345,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
case BUILT_IN_FILE:
case BUILT_IN_LINE:
SET_EXPR_LOCATION (*tp, input_location);
+ default:
+ break;
}
}
return t;
diff --git gcc/gcc/ipa-pure-const.c gcc/gcc/ipa-pure-const.c
index 459d08d..b5ded3e 100644
--- gcc/gcc/ipa-pure-const.c
+++ gcc/gcc/ipa-pure-const.c
@@ -451,6 +451,8 @@ special_builtin_state (enum pure_const_state_e *state, bool *looping,
*looping = true;
*state = IPA_CONST;
return true;
+ default:
+ break;
}
return false;
}
diff --git gcc/gcc/lto-streamer-out.c gcc/gcc/lto-streamer-out.c
index b516c7b..cff48ee 100644
--- gcc/gcc/lto-streamer-out.c
+++ gcc/gcc/lto-streamer-out.c
@@ -2422,7 +2422,7 @@ write_symbol (struct streamer_tree_cache_d *cache,
{
const char *name;
enum gcc_plugin_symbol_kind kind;
- enum gcc_plugin_symbol_visibility visibility;
+ enum gcc_plugin_symbol_visibility visibility = GCCPV_DEFAULT;
unsigned slot_num;
uint64_t size;
const char *comdat;
diff --git gcc/gcc/predict.c gcc/gcc/predict.c
index eb5db2a..4e38d0e 100644
--- gcc/gcc/predict.c
+++ gcc/gcc/predict.c
@@ -1902,6 +1902,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
if (predictor)
*predictor = PRED_COMPARE_AND_SWAP;
return boolean_true_node;
+ default:
+ break;
}
}
diff --git gcc/gcc/testsuite/c-c++-common/pr53874.c gcc/gcc/testsuite/c-c++-common/pr53874.c
index e69de29..153f997 100644
--- gcc/gcc/testsuite/c-c++-common/pr53874.c
+++ gcc/gcc/testsuite/c-c++-common/pr53874.c
@@ -0,0 +1,35 @@
+/* PR c/53874 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch-enum" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
diff --git gcc/gcc/testsuite/c-c++-common/pr61405.c gcc/gcc/testsuite/c-c++-common/pr61405.c
index e69de29..9c05a84 100644
--- gcc/gcc/testsuite/c-c++-common/pr61405.c
+++ gcc/gcc/testsuite/c-c++-common/pr61405.c
@@ -0,0 +1,31 @@
+/* PR c/61405 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index 62d271b..bd6e0f4 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -153,6 +153,22 @@ enum cpp_ttype
TTYPE_TABLE
N_TTYPES,
+ /* A token type for keywords, as opposed to ordinary identifiers. */
+ CPP_KEYWORD = N_TTYPES + 1,
+
+ /* A token type for template-ids. If a template-id is processed while
+ parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
+ the value of the CPP_TEMPLATE_ID is whatever was returned by
+ cp_parser_template_id. */
+ CPP_TEMPLATE_ID = CPP_KEYWORD + 1,
+
+ /* A token type for nested-name-specifiers. If a
+ nested-name-specifier is processed while parsing tentatively, it is
+ replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the
+ CPP_NESTED_NAME_SPECIFIER is whatever was returned by
+ cp_parser_nested_name_specifier_opt. */
+ CPP_NESTED_NAME_SPECIFIER = CPP_TEMPLATE_ID + 1,
+
/* Positions in the table. */
CPP_LAST_EQ = CPP_LSHIFT,
CPP_FIRST_DIGRAPH = CPP_HASH,
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
2014-09-19 13:29 [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874) Marek Polacek
2014-09-19 13:33 ` Jakub Jelinek
2014-09-19 15:19 ` Jason Merrill
@ 2014-09-19 19:39 ` Jason Merrill
2014-09-23 17:42 ` Marek Polacek
2 siblings, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2014-09-19 19:39 UTC (permalink / raw)
To: Marek Polacek, GCC Patches, Joseph S. Myers, Jakub Jelinek, Jan Hubicka
On 09/19/2014 09:29 AM, Marek Polacek wrote:
> But we also started to warn on
> CPP_KEYWORD and two others: "case value not in enumerated type".
> Fixed by moving CPP_KEYWORD, CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER
> into enum cpp_ttype. Not sure if this is going to hurt something else.
Wait, -Wswitch warns if any of the case labels don't correspond to
enumerators? Apparently so, it complains about
enum E { a=1,b=2,c=4 } e;
int main()
{
switch (e)
{
case a|b: break;
default: break;
}
}
That seems bogus. The docs say,
"'case' labels outside the enumeration range also provoke warnings when
this option is used (even if there is a 'default' label)."
but 3 is within the range 1-4.
If this is working as intended, I'm still uneasy about moving the C++
internal token types into libcpp; instead, I think I'd prefer to work
around the warning by suppressing -Wswitch inside affected functions or
moving the cases to ifs.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)
2014-09-19 19:39 ` Jason Merrill
@ 2014-09-23 17:42 ` Marek Polacek
2014-09-23 20:51 ` Jason Merrill
0 siblings, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2014-09-23 17:42 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches, Joseph S. Myers, Jakub Jelinek, Jan Hubicka
On Fri, Sep 19, 2014 at 03:39:39PM -0400, Jason Merrill wrote:
> On 09/19/2014 09:29 AM, Marek Polacek wrote:
> >But we also started to warn on
> >CPP_KEYWORD and two others: "case value not in enumerated type".
> >Fixed by moving CPP_KEYWORD, CPP_TEMPLATE_ID, and CPP_NESTED_NAME_SPECIFIER
> >into enum cpp_ttype. Not sure if this is going to hurt something else.
>
> Wait, -Wswitch warns if any of the case labels don't correspond to
> enumerators? Apparently so, it complains about
Yeah.
> enum E { a=1,b=2,c=4 } e;
>
> int main()
> {
> switch (e)
> {
> case a|b: break;
> default: break;
> }
> }
>
> That seems bogus. The docs say,
>
> "'case' labels outside the enumeration range also provoke warnings when this
> option is used (even if there is a 'default' label)."
>
> but 3 is within the range 1-4.
Note that even if we allowed this (don't warn if case value is within the range
of an enum), this wouldn't help with the CPP_KEYWORD, since CPP_KEYWORD is
outside the range of cpp_ttype enum values.
> If this is working as intended, I'm still uneasy about moving the C++
> internal token types into libcpp; instead, I think I'd prefer to work around
> the warning by suppressing -Wswitch inside affected functions or moving the
> cases to ifs.
I still hope we can move the CPP_KEYWORD - that is not C++ only thing;
the C FE parser uses that as well (and defined it).
I suppressed the warnings just by casting the controlling expression
of the switch to an int (two spots, not that bad).
How does this look now?
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2014-09-23 Marek Polacek <polacek@redhat.com>
PR c/61405
PR c/53874
gcc/
* asan.c (maybe_instrument_call): Add default case.
* ipa-pure-const.c (special_builtin_state): Likewise.
* predict.c (expr_expected_value_1): Likewise.
* lto-streamer-out.c (write_symbol): Initialize variable.
gcc/c-family/
* c-common.h (struct c_common_resword): Don't define CPP_KEYWORD.
gcc/c/
* c-parser.c: Don't define CPP_KEYWORD.
(c_parser_switch_statement): Pass original type to c_finish_case.
* c-tree.h (c_finish_case): Update declaration.
* c-typeck.c (c_finish_case): Add TYPE parameter. Pass it
conditionally to c_do_switch_warnings.
gcc/cp/
* semantics.c (finish_switch_cond): Call unlowered_expr_type.
* tree.c (bot_manip): Add default case.
* parser.c (cp_parser_primary_expression): Cast the controlling
expression of a switch to an int.
(cp_parser_unqualified_id): Likewise.
gcc/testsuite/
* c-c++-common/pr53874.c: New test.
* c-c++-common/pr61405.c: New test.
libcpp/
* include/cpplib.h (enum cpp_ttype): Define CPP_KEYWORD.
diff --git gcc/gcc/asan.c gcc/gcc/asan.c
index 2a90d86..bca95df 100644
--- gcc/gcc/asan.c
+++ gcc/gcc/asan.c
@@ -2024,6 +2024,8 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
case BUILT_IN_TRAP:
/* Don't instrument these. */
return false;
+ default:
+ break;
}
}
tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 993a97b..5ec79a0 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -327,9 +327,6 @@ struct c_common_resword
/* Extra cpp_ttype values for C++. */
-/* A token type for keywords, as opposed to ordinary identifiers. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
/* A token type for template-ids. If a template-id is processed while
parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token;
the value of the CPP_TEMPLATE_ID is whatever was returned by
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 3f4a92b..71f40b7 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -126,11 +126,6 @@ c_parse_init (void)
C++). It would then be possible to share more of the C and C++
lexer code, if desired. */
-/* The following local token type is used. */
-
-/* A keyword. */
-#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
-
/* More information about the type of a CPP_NAME token. */
typedef enum c_id_kind {
/* An ordinary identifier. */
@@ -5232,7 +5227,7 @@ c_parser_switch_statement (c_parser *parser)
save_break = c_break_label;
c_break_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
- c_finish_case (body);
+ c_finish_case (body, ce.original_type);
if (c_break_label)
{
location_t here = c_parser_peek_token (parser)->location;
diff --git gcc/gcc/c/c-tree.h gcc/gcc/c/c-tree.h
index 6004d50..fc145a85 100644
--- gcc/gcc/c/c-tree.h
+++ gcc/gcc/c/c-tree.h
@@ -618,7 +618,7 @@ extern void process_init_element (location_t, struct c_expr, bool,
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, bool);
-extern void c_finish_case (tree);
+extern void c_finish_case (tree, tree);
extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
extern tree build_asm_stmt (tree, tree);
extern int c_types_compatible_p (tree, tree);
diff --git gcc/gcc/c/c-typeck.c gcc/gcc/c/c-typeck.c
index da71ab2..f69c28b 100644
--- gcc/gcc/c/c-typeck.c
+++ gcc/gcc/c/c-typeck.c
@@ -9486,10 +9486,11 @@ do_case (location_t loc, tree low_value, tree high_value)
return label;
}
-/* Finish the switch statement. */
+/* Finish the switch statement. TYPE is the original type of the
+ controlling expression of the switch, or NULL_TREE. */
void
-c_finish_case (tree body)
+c_finish_case (tree body, tree type)
{
struct c_switch *cs = c_switch_stack;
location_t switch_location;
@@ -9499,7 +9500,7 @@ c_finish_case (tree body)
/* Emit warnings as needed. */
switch_location = EXPR_LOCATION (cs->switch_expr);
c_do_switch_warnings (cs->cases, switch_location,
- TREE_TYPE (cs->switch_expr),
+ type ? type : TREE_TYPE (cs->switch_expr),
SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
diff --git gcc/gcc/cp/parser.c gcc/gcc/cp/parser.c
index 9764794..0c2acbe 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -4172,7 +4172,7 @@ cp_parser_primary_expression (cp_parser *parser,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- switch (token->type)
+ switch ((int) token->type)
{
/* literal:
integer-literal
@@ -4858,7 +4858,7 @@ cp_parser_unqualified_id (cp_parser* parser,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- switch (token->type)
+ switch ((int) token->type)
{
case CPP_NAME:
{
diff --git gcc/gcc/cp/semantics.c gcc/gcc/cp/semantics.c
index 6e04e5e..2728f58 100644
--- gcc/gcc/cp/semantics.c
+++ gcc/gcc/cp/semantics.c
@@ -1127,7 +1127,8 @@ finish_switch_cond (tree cond, tree switch_stmt)
error ("switch quantity not an integer");
cond = error_mark_node;
}
- orig_type = TREE_TYPE (cond);
+ /* We want unlowered type here to handle enum bit-fields. */
+ orig_type = unlowered_expr_type (cond);
if (cond != error_mark_node)
{
/* Warn if the condition has boolean value. */
diff --git gcc/gcc/cp/tree.c gcc/gcc/cp/tree.c
index d0e1180..a7bb38b 100644
--- gcc/gcc/cp/tree.c
+++ gcc/gcc/cp/tree.c
@@ -2345,6 +2345,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
case BUILT_IN_FILE:
case BUILT_IN_LINE:
SET_EXPR_LOCATION (*tp, input_location);
+ default:
+ break;
}
}
return t;
diff --git gcc/gcc/ipa-pure-const.c gcc/gcc/ipa-pure-const.c
index 459d08d..b5ded3e 100644
--- gcc/gcc/ipa-pure-const.c
+++ gcc/gcc/ipa-pure-const.c
@@ -451,6 +451,8 @@ special_builtin_state (enum pure_const_state_e *state, bool *looping,
*looping = true;
*state = IPA_CONST;
return true;
+ default:
+ break;
}
return false;
}
diff --git gcc/gcc/lto-streamer-out.c gcc/gcc/lto-streamer-out.c
index b516c7b..cff48ee 100644
--- gcc/gcc/lto-streamer-out.c
+++ gcc/gcc/lto-streamer-out.c
@@ -2422,7 +2422,7 @@ write_symbol (struct streamer_tree_cache_d *cache,
{
const char *name;
enum gcc_plugin_symbol_kind kind;
- enum gcc_plugin_symbol_visibility visibility;
+ enum gcc_plugin_symbol_visibility visibility = GCCPV_DEFAULT;
unsigned slot_num;
uint64_t size;
const char *comdat;
diff --git gcc/gcc/predict.c gcc/gcc/predict.c
index 56e45d9..b5556db 100644
--- gcc/gcc/predict.c
+++ gcc/gcc/predict.c
@@ -1902,6 +1902,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
if (predictor)
*predictor = PRED_COMPARE_AND_SWAP;
return boolean_true_node;
+ default:
+ break;
}
}
diff --git gcc/gcc/testsuite/c-c++-common/pr53874.c gcc/gcc/testsuite/c-c++-common/pr53874.c
index e69de29..153f997 100644
--- gcc/gcc/testsuite/c-c++-common/pr53874.c
+++ gcc/gcc/testsuite/c-c++-common/pr53874.c
@@ -0,0 +1,35 @@
+/* PR c/53874 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch-enum" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ default:
+ return 0;
+ }
+}
diff --git gcc/gcc/testsuite/c-c++-common/pr61405.c gcc/gcc/testsuite/c-c++-common/pr61405.c
index e69de29..9c05a84 100644
--- gcc/gcc/testsuite/c-c++-common/pr61405.c
+++ gcc/gcc/testsuite/c-c++-common/pr61405.c
@@ -0,0 +1,31 @@
+/* PR c/61405 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum E { A, B, C };
+struct S { enum E e:2; };
+typedef struct S TS;
+
+int
+fn0 (struct S *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
+
+int
+fn1 (TS *s)
+{
+ switch (s->e) /* { dg-warning "enumeration value .C. not handled in switch" } */
+ {
+ case A:
+ return 1;
+ case B:
+ return 2;
+ }
+}
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index 62d271b..06d18d4 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -153,6 +153,9 @@ enum cpp_ttype
TTYPE_TABLE
N_TTYPES,
+ /* A token type for keywords, as opposed to ordinary identifiers. */
+ CPP_KEYWORD,
+
/* Positions in the table. */
CPP_LAST_EQ = CPP_LSHIFT,
CPP_FIRST_DIGRAPH = CPP_HASH,
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-09-23 20:51 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-19 13:29 [C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874) Marek Polacek
2014-09-19 13:33 ` Jakub Jelinek
2014-09-19 15:19 ` Jason Merrill
2014-09-19 17:43 ` Marek Polacek
2014-09-19 19:39 ` Jason Merrill
2014-09-23 17:42 ` Marek Polacek
2014-09-23 20:51 ` 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).