summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/stmt.c10
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/opt/switch4.C30
4 files changed, 49 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ca5a33b871c..61ea0ad332c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-02-18 Alexandre Oliva <aoliva@redhat.com>
+
+ PR c++/20008
+ * stmt.c (expand_case): Don't assume cleanup_tree_cfg will remove
+ cases that are out-of-range for the index type.
+
2005-02-18 James A. Morrison <phython@gcc.gnu.org>
* stmt.c (emit_case_bit_tests): Call fold_convert instead of convert.
diff --git a/gcc/stmt.c b/gcc/stmt.c
index a438532b11b..64e070b5a0a 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -2394,8 +2394,14 @@ expand_case (tree exp)
BITMAP_FREE (label_bitmap);
/* cleanup_tree_cfg removes all SWITCH_EXPR with a single
- destination, such as one with a default case only. */
- gcc_assert (count != 0);
+ destination, such as one with a default case only. However,
+ it doesn't remove cases that are out of range for the switch
+ type, so we may still get a zero here. */
+ if (count == 0)
+ {
+ emit_jump (default_label);
+ return;
+ }
/* Compute span of values. */
range = fold (build2 (MINUS_EXPR, index_type, maxval, minval));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 668d6e471c3..7d653eca38b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-02-18 Alexandre Oliva <aoliva@redhat.com>
+
+ PR c++/20008
+ * g++.dg/opt/switch4.C: New.
+
2005-02-18 Jakub Jelinek <jakub@redhat.com>
PR c++/20023
diff --git a/gcc/testsuite/g++.dg/opt/switch4.C b/gcc/testsuite/g++.dg/opt/switch4.C
new file mode 100644
index 00000000000..231929fdf3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/switch4.C
@@ -0,0 +1,30 @@
+// { dg-do compile }
+
+// PR c++/20008
+
+// We failed to compile this because CFG cleanup left the switch
+// statement intact, whereas expand_case expected at least one
+// in-range case to remain.
+
+typedef enum _SECStatus {
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus;
+
+typedef enum {
+ SEC_ERROR_BAD_SIGNATURE = (-0x2000) + 10
+} SECErrorCodes;
+
+void g(void);
+void f(SECStatus status)
+{
+ switch( status )
+ {
+ case SEC_ERROR_BAD_SIGNATURE :
+ // This case can be optimized away in C++ (but apparently not in
+ // C), because the enum type is defined with a narrow range.
+ g();
+ break ;
+ }
+}