PR c/4475, c++/3780:
authorJakub Jelinek <jakub@redhat.com>
Mon, 4 Feb 2002 22:05:15 +0000 (23:05 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 4 Feb 2002 22:05:15 +0000 (23:05 +0100)
* c-common.def (SWITCH_STMT): Add SWITCH_TYPE operand.
* c-common.h (SWITCH_TYPE): Define.
* c-typeck.c (c_start_case): Set SWITCH_TYPE.
* stmt.c (all_cases_count): Set lastval to thisval at end of loop.
Rename spareness variable to sparseness.
(expand_end_case_type): Renamed from expand_end_case, use orig_type
if non-NULL instead of TREE_TYPE (orig_index).
* tree.h (expand_end_case_type): Renamed from expand_end_case.
(expand_end_case): Define using expand_end_case_type.
* c-semantics.c (genrtl_switch_stmt): Pass SWITCH_TYPE
to expand_end_case_type.
* doc/c-tree.texi (SWITCH_STMT): Document SWITCH_TYPE.

* semantics.c (begin_switch_stmt): Clear SWITCH_TYPE.
(finish_switch_cond): Set SWITCH_TYPE.

* gcc.dg/Wswitch.c: Fix typos.  Don't return unconditionally
before all tests.  Move warning one line above to match where it
C frontend emits.
* gcc.dg/Wswitch-2.c: New test.
* g++.dg/warn/Wswitch-1.C: New test.
* g++.dg/warn/Wswitch-2.C: New test.

From-SVN: r49497

15 files changed:
gcc/ChangeLog
gcc/c-common.def
gcc/c-common.h
gcc/c-semantics.c
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/doc/c-tree.texi
gcc/stmt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wswitch-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wswitch-2.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wswitch-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wswitch.c
gcc/tree.h

index a3aa6bef5533c47e891f612ae703b0807359eac1..afd68d6fb02d2895a10a6ee95c6d11633d21375d 100644 (file)
@@ -1,3 +1,19 @@
+2002-02-04  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/4475, c++/3780:
+       * c-common.def (SWITCH_STMT): Add SWITCH_TYPE operand.
+       * c-common.h (SWITCH_TYPE): Define.
+       * c-typeck.c (c_start_case): Set SWITCH_TYPE.
+       * stmt.c (all_cases_count): Set lastval to thisval at end of loop.
+       Rename spareness variable to sparseness.
+       (expand_end_case_type): Renamed from expand_end_case, use orig_type
+       if non-NULL instead of TREE_TYPE (orig_index).
+       * tree.h (expand_end_case_type): Renamed from expand_end_case.
+       (expand_end_case): Define using expand_end_case_type.
+       * c-semantics.c (genrtl_switch_stmt): Pass SWITCH_TYPE
+       to expand_end_case_type.
+       * doc/c-tree.texi (SWITCH_STMT): Document SWITCH_TYPE.
+
 2002-02-04  John David Anglin  <dave@hiauly1.hia.nrc.ca>
 
        * pa.h (PREFERRED_STACK_BOUNDARY): Define to match standard rounding.
index d59a151680ea7add3890a0598ab645eff667c9dc..293f4b21bd32b606caebc312cd70e969fd77fa67 100644 (file)
@@ -71,8 +71,8 @@ DEFTREECODE (BREAK_STMT, "break_stmt", 'e', 0)
 DEFTREECODE (CONTINUE_STMT, "continue_stmt", 'e', 0)
 
 /* Used to represent a 'switch' statement. The operands are
-   SWITCH_COND and SWITCH_BODY, respectively. */
-DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 2)
+   SWITCH_COND, SWITCH_BODY and SWITCH_TYPE, respectively. */
+DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 3)
 
 /* Used to represent a 'goto' statement. The operand is GOTO_DESTINATION. */
 DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1)
index 3aaa513ed66d2fee2939c6795cde8c26ae1565b0..c90cbfb076b19a6e454834c665969cfe3b770358 100644 (file)
@@ -603,10 +603,12 @@ extern tree strip_array_types                   PARAMS ((tree));
 #define FOR_EXPR(NODE)          TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
 #define FOR_BODY(NODE)          TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
 
-/* SWITCH_STMT accessors. These give access to the condition and body
+/* SWITCH_STMT accessors. These give access to the condition, body and
+   original condition type (before any compiler conversions)
    of the switch statement, respectively.  */
 #define SWITCH_COND(NODE)       TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
 #define SWITCH_BODY(NODE)       TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
