summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/c-common.def4
-rw-r--r--gcc/c-common.h4
-rw-r--r--gcc/c-semantics.c2
-rw-r--r--gcc/c-typeck.c8
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/semantics.c5
-rw-r--r--gcc/doc/c-tree.texi3
-rw-r--r--gcc/stmt.c29
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/warn/Wswitch-1.C63
-rw-r--r--gcc/testsuite/g++.dg/warn/Wswitch-2.C31
-rw-r--r--gcc/testsuite/gcc.dg/Wswitch-2.c31
-rw-r--r--gcc/testsuite/gcc.dg/Wswitch.c12
-rw-r--r--gcc/tree.h3
15 files changed, 196 insertions, 29 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a3aa6bef553..afd68d6fb02 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/c-common.def b/gcc/c-common.def
index d59a151680e..293f4b21bd3 100644
--- a/gcc/c-common.def
+++ b/gcc/c-common.def
@@ -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)
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 3aaa513ed66..c90cbfb076b 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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. */
diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c
index c0bbc515da8..8f99bc1f64c 100644
--- a/gcc/c-semantics.c
+++ b/gcc/c-semantics.c
@@ -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. */
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index a00c7241f7e..8c34a17c5d3 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index dfb3d4bdda2..f0cb0704b43 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index cdc1178f338..c344a3016ef 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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);
}
diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi
index cbf01967dfa..65b39db0bb8 100644
--- a/gcc/doc/c-tree.texi
+++ b/gcc/doc/c-tree.texi
@@ -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
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 5d0e4c44388..99f910a9d21 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c27aab81528..6393589a19a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..e9fcb581817
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wswitch-1.C
@@ -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
index 00000000000..b151e2310c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wswitch-2.C
@@ -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
index 00000000000..b151e2310c7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wswitch-2.c
@@ -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.c b/gcc/testsuite/gcc.dg/Wswitch.c
index 372b9158c16..014919b87bd 100644
--- a/gcc/testsuite/gcc.dg/Wswitch.c
+++ b/gcc/testsuite/gcc.dg/Wswitch.c
@@ -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;
}
diff --git a/gcc/tree.h b/gcc/tree.h
index e7b634d81f2..842c0a9924f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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,
OpenPOWER on IntegriCloud