This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C/C++ PATCH] Handle enum bit-fields for -Wswitch (PR c/61405, PR c/53874)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]