+#define SWITCH_TYPE(NODE)      TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
 
 /* CASE_LABEL accessors. These give access to the high and low values
    of a case label, respectively.  */
index c0bbc515da8faef3ff44f9259f9b61d7869800ab..8f99bc1f64c679f26aee024e647fe56a2372a298 100644 (file)
@@ -644,7 +644,7 @@ genrtl_switch_stmt (t)
   emit_line_note (input_filename, lineno);
   expand_start_case (1, cond, TREE_TYPE (cond), "switch statement");
   expand_stmt (SWITCH_BODY (t));
-  expand_end_case (cond);
+  expand_end_case_type (cond, SWITCH_TYPE (t));
 }
 
 /* Create a CASE_LABEL tree node and return it.  */
index a00c7241f7e0fc0f6873f408781f6c4a288782a4..8c34a17c5d3ab1b278bb288f489474c1fc7b45f4 100644 (file)
@@ -7176,15 +7176,15 @@ c_start_case (exp)
      tree exp;
 {
   enum tree_code code;
-  tree type;
+  tree type, orig_type = error_mark_node;
   struct c_switch *cs;
 
   if (exp != error_mark_node)
     {
       code = TREE_CODE (TREE_TYPE (exp));
-      type = TREE_TYPE (exp);
+      orig_type = TREE_TYPE (exp);
 
-      if (! INTEGRAL_TYPE_P (type)
+      if (! INTEGRAL_TYPE_P (orig_type)
          && code != ERROR_MARK)
        {
          error ("switch quantity not an integer");
@@ -7206,7 +7206,7 @@ c_start_case (exp)
 
   /* Add this new SWITCH_STMT to the stack.  */
   cs = (struct c_switch *) xmalloc (sizeof (*cs));
-  cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, NULL_TREE);
+  cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
   cs->cases = splay_tree_new (case_compare, NULL, NULL);
   cs->next = switch_stack;
   switch_stack = cs;
index dfb3d4bdda296864004f4e390c0ebc88ea64e5ce..f0cb0704b432d2520ee583ca12be36e1de934502 100644 (file)
@@ -1,3 +1,8 @@
+2002-02-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * semantics.c (begin_switch_stmt): Clear SWITCH_TYPE.
+       (finish_switch_cond): Set SWITCH_TYPE.
+
 2002-02-04  Richard Henderson  <rth@redhat.com>
 
        * method.c (use_thunk): Always initialize the block tree.  Reindent.
index cdc1178f338c40dd70d7feab2c8a6c306942b317..c344a3016efacea864050672ba0c249073c55cc1 100644 (file)
@@ -500,7 +500,7 @@ tree
 begin_switch_stmt ()
 {
   tree r;
-  r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
+  r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
   add_stmt (r);
   do_pushlevel ();
   return r;
@@ -513,6 +513,7 @@ finish_switch_cond (cond, switch_stmt)
      tree cond;
      tree switch_stmt;
 {
+  tree orig_type = NULL;
   if (!processing_template_decl)
     {
       tree type;
@@ -525,6 +526,7 @@ finish_switch_cond (cond, switch_stmt)
          error ("switch quantity not an integer");
          cond = error_mark_node;
        }
+      orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
        {
          cond = default_conversion (cond);
@@ -542,6 +544,7 @@ finish_switch_cond (cond, switch_stmt)
        cond = index;
     }
   FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
+  SWITCH_TYPE (switch_stmt) = orig_type;
   push_switch (switch_stmt);
 }
 
index cbf01967dfa15716655ceb9ff6e7a984ada55789..65b39db0bb8880a41b7afd7f5d7bac6db1a2efdd 100644 (file)
@@ -1631,7 +1631,8 @@ Used to represent a @code{switch} statement.  The @code{SWITCH_COND} is
 the expression on which the switch is occurring.  See the documentation
 for an @code{IF_STMT} for more information on the representation used
 for the condition.  The @code{SWITCH_BODY} is the body of the switch
-statement.
+statement.   The @code{SWITCH_TYPE} is the original type of switch
+expression as given in the source, before any compiler conversions.
 
 @item TRY_BLOCK
 Used to represent a @code{try} block.  The body of the try block is
index 5d0e4c44388eeb29450530040d2f47718eab0807..99f910a9d2194a956b4e1a470d6624b7109c4edd 100644 (file)
@@ -4876,20 +4876,20 @@ add_case_node (low, high, label, duplicate)
 /* Returns the number of possible values of TYPE.
    Returns -1 if the number is unknown, variable, or if the number does not
    fit in a HOST_WIDE_INT.
-   Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+   Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
    do not increase monotonically (there may be duplicates);
    to 1 if the values increase monotonically, but not always by 1;
    otherwise sets it to 0.  */
 
 HOST_WIDE_INT
-all_cases_count (type, spareness)
+all_cases_count (type, sparseness)
      tree type;
-     int *spareness;
+     int *sparseness;
 {
   tree t;
   HOST_WIDE_INT count, minval, lastval;
 
-  *spareness = 0;
+  *sparseness = 0;
 
   switch (TREE_CODE (type))
     {
@@ -4928,11 +4928,12 @@ all_cases_count (type, spareness)
        {
          HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0);
 
-         if (*spareness == 2 || thisval < lastval)
-           *spareness = 2;
+         if (*sparseness == 2 || thisval <= lastval)
+           *sparseness = 2;
          else if (thisval != minval + count)
-           *spareness = 1;
+           *sparseness = 1;
 
+         lastval = thisval;
          count++;
        }
     }
@@ -5213,11 +5214,13 @@ free_case_nodes (cn)
 
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
+   If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
+   type as given in the source before any compiler conversions.
    Generate the code to test it and jump to the right place.  */
 
 void
-expand_end_case (orig_index)
-     tree orig_index;
+expand_end_case_type (orig_index, orig_type)
+     tree orig_index, orig_type;
 {
   tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = 0;
@@ -5241,6 +5244,8 @@ expand_end_case (orig_index)
   index_expr = thiscase->data.case_stmt.index_expr;
   index_type = TREE_TYPE (index_expr);
   unsignedp = TREE_UNSIGNED (index_type);
+  if (orig_type == NULL)
+    orig_type = TREE_TYPE (orig_index);
 
   do_pending_stack_adjust ();
 
@@ -5261,9 +5266,9 @@ expand_end_case (orig_index)
         No sense trying this if there's a default case, however.  */
 
       if (!thiscase->data.case_stmt.default_label
-         && TREE_CODE (TREE_TYPE (orig_index)) == ENUMERAL_TYPE
+         && TREE_CODE (orig_type) == ENUMERAL_TYPE
          && TREE_CODE (index_expr) != INTEGER_CST)
-       check_for_full_enumeration_handling (TREE_TYPE (orig_index));
+       check_for_full_enumeration_handling (orig_type);
 
       /* If we don't have a default-label, create one here,
         after the body of the switch.  */
@@ -5420,7 +5425,7 @@ expand_end_case (orig_index)
                 default code is emitted.  */
 
              use_cost_table
-               = (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE
+               = (TREE_CODE (orig_type) != ENUMERAL_TYPE
                   && estimate_case_costs (thiscase->data.case_stmt.case_list));
              balance_case_nodes (&thiscase->data.case_stmt.case_list, NULL);
              emit_case_nodes (index, thiscase->data.case_stmt.case_list,
index c27aab8152896113e511b6b96ef2a729317b893f..6393589a19aa41a99d78ef70ce22ea420ba1d60b 100644 (file)
@@ -1,3 +1,12 @@
+2002-02-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.dg/Wswitch.c: Fix typos.  Don't return unconditionally
+       before all tests.  Move warning one line above to match where it
+       C frontend emits.
+       * gcc.dg/Wswitch-2.c: New test.
+       * g++.dg/warn/Wswitch-1.C: New test.
+       * g++.dg/warn/Wswitch-2.C: New test.
+
 2002-02-04  Richard Henderson  <rth@redhat.com>
 
        * g++.dg/abi/offsetof.C: Fix size comparison.
diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-1.C b/gcc/testsuite/g++.dg/warn/Wswitch-1.C
new file mode 100644 (file)
index 0000000..e9fcb58
--- /dev/null
@@ -0,0 +1,63 @@
+/* PR c/4475, PR c++/3780 */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum e { e1, e2 };
+
+int
+foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el,
+     enum e em, enum e en, enum e eo, enum e ep)
+{
+  switch (i)
+    {
+    case 1: return 1;
+    case 2: return 2;
+    }
+  switch (j)
+    {
+    case 3: return 4;
+    case 4: return 3;
+    default: break;
+    }
+  switch (ei)
+    { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 24 } */
+    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */
+  switch (ej)
+    {
+    default: break;
+    }
+  switch (ek)
+    {
+    case e1: return 1;
+    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */
+  switch (el)
+    {
+    case e1: return 1;
+    default: break;
+    }
+  switch (em)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    }
+  switch (en)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    default: break;
+    }
+  switch (eo)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    case 3: return 3;
+    } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */
+  switch (ep)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    case 3: return 3;
+    default: break;
+    } /* Since there is a default, no warning about ``case 3'' */
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-2.C b/gcc/testsuite/g++.dg/warn/Wswitch-2.C
new file mode 100644 (file)
index 0000000..b151e23
--- /dev/null
@@ -0,0 +1,31 @@
+/* Further -Wswitch tests.  */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum e { e1 = 0, e2 = 1, e3 = 1, e4 = 2 };
+
+int
+foo (enum e ei, int j)
+{
+  switch (ei)
+    {
+    case e1: return 1;
+    case e3: return 2;
+    case e4: return 3;
+    }  /* No warning here since e2 has the same value as e3.  */
+  switch (ei)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    }  /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */
+  switch ((int) ei)
+    {
+    case e1: return 1;
+    }  /* No warning here since switch condition was cast to int.  */
+  switch ((enum e) j)
+    {
+    case e2: return 1;
+    case e4: return 2;
+    }  /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wswitch-2.c b/gcc/testsuite/gcc.dg/Wswitch-2.c
new file mode 100644 (file)
index 0000000..b151e23
--- /dev/null
@@ -0,0 +1,31 @@
+/* Further -Wswitch tests.  */
+/* { dg-do compile } */
+/* { dg-options "-Wswitch" } */
+
+enum e { e1 = 0, e2 = 1, e3 = 1, e4 = 2 };
+
+int
+foo (enum e ei, int j)
+{
+  switch (ei)
+    {
+    case e1: return 1;
+    case e3: return 2;
+    case e4: return 3;
+    }  /* No warning here since e2 has the same value as e3.  */
+  switch (ei)
+    {
+    case e1: return 1;
+    case e2: return 2;
+    }  /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */
+  switch ((int) ei)
+    {
+    case e1: return 1;
+    }  /* No warning here since switch condition was cast to int.  */
+  switch ((enum e) j)
+    {
+    case e2: return 1;
+    case e4: return 2;
+    }  /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */
+  return 0;
+}
index 372b9158c16faf018a452801ed3feb53060f5513..014919b87bd7540edfe54ae82142063719aebc68 100644 (file)
@@ -1,4 +1,4 @@
-/* PR gcc/4475, PR gcc/3780 */
+/* PR c/4475, PR c++/3780 */
 /* { dg-do compile } */
 /* { dg-options "-Wswitch" } */
 
@@ -17,11 +17,11 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el,
     {
     case 3: return 4;
     case 4: return 3;
-    default: return 7;
+    default: break;
     }
   switch (ei)
-    { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 24 } */
-    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */
+    { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */
+    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" { target *-*-* } 23 } */
   switch (ej)
     {
     default: break;
@@ -29,7 +29,7 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el,
   switch (ek)
     {
     case e1: return 1;
-    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e1" } */
+    } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */
   switch (el)
     {
     case e1: return 1;
@@ -58,6 +58,6 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el,
     case e2: return 2;
     case 3: return 3;
     default: break;
-    } /* Since there is a default, no warning about ``case 3'' */
+    } /* Since there is a default, no warning about ``case 3'' */
   return 0;
 }
index e7b634d81f23157c991bf445feb1ad79798518bb..842c0a9924f82d88a511a938fc6d90ebb44da923 100644 (file)
@@ -2772,7 +2772,8 @@ extern struct nesting * current_nesting_level     PARAMS ((void));
 extern tree last_cleanup_this_contour          PARAMS ((void));
 extern void expand_start_case                  PARAMS ((int, tree, tree,
                                                       const char *));
-extern void expand_end_case                    PARAMS ((tree));
+extern void expand_end_case_type               PARAMS ((tree, tree));
+#define expand_end_case(cond) expand_end_case_type (cond, NULL)
 extern int add_case_node                        PARAMS ((tree, tree,
                                                         tree, tree *));
 extern int pushcase                            PARAMS ((tree,