]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c-common.h (add_stmt): Change prototype.
authorMark Mitchell <mark@codesourcery.com>
Sun, 10 Sep 2000 21:34:41 +0000 (21:34 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sun, 10 Sep 2000 21:34:41 +0000 (21:34 +0000)
* c-common.h (add_stmt): Change prototype.
(RECHAIN_STMTS): New macro.
(CASE_LABEL_DECL): Likewise.
(genrtl_case_label): Change prototype.
(c_expand_start_case): Remove prototype.
(build_case_label): Change prototype.
(decl_constant_value): Declare.
* c-common.c (check_case_value): Handle C++'s extensions to C
semantics.
* c-commnon.def (CASE_LABEL): Add room for the CASE_LABEL_DECL
field.
* c-parse.in (stmt): Adjust handling of return statements and case
laels.
* c-semantics.c (add_stmt): Return the new statement.
(genrtl_return_stmt): Take the RETURN_STMT as input, not the
returned expression.  Directly generate RTL, rather than calling
c_expand_return.
(genrtl_switch_stmt): Don't call c_expand_start_case.
(build_case_label): Take the LABEL_DECL as input, too.
(genrtl_case_label): Just call add_case_node.
(expand_stmt): Adjust calls to genrtl_return_stmt and
genrtl_case_label.
* c-tree.h (c_expand_start_case): Declare.
* c-typeck.c (decl_constant_value): Give it external linkage.
(c_expand_return): Don't call expand_return or expand_null_return;
use genrtl_return_stmt instead.
* stmt.c (struct nesting): Remove num_ranges field.
(add_case_node): Give it external linkage.
(expand_start_case): Don't set num_ranges.
(expand_start_case_dummy): Don't clear it.
(pushcase): Rely on add_case_node to handle `default' labels.
(add_case_node): Handle `default' labels.
* tree.c (tree_int_cst_compare): New function.
* tree.h (tree_int_cst_compare): Declare.
(add_case_node): Likewise.

* cp-tree.h (push_switch): Change prototype.
(check_cp_case_value): Remove declaration.
(decl_constant_value): Likewise.
* decl.c (struct cp_switch): Add switch_stmt and cases.
(case_compare): New function.
(push_switch): Set switch_stmt.  Initialize cases.
(pop_switch): Clean up cases.
(define_case_label): Rename to ...
(finish_case_label): ... this.  Do semantic analysis for case
labels here.
(start_function): Correct comment.
* decl2.c (check_cp_case_value): Remove.
* expr.c (do_case): Remove.
* pt.c (tsubst_expr): Adjust call to finish_case_label.
* semantics.c (genrtl_do_poplevel): Remove declaration.
(RECHAIN_STMTS): Remove.
(finish_break_stmt): Use build_break_stmt.
(finish_continue_stmt): Use build_continue_stmt.
(finish_switch_cond): Adjust condition here, rater than in
c_expand_start_case.
(finish_case_label): Remove.
* typeck.c (c_expand_return): Remove.
(c_expand_start_case): Likewise.

From-SVN: r36305

19 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-common.def
gcc/c-common.h
gcc/c-parse.in
gcc/c-semantics.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/expr.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/stmt.c
gcc/tree.c
gcc/tree.h

index 65a02e32b1bcf6a96ce2b2f23b491f0977773b44..e03db7dfa854ec45799b195057c2c0d3da067436 100644 (file)
@@ -1,3 +1,41 @@
+2000-09-10  Mark Mitchell  <mark@codesourcery.com>
+
+       * c-common.h (add_stmt): Change prototype.
+       (RECHAIN_STMTS): New macro.
+       (CASE_LABEL_DECL): Likewise.
+       (genrtl_case_label): Change prototype.
+       (c_expand_start_case): Remove prototype.
+       (build_case_label): Change prototype.
+       (decl_constant_value): Declare.
+       * c-common.c (check_case_value): Handle C++'s extensions to C
+       semantics.
+       * c-commnon.def (CASE_LABEL): Add room for the CASE_LABEL_DECL
+       field. 
+       * c-parse.in (stmt): Adjust handling of return statements and case
+       laels.
+       * c-semantics.c (add_stmt): Return the new statement.
+       (genrtl_return_stmt): Take the RETURN_STMT as input, not the
+       returned expression.  Directly generate RTL, rather than calling
+       c_expand_return.
+       (genrtl_switch_stmt): Don't call c_expand_start_case.
+       (build_case_label): Take the LABEL_DECL as input, too.
+       (genrtl_case_label): Just call add_case_node.
+       (expand_stmt): Adjust calls to genrtl_return_stmt and
+       genrtl_case_label.
+       * c-tree.h (c_expand_start_case): Declare.
+       * c-typeck.c (decl_constant_value): Give it external linkage.
+       (c_expand_return): Don't call expand_return or expand_null_return;
+       use genrtl_return_stmt instead.
+       * stmt.c (struct nesting): Remove num_ranges field.
+       (add_case_node): Give it external linkage.
+       (expand_start_case): Don't set num_ranges.
+       (expand_start_case_dummy): Don't clear it.
+       (pushcase): Rely on add_case_node to handle `default' labels.
+       (add_case_node): Handle `default' labels.
+       * tree.c (tree_int_cst_compare): New function.
+       * tree.h (tree_int_cst_compare): Declare.
+       (add_case_node): Likewise.
+
 2000-09-10  Richard Henderson  <rth@cygnus.com>
 
        * c-parse.in: Revert last change.
index c53ee1ae7dd0e447a90c3cdf226920e1f21a8c0e..5e093372121f4e26a6791f2f3c57bcfc95525894 100644 (file)
@@ -2678,6 +2678,18 @@ check_case_value (value)
 
   /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
   STRIP_TYPE_NOPS (value);
+  /* In C++, the following is allowed:
+
+       const int i = 3;
+       switch (...) { case i: ... }
+
+     So, we try to reduce the VALUE to a constant that way.  */
+  if (c_language == clk_cplusplus)
+    {
+      value = decl_constant_value (value);
+      STRIP_TYPE_NOPS (value);
+      value = fold (value);
+    }
 
   if (TREE_CODE (value) != INTEGER_CST
       && value != error_mark_node)
index 3486a4c1d8814fa9bd5ee869138a6914dac97801..b262dd763859183e6ca5f77c656fe96359b70f05 100644 (file)
@@ -95,8 +95,8 @@ DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 1)
 /* Used to represent a CASE_LABEL. The operands are CASE_LOW and
    CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a
    'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case
-   label. */
-DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
+   label.  The CASE_LABEL_DECL is a LABEL_DECL for this node.  */
+DEFTREECODE (CASE_LABEL, "case_label", 'e', 3)
 
 /* A STMT_EXPR represents a statement-expression.  The
    STMT_EXPR_STMT is the statement given by the expression.  */
index e995b9978e0b9ac8ea976d534533403db2c116d9..4fb65608b7ea15adc64b508613b77c8821d48991 100644 (file)
@@ -256,7 +256,7 @@ typedef tree (*walk_tree_fn)                    PARAMS ((tree *,
 
 extern stmt_tree current_stmt_tree              PARAMS ((void));
 extern void begin_stmt_tree                     PARAMS ((tree *));
-extern void add_stmt                           PARAMS ((tree));
+extern tree add_stmt                           PARAMS ((tree));
 extern void finish_stmt_tree                    PARAMS ((tree *));
 
 extern int statement_code_p                     PARAMS ((enum tree_code));
@@ -268,6 +268,18 @@ extern void prep_stmt                           PARAMS ((tree));
 extern void (*lang_expand_stmt)                 PARAMS ((tree));
 extern void expand_stmt                         PARAMS ((tree));
 
+/* LAST_TREE contains the last statement parsed.  These are chained
+   together through the TREE_CHAIN field, but often need to be
+   re-organized since the parse is performed bottom-up.  This macro
+   makes LAST_TREE the indicated SUBSTMT of STMT.  */
+
+#define RECHAIN_STMTS(stmt, substmt)           \
+  do {                                         \
+    substmt = TREE_CHAIN (stmt);               \
+    TREE_CHAIN (stmt) = NULL_TREE;             \
+    last_tree = stmt;                          \
+  } while (0)
+
 /* The variant of the C language being processed.  Each C language
    front-end defines this variable.  */
 
@@ -457,6 +469,7 @@ extern tree simple_type_promotes_to         PARAMS ((tree));
    of a case label, respectively. */
 #define CASE_LOW(NODE)          TREE_OPERAND (CASE_LABEL_CHECK (NODE), 0)
 #define CASE_HIGH(NODE)         TREE_OPERAND (CASE_LABEL_CHECK (NODE), 1)
+#define CASE_LABEL_DECL(NODE)   TREE_OPERAND (CASE_LABEL_CHECK (NODE), 2)
 
 /* GOTO_STMT accessor. This gives access to the label associated with
    a goto statement. */
@@ -570,7 +583,7 @@ extern void genrtl_break_stmt                   PARAMS ((void));
 extern void genrtl_continue_stmt                PARAMS ((void));
 extern void genrtl_scope_stmt                   PARAMS ((tree));
 extern void genrtl_switch_stmt                  PARAMS ((tree));
-extern void genrtl_case_label                   PARAMS ((tree, tree));
+extern void genrtl_case_label                   PARAMS ((tree));
 extern void genrtl_compound_stmt                PARAMS ((tree));
 extern void genrtl_asm_stmt                     PARAMS ((tree, tree,
                                                         tree, tree,
@@ -589,10 +602,9 @@ extern void emit_local_var                      PARAMS ((tree));
 extern void make_rtl_for_local_static           PARAMS ((tree));
 extern tree expand_cond                         PARAMS ((tree));
 extern void c_expand_return                    PARAMS ((tree));
-extern tree c_expand_start_case                        PARAMS ((tree));
 extern void do_case                            PARAMS ((tree, tree));
 extern tree build_stmt                          PARAMS ((enum tree_code, ...));
-extern tree build_case_label                    PARAMS ((tree, tree));
+extern tree build_case_label                    PARAMS ((tree, tree, tree));
 extern tree build_continue_stmt                 PARAMS ((void));
 extern tree build_break_stmt                    PARAMS ((void));
 extern tree build_return_stmt                   PARAMS ((tree));
@@ -620,6 +632,8 @@ extern tree common_type                         PARAMS ((tree, tree));
 
 extern tree expand_tree_builtin                 PARAMS ((tree, tree, tree));
 
+extern tree decl_constant_value                PARAMS ((tree));
+
 /* Hook currently used only by the C++ front end to reset internal state
    after entering or leaving a header file.  */
 extern void extract_interface_info             PARAMS ((void));
index 5825da4c7da7519612146011e0959d661fc76cd8..bd9e652de89651e7f4cabb1450ff9e6dfd9b550c 100644 (file)
@@ -1879,13 +1879,11 @@ stmt:
                   stmt_count++;
                  genrtl_continue_stmt (); }
        | RETURN ';'
-                { tree return_stmt = build_return_stmt (NULL_TREE);
-                  stmt_count++;
-                 genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
+                { stmt_count++;
+                 c_expand_return (NULL_TREE); }
        | RETURN expr ';'
-                { tree return_stmt = build_return_stmt ($2);
-                  stmt_count++;
-                 genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
+                { stmt_count++;
+                 c_expand_return ($2); }
        | ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
                { stmt_count++;
                  emit_line_note ($<filename>-1, $<lineno>0);
@@ -1943,20 +1941,14 @@ stmt:
    also at the end of a compound statement.  */
 
 label:   CASE expr_no_commas ':'
-                { tree case_label_tree = build_case_label ($2, NULL_TREE);
-                 stmt_count++;
-                 genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
-               }
+                { stmt_count++;
+                 do_case ($2, NULL_TREE); }
        | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
-                { tree case_label_tree = build_case_label ($2, $4);
-                 stmt_count++;
-                 genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
-               }
+                { stmt_count++;
+                 do_case ($2, $4); }
        | DEFAULT ':'
-                { tree case_label_tree = build_case_label (NULL_TREE, NULL_TREE);
-                 stmt_count++;
-                 genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
-               }
+                { stmt_count++;
+                 do_case (NULL_TREE, NULL_TREE); }
        | identifier save_filename save_lineno ':' maybe_attribute
                { tree label = define_label ($2, $3, $1);
                  stmt_count++;
index 8a4cf91c6c461e67363d9e06edf7dd094848ed40..991311ef1171623c33148d1ab9cb573cac46ec83 100644 (file)
@@ -58,7 +58,7 @@ begin_stmt_tree (t)
 
 /* T is a statement.  Add it to the statement-tree.  */
 
-void
+tree
 add_stmt (t)
      tree t;
 {
@@ -68,6 +68,7 @@ add_stmt (t)
   /* When we expand a statement-tree, we must know whether or not the
      statements are full-expresions.  We record that fact here.  */
   STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
+  return t;
 }
 
 /* Remove declarations of internal variables that are not used from a
@@ -434,14 +435,23 @@ build_return_stmt (expr)
   return (build_stmt (RETURN_STMT, expr));
 }
 
-/* Generate the RTL for EXPR, which is a RETURN_STMT. */
+/* Generate the RTL for STMT, which is a RETURN_STMT. */
 
 void
-genrtl_return_stmt (expr)
-     tree expr;
+genrtl_return_stmt (stmt)
+     tree stmt;
 {
+  tree expr = RETURN_EXPR (stmt);
+
   emit_line_note (input_filename, lineno);
-  c_expand_return (expr);
+  if (!expr)
+    expand_null_return ();
+  else
+    {
+      expand_start_target_temps ();
+      expand_return (expr);
+      expand_end_target_temps ();
+    }
 }
 
 /* Generate the RTL for T, which is a FOR_STMT. */
@@ -547,40 +557,38 @@ genrtl_switch_stmt (t)
   genrtl_do_pushlevel ();
  
   cond = expand_cond (SWITCH_COND (t));
-  if (cond != error_mark_node)
-    {
-      emit_line_note (input_filename, lineno);
-      c_expand_start_case (cond);
-    }
-  else
+  if (cond == error_mark_node)
     /* The code is in error, but we don't want expand_end_case to
        crash. */
-    c_expand_start_case (boolean_false_node);
+    cond = boolean_false_node;
 
+  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);
 }
 
 /* Create a CASE_LABEL tree node and return it. */
 
 tree
-build_case_label (low_value, high_value)
+build_case_label (low_value, high_value, label_decl)
      tree low_value;
      tree high_value;
+     tree label_decl;
 {
-  return build_stmt (CASE_LABEL, low_value, high_value);
+  return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
 }
 
 
 /* Generate the RTL for a CASE_LABEL. */
 
 void 
-genrtl_case_label (low_value, high_value)
-     tree low_value;
-     tree high_value;
+genrtl_case_label (case_label)
+     tree case_label;
 {
-  do_case (low_value, high_value);
+  tree duplicate;
+  add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label), 
+                CASE_LABEL_DECL (case_label), &duplicate);
 }
 
 /* Generate the RTL for T, which is a COMPOUND_STMT. */
@@ -677,7 +685,7 @@ expand_stmt (t)
       switch (TREE_CODE (t))
        {
        case RETURN_STMT:
-         genrtl_return_stmt (RETURN_EXPR (t));
+         genrtl_return_stmt (t);
          break;
 
        case EXPR_STMT:
@@ -721,7 +729,7 @@ expand_stmt (t)
          break;
 
        case CASE_LABEL:
-         genrtl_case_label (CASE_LOW (t), CASE_HIGH (t));
+         genrtl_case_label (t);
          break;
 
        case LABEL_STMT:
index 290ebe9daa87a1efcaca1da307494510253b4833..92f0b4533290e9d46fe1bac278ba05a547349eb3 100644 (file)
@@ -268,6 +268,7 @@ extern void set_init_label                  PARAMS ((tree));
 extern void process_init_element               PARAMS ((tree));
 extern void pedwarn_c99                                PARAMS ((const char *, ...))
                                                        ATTRIBUTE_PRINTF_1;
+extern tree c_expand_start_case                 PARAMS ((tree));
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
index cd787d97295f495574d45aa4434591e52dc619e1..49227ff82c5c1f0194f757b49a8c90bb2222669e 100644 (file)
@@ -54,7 +54,6 @@ static tree qualify_type              PARAMS ((tree, tree));
 static int comp_target_types           PARAMS ((tree, tree));
 static int function_types_compatible_p PARAMS ((tree, tree));
 static int type_lists_compatible_p     PARAMS ((tree, tree));
-static tree decl_constant_value                PARAMS ((tree));
 static tree lookup_field               PARAMS ((tree, tree, tree *));
 static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
 static tree pointer_int_sum            PARAMS ((enum tree_code, tree, tree));
@@ -838,7 +837,7 @@ c_alignof_expr (expr)
 
 /* Return either DECL or its known constant value (if it has one).  */
 
-static tree
+tree
 decl_constant_value (decl)
      tree decl;
 {
@@ -6629,14 +6628,12 @@ c_expand_return (retval)
       if ((warn_return_type || flag_isoc99)
          && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
        pedwarn_c99 ("`return' with no value, in function returning non-void");
-      expand_null_return ();
     }
   else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
       if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
        pedwarn ("`return' with a value, in function returning void");
-      expand_return (retval);
     }
   else
     {
@@ -6701,11 +6698,11 @@ c_expand_return (retval)
          break;
        }
 
-      t = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-      expand_return (t);
+      retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
       current_function_returns_value = 1;
     }
+
+  genrtl_return_stmt (build_return_stmt (retval));
 }
 \f
 /* Start a C switch statement, testing expression EXP.
index 537e57ad04891709b2e0bd987b313ecaac43bf26..1ba64f02baccf31125953c2752dc1dcef07a7370 100644 (file)
@@ -1,3 +1,29 @@
+2000-09-09  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (push_switch): Change prototype.
+       (check_cp_case_value): Remove declaration.
+       (decl_constant_value): Likewise.
+       * decl.c (struct cp_switch): Add switch_stmt and cases.
+       (case_compare): New function.
+       (push_switch): Set switch_stmt.  Initialize cases.
+       (pop_switch): Clean up cases.
+       (define_case_label): Rename to ...
+       (finish_case_label): ... this.  Do semantic analysis for case
+       labels here.
+       (start_function): Correct comment.
+       * decl2.c (check_cp_case_value): Remove.
+       * expr.c (do_case): Remove.
+       * pt.c (tsubst_expr): Adjust call to finish_case_label.
+       * semantics.c (genrtl_do_poplevel): Remove declaration.
+       (RECHAIN_STMTS): Remove.
+       (finish_break_stmt): Use build_break_stmt.
+       (finish_continue_stmt): Use build_continue_stmt.
+       (finish_switch_cond): Adjust condition here, rater than in
+       c_expand_start_case.
+       (finish_case_label): Remove.
+       * typeck.c (c_expand_return): Remove.
+       (c_expand_start_case): Likewise.
+       
 2000-09-07  Gabriel Dos Reis  <gdr@codesourcery.com>
 
        * ir.texi: Document type nodes.
index f29b04b35e6450bc0342e36ac29236d6a28a6ece..8dbb82e29ad1da4659944c09e8ccae540552d791 100644 (file)
@@ -3829,7 +3829,7 @@ extern void pop_nested_namespace          PARAMS ((tree));
 extern void maybe_push_to_top_level            PARAMS ((int));
 extern void push_to_top_level                  PARAMS ((void));
 extern void pop_from_top_level                 PARAMS ((void));
-extern void push_switch                                PARAMS ((void));
+extern void push_switch                                PARAMS ((tree));
 extern void pop_switch                         PARAMS ((void));
 extern tree identifier_type_value              PARAMS ((tree));
 extern void set_identifier_type_value          PARAMS ((tree, tree));
@@ -3990,7 +3990,6 @@ extern tree reparse_absdcl_as_casts               PARAMS ((tree, tree));
 extern tree build_expr_from_tree               PARAMS ((tree));
 extern tree reparse_decl_as_expr               PARAMS ((tree, tree));
 extern tree finish_decl_parsing                        PARAMS ((tree));
-extern tree check_cp_case_value                        PARAMS ((tree));
 extern void set_decl_namespace                  PARAMS ((tree, tree, int));
 extern tree current_decl_namespace              PARAMS ((void));
 extern void push_decl_namespace                 PARAMS ((tree));
@@ -4075,7 +4074,6 @@ extern tree get_type_value                        PARAMS ((tree));
 extern tree build_member_call                  PARAMS ((tree, tree, tree));
 extern tree build_offset_ref                   PARAMS ((tree, tree));
 extern tree resolve_offset_ref                 PARAMS ((tree));
-extern tree decl_constant_value                        PARAMS ((tree));
 extern tree build_new                          PARAMS ((tree, tree, tree, int));
 extern tree build_vec_init                     PARAMS ((tree, tree, tree, tree, int));
 extern tree build_x_delete                     PARAMS ((tree, int, tree));
index 640deb2208ce816bb9900dd3ed01edfce1cc0f2d..9ac30e40832cd282c65534dceda13f58c7751747 100644 (file)
@@ -187,6 +187,7 @@ static tree check_special_function_return_type
   PARAMS ((special_function_kind, tree, tree, tree));
 static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
 static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
+static int case_compare PARAMS ((splay_tree_key, splay_tree_key));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PARAMS ((void));
@@ -5176,17 +5177,52 @@ struct cp_switch
 {
   struct binding_level *level;
   struct cp_switch *next;
+  /* The SWITCH_STMT being built.  */
+  tree switch_stmt;
+  /* A splay-tree mapping the low element of a case range to the high
+     element, or NULL_TREE if there is no high element.  Used to
+     determine whether or not a new case label duplicates an old case
+     label.  We need a tree, rather than simply a hash table, because
+     of the GNU case range extension.  */
+  splay_tree cases;
 };
 
+/* A stack of the currently active switch statements.  The innermost
+   switch statement is on the top of the stack.  There is no need to
+   mark the stack for garbage collection because it is only active
+   during the processing of the body of a function, and we never
+   collect at that point.  */
+   
 static struct cp_switch *switch_stack;
 
+static int
+case_compare (k1, k2)
+     splay_tree_key k1;
+     splay_tree_key k2;
+{
+  /* Consider a NULL key (such as arises with a `default' label) to be
+     smaller than anything else.  */
+  if (!k1)
+    return k2 ? -1 : 0;
+  else if (!k2)
+    return k1 ? 1 : 0;
+
+  return tree_int_cst_compare ((tree) k1, (tree) k2);
+}
+
+/* Called right after a switch-statement condition is parsed.
+   SWITCH_STMT is the switch statement being parsed.  */
+
 void
-push_switch ()
+push_switch (switch_stmt)
+     tree switch_stmt;
 {
   struct cp_switch *p
     = (struct cp_switch *) xmalloc (sizeof (struct cp_switch));
   p->level = current_binding_level;
   p->next = switch_stack;
+  p->switch_stmt = switch_stmt;
+  p->cases = splay_tree_new (case_compare, NULL, NULL);
   switch_stack = p;
 }
 
@@ -5196,6 +5232,7 @@ pop_switch ()
   struct cp_switch *cs;
   
   cs = switch_stack;
+  splay_tree_delete (cs->cases);
   switch_stack = switch_stack->next;
   free (cs);
 }
@@ -5204,14 +5241,150 @@ pop_switch ()
    is a bad place for one.  */
 
 void
-define_case_label ()
+finish_case_label (low_value, high_value)
+     tree low_value;
+     tree high_value;
 {
-  tree cleanup = last_cleanup_this_contour ();
+  tree label;
+  tree cleanup;
+  tree type;
+  tree cond;
+  tree case_label;
+  splay_tree_node node;
 
   if (! switch_stack)
-    /* Don't crash; we'll complain in do_case.  */
+    {
+      if (high_value)
+       error ("case label not within a switch statement");
+      else if (low_value)
+       cp_error ("case label `%E' not within a switch statement", 
+                 low_value);
+      else
+       error ("`default' label not within a switch statement");
+      return;
+    }
+
+  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+  if (processing_template_decl)
+    {
+      /* For templates, just add the case label; we'll do semantic
+        analysis at instantiation-time.  */
+      add_stmt (build_case_label (low_value, high_value, label));
+      return;
+    }
+
+  /* Find the condition on which this switch statement depends.  */
+  cond = SWITCH_COND (switch_stack->switch_stmt);
+  if (cond && TREE_CODE (cond) == TREE_LIST)
+    cond = TREE_VALUE (cond);
+  /* If there was an error processing the switch condition, bail now
+     before we get more confused.  */
+  if (!cond || cond == error_mark_node)
     return;
+  type = TREE_TYPE (cond);
 
+  if ((low_value && TREE_TYPE (low_value) 
+       && POINTER_TYPE_P (TREE_TYPE (low_value))) 
+      || (high_value && TREE_TYPE (high_value)
+         && POINTER_TYPE_P (TREE_TYPE (high_value))))
+    error ("pointers are not permitted as case values");
+
+  /* Case ranges are a GNU extension.  */
+  if (high_value && pedantic)
+    pedwarn ("ISO C++ forbids range expressions in switch statement");
+
+  if (low_value)
+    {
+      low_value = check_case_value (low_value);
+      low_value = convert_and_check (type, low_value);
+    }
+  if (high_value)
+    {
+      high_value = check_case_value (high_value);
+      high_value = convert_and_check (type, high_value);
+    }
+
+  /* If an error has occurred, bail out now.  */
+  if (low_value == error_mark_node || high_value == error_mark_node)
+    return;
+
+  /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
+     really a case range, even though it was written that way.  Remove
+     the HIGH_VALUE to simplify later processing.  */
+  if (tree_int_cst_equal (low_value, high_value))
+    high_value = NULL_TREE;
+  if (low_value && high_value 
+      && !tree_int_cst_lt (low_value, high_value)) 
+    warning ("empty range specified");
+
+  /* Look up the LOW_VALUE in the table of case labels we already
+     have.  */
+  node = splay_tree_lookup (switch_stack->cases, (splay_tree_key) low_value);
+  /* If there was not an exact match, check for overlapping ranges.
+     There's no need to do this if there's no LOW_VALUE or HIGH_VALUE;
+     that's a `default' label and the only overlap is an exact match.  */
+  if (!node && (low_value || high_value))
+    {
+      splay_tree_node low_bound;
+      splay_tree_node high_bound;
+
+      /* Even though there wasn't an exact match, there might be an
+        overlap between this case range and another case range.
+        Since we've (inductively) not allowed any overlapping case
+        ranges, we simply need to find the greatest low case label
+        that is smaller that LOW_VALUE, and the smallest low case
+        label that is greater than LOW_VALUE.  If there is an overlap
+        it will occur in one of these two ranges.  */
+      low_bound = splay_tree_predecessor (switch_stack->cases,
+                                         (splay_tree_key) low_value);
+      high_bound = splay_tree_successor (switch_stack->cases,
+                                        (splay_tree_key) low_value);
+
+      /* Check to see if the LOW_BOUND overlaps.  It is smaller than
+        the LOW_VALUE, so there is no need to check unless the
+        LOW_BOUND is in fact itself a case range.  */
+      if (low_bound
+         && CASE_HIGH ((tree) low_bound->value)
+         && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value),
+                                   low_value) >= 0)
+       node = low_bound;
+      /* Check to see if the HIGH_BOUND overlaps.  The low end of that
+        range is bigger than the low end of the current range, so we
+        are only interested if the current range is a real range, and
+        not an ordinary case label.  */
+      else if (high_bound 
+              && high_value
+              && (tree_int_cst_compare ((tree) high_bound->key,
+                                        high_value)
+                  <= 0))
+       node = high_bound;
+    }
+  /* If there was an overlap, issue an error.  */
+  if (node)
+    {
+      tree duplicate = CASE_LABEL_DECL ((tree) node->value);
+
+      if (high_value)
+       {
+         error ("duplicate (or overlapping) case value");
+         cp_error_at ("this is the first entry overlapping that value",
+                      duplicate);
+       }
+      else if (low_value)
+       {
+         cp_error ("duplicate case value `%E'", low_value) ;
+         cp_error_at ("previously used here", duplicate);
+       }
+      else
+       {
+         error ("multiple default labels in one switch");
+         cp_error_at ("this is the first default label", duplicate);
+       }
+      return;
+    }
+
+  cleanup = last_cleanup_this_contour ();
   if (cleanup)
     {
       static int explained = 0;
@@ -5228,9 +5401,18 @@ define_case_label ()
 
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
-
   current_binding_level->more_cleanups_ok = 0;
   current_function_return_value = NULL_TREE;
+
+  /* Add a representation for the case label to the statement
+     tree.  */
+  case_label = build_case_label (low_value, high_value, label);
+  add_stmt (case_label);
+
+  /* Register this case label in the splay tree.  */
+  splay_tree_insert (switch_stack->cases, 
+                    (splay_tree_key) low_value,
+                    (splay_tree_value) case_label);
 }
 \f
 /* Return the list of declarations of the current level.
@@ -13601,7 +13783,7 @@ start_function (declspecs, declarator, attrs, flags)
   if (flags & SF_INCLASS_INLINE)
     maybe_begin_member_template_processing (decl1);
 
-  /* Effective C++ rule 15.  See also c_expand_return.  */
+  /* Effective C++ rule 15.  */
   if (warn_ecpp
       && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
       && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
index 7bbd998df4561c821b78df4e23f2be50bda9b102..e97d52593ab68bf685bb925c7953a97ed6bc80b1 100644 (file)
@@ -4329,35 +4329,6 @@ finish_decl_parsing (decl)
     }
 }
 
-tree
-check_cp_case_value (value)
-     tree value;
-{
-  if (value == NULL_TREE)
-    return value;
-
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  STRIP_TYPE_NOPS (value);
-  value = decl_constant_value (value);
-  STRIP_TYPE_NOPS (value);
-  value = fold (value);
-
-  if (TREE_CODE (value) != INTEGER_CST
-      && value != error_mark_node)
-    {
-      cp_error ("case label `%E' does not reduce to an integer constant",
-               value);
-      value = error_mark_node;
-    }
-  else
-    /* Promote char or short to int.  */
-    value = default_conversion (value);
-
-  constant_expression_warning (value);
-
-  return value;
-}
-
 /* Return 1 if root encloses child. */
 
 static int
index 42a53903ee315dbd84115874500e271706a559a9..39095ec17db9950f24d4163ee35f211cfc7fcb46 100644 (file)
@@ -205,82 +205,3 @@ extract_init (decl, init)
   return 0;
 }
 
-void
-do_case (start, end)
-     tree start, end;
-{
-  tree value1 = NULL_TREE, value2 = NULL_TREE, label;
-
-  if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE 
-      && POINTER_TYPE_P (TREE_TYPE (start)))
-    error ("pointers are not permitted as case values");
-
-  if (end && pedantic)
-    pedwarn ("ISO C++ forbids range expressions in switch statement");
-
-  if (start)
-    value1 = check_cp_case_value (start);
-  if (end)
-    value2 = check_cp_case_value (end);
-  
-  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
-  if (value1 != error_mark_node
-      && value2 != error_mark_node)
-    {
-      tree duplicate;
-      int success;
-
-      if (end)
-       success = pushcase_range (value1, value2, convert_and_check,
-                                 label, &duplicate);
-      else if (start)
-       success = pushcase (value1, convert_and_check, label, &duplicate);
-      else
-       success = pushcase (NULL_TREE, 0, label, &duplicate);
-
-      if (success == 1)
-       {
-         if (end)
-           error ("case label not within a switch statement");
-         else if (start)
-           cp_error ("case label `%E' not within a switch statement", start);
-         else
-           error ("default label not within a switch statement");
-       }
-      else if (success == 2)
-       {
-         if (end)
-           {
-             error ("duplicate (or overlapping) case value");
-             cp_error_at ("this is the first entry overlapping that value",
-                          duplicate);
-           }
-         else if (start)
-           {
-             cp_error ("duplicate case value `%E'", start);
-             cp_error_at ("previously used here", duplicate);
-           }
-         else
-           {
-             error ("multiple default labels in one switch");
-             cp_error_at ("this is the first default label", duplicate);
-           }
-       }
-      else if (success == 3)
-       warning ("case value out of range");
-      else if (success == 4)
-       warning ("empty range specified");
-      else if (success == 5)
-       {
-         if (end)
-           error ("case label within scope of cleanup or variable array");
-         else if (! start)
-           error ("`default' label within scope of cleanup or variable array");
-         else
-           cp_error ("case label `%E' within scope of cleanup or variable array", start);
-       }
-    }
-
-  current_function_return_value = NULL_TREE;
-}
index 51421fd9a17cb238e0bdae4e4d937b6cffad21da..dc6f00f931c0f6760b108f1060fd810ad1090027 100644 (file)
@@ -7269,7 +7269,8 @@ tsubst_expr (t, args, complain, in_decl)
     case CASE_LABEL:
       prep_stmt (t);
       finish_case_label (tsubst_expr (CASE_LOW (t), args, complain, in_decl),
-                        tsubst_expr (CASE_HIGH (t), args, complain, in_decl));
+                        tsubst_expr (CASE_HIGH (t), args, complain,
+                                     in_decl));
       break;
 
     case LABEL_STMT:
index e1a73cee6bc2ec0afae1bfbfc5e65b9b75ee7057..b7abff29dec27544b7fa17f89bc85cd9e3f6e696 100644 (file)
@@ -55,23 +55,9 @@ static void genrtl_handler PARAMS ((tree));
 static void genrtl_catch_block PARAMS ((tree));
 static void genrtl_ctor_stmt PARAMS ((tree));
 static void genrtl_subobject PARAMS ((tree));
-static tree genrtl_do_poplevel PARAMS ((void));
 static void genrtl_named_return_value PARAMS ((void));
 static void cp_expand_stmt PARAMS ((tree));
 
-/* When parsing a template, LAST_TREE contains the last statement
-   parsed.  These are chained together through the TREE_CHAIN field,
-   but often need to be re-organized since the parse is performed
-   bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
-   STMT.  */
-
-#define RECHAIN_STMTS(stmt, substmt)           \
-  do {                                         \
-    substmt = TREE_CHAIN (stmt);               \
-    TREE_CHAIN (stmt) = NULL_TREE;             \
-    last_tree = stmt;                          \
-  } while (0)
-
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
 #define FINISH_COND(cond, stmt, substmt)               \
@@ -520,7 +506,7 @@ finish_for_stmt (for_stmt)
 void
 finish_break_stmt ()
 {
-  add_stmt (build_stmt (BREAK_STMT));
+  add_stmt (build_break_stmt ());
 }
 
 /* Finish a continue-statement.  */
@@ -528,7 +514,7 @@ finish_break_stmt ()
 void
 finish_continue_stmt ()
 {
-  add_stmt (build_stmt (CONTINUE_STMT));
+  add_stmt (build_continue_stmt ());
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
@@ -553,6 +539,9 @@ finish_switch_cond (cond, switch_stmt)
 {
   if (!processing_template_decl)
     {
+      tree type;
+      tree index;
+
       /* Convert the condition to an integer or enumeration type.  */
       cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1);
       if (cond == NULL_TREE)
@@ -565,9 +554,19 @@ finish_switch_cond (cond, switch_stmt)
          cond = default_conversion (cond);
          cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
        }
+
+      type = TREE_TYPE (cond);
+      index = get_unwidened (cond, NULL_TREE);
+      /* We can't strip a conversion from a signed type to an unsigned,
+        because if we did, int_fits_type_p would do the wrong thing
+        when checking case values for being in range,
+        and it's too hard to do the right thing.  */
+      if (TREE_UNSIGNED (TREE_TYPE (cond))
+         == TREE_UNSIGNED (TREE_TYPE (index)))
+       cond = index;
     }
   FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
-  push_switch ();
+  push_switch (switch_stmt);
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -583,21 +582,6 @@ finish_switch_stmt (switch_stmt)
   finish_stmt ();
 }
 
-/* Finish a case-label.  */
-
-void 
-finish_case_label (low_value, high_value)
-     tree low_value;
-     tree high_value;
-{
-  /* Add a representation for the case label to the statement
-     tree.  */
-  add_stmt (build_stmt (CASE_LABEL, low_value, high_value));
-  /* And warn about crossing initializations, etc.  */
-  if (!processing_template_decl)
-    define_case_label ();
-}
-
 /* Generate the RTL for T, which is a TRY_BLOCK. */
 
 static void 
index bff019d36c9a4c29be1922db6b17385aa3f9952c..e15a7248930ff29cab49231ce97b3f6a00f6e172 100644 (file)
@@ -6839,56 +6839,7 @@ check_return_expr (retval)
   return retval;
 }
 
-/* Expand a C `return' statement.
-   RETVAL is the expression for what to return,
-   or a null pointer for `return;' with no value.
-
-   C++: upon seeing a `return', we must call destructors on all
-   variables in scope which had constructors called on them.
-   This means that if in a destructor, the base class destructors
-   must be called before returning.
-
-   The RETURN statement in C++ has initialization semantics.  */
-
-void
-c_expand_return (retval)
-     tree retval;
-{
-  if (!retval)
-    expand_null_return ();
-  else
-    {
-      expand_start_target_temps ();
-      expand_return (retval);
-      expand_end_target_temps ();
-    }
-}
 \f
-/* Start a C switch statement, testing expression EXP.
-   Return EXP if it is valid, an error node otherwise.  */
-
-tree
-c_expand_start_case (exp)
-     tree exp;
-{
-  tree type;
-  tree index;
-
-  type = TREE_TYPE (exp);
-  index = get_unwidened (exp, NULL_TREE);
-  /* We can't strip a conversion from a signed type to an unsigned,
-     because if we did, int_fits_type_p would do the wrong thing
-     when checking case values for being in range,
-     and it's too hard to do the right thing.  */
-  if (TREE_UNSIGNED (TREE_TYPE (exp))
-      == TREE_UNSIGNED (TREE_TYPE (index)))
-    exp = index;
-
-  expand_start_case (1, exp, type, "switch statement");
-
-  return exp;
-}
-
 /* Returns non-zero if the pointer-type FROM can be converted to the
    pointer-type TO via a qualification conversion.  If CONSTP is -1,
    then we return non-zero if the pointers are similar, and the
index 46b2317149faed7de083bd99c53bc4527c579425..6adee8159d7321e3bc2d290bb82d04089616c10b 100644 (file)
@@ -240,8 +240,6 @@ struct nesting
          tree index_expr;
          /* Type that INDEX_EXPR should be converted to.  */
          tree nominal_type;
-         /* Number of range exprs in case statement.  */
-         int num_ranges;
          /* Name of this kind of statement, for warnings.  */
          const char *printname;
          /* Used to save no_line_numbers till we see the first case label.
@@ -421,7 +419,6 @@ static int node_has_high_bound              PARAMS ((case_node_ptr, tree));
 static int node_is_bounded             PARAMS ((case_node_ptr, tree));
 static void emit_jump_if_reachable     PARAMS ((rtx));
 static void emit_case_nodes            PARAMS ((rtx, case_node_ptr, rtx, tree));
-static int add_case_node               PARAMS ((tree, tree, tree, tree *));
 static struct case_node *case_tree2list        PARAMS ((case_node *, case_node *));
 static void mark_cond_nesting           PARAMS ((struct nesting *));
 static void mark_loop_nesting           PARAMS ((struct nesting *));
@@ -4426,7 +4423,6 @@ expand_start_case (exit_flag, expr, type, printname)
   thiscase->data.case_stmt.index_expr = expr;
   thiscase->data.case_stmt.nominal_type = type;
   thiscase->data.case_stmt.default_label = 0;
-  thiscase->data.case_stmt.num_ranges = 0;
   thiscase->data.case_stmt.printname = printname;
   thiscase->data.case_stmt.line_number_status = force_line_numbers ();
   case_stack = thiscase;
@@ -4464,7 +4460,6 @@ expand_start_case_dummy ()
   thiscase->data.case_stmt.start = 0;
   thiscase->data.case_stmt.nominal_type = 0;
   thiscase->data.case_stmt.default_label = 0;
-  thiscase->data.case_stmt.num_ranges = 0;
   case_stack = thiscase;
   nesting_stack = thiscase;
   start_cleanup_deferral ();
@@ -4580,21 +4575,7 @@ pushcase (value, converter, label, duplicate)
          || ! int_fits_type_p (value, index_type)))
     return 3;
 
-  /* Fail if this is a duplicate or overlaps another entry.  */
-  if (value == 0)
-    {
-      if (case_stack->data.case_stmt.default_label != 0)
-       {
-         *duplicate = case_stack->data.case_stmt.default_label;
-         return 2;
-       }
-      case_stack->data.case_stmt.default_label = label;
-    }
-  else
-    return add_case_node (value, value, label, duplicate);
-
-  expand_label (label);
-  return 0;
+  return add_case_node (value, value, label, duplicate);
 }
 
 /* Like pushcase but this case applies to all values between VALUE1 and
@@ -4670,7 +4651,7 @@ pushcase_range (value1, value2, converter, label, duplicate)
    into case_stack->data.case_stmt.case_list.  Use an AVL tree to avoid
    slowdown for large switch statements.  */
 
-static int
+int
 add_case_node (low, high, label, duplicate)
      tree low, high;
      tree label;
@@ -4678,6 +4659,25 @@ add_case_node (low, high, label, duplicate)
 {
   struct case_node *p, **q, *r;
 
+  /* If there's no HIGH value, then this is not a case range; it's
+     just a simple case label.  But that's just a degenerate case
+     range.  */
+  if (!high)
+    high = low;
+
+  /* Handle default labels specially.  */
+  if (!high && !low)
+    {
+      if (case_stack->data.case_stmt.default_label != 0)
+       {
+         *duplicate = case_stack->data.case_stmt.default_label;
+         return 2;
+       }
+      case_stack->data.case_stmt.default_label = label;
+      expand_label (label);
+      return 0;
+    }
+
   q = &case_stack->data.case_stmt.case_list;
   p = *q;
 
@@ -4709,14 +4709,10 @@ add_case_node (low, high, label, duplicate)
   r->low = copy_node (low);
 
   /* If the bounds are equal, turn this into the one-value case.  */
-
   if (tree_int_cst_equal (low, high))
     r->high = r->low;
   else
-    {
-      r->high = copy_node (high);
-      case_stack->data.case_stmt.num_ranges++;
-    }
+    r->high = copy_node (high);
 
   r->code_label = label;
   expand_label (label);
index e1a4a7d0eb67b590d0ed34b7d811c536148e956d..d396cc11ca8d16e7fdaab84586301fae64bb9328 100644 (file)
@@ -4293,6 +4293,21 @@ tree_int_cst_lt (t1, t2)
   return INT_CST_LT_UNSIGNED (t1, t2);
 }
 
+/* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2.  */
+
+int
+tree_int_cst_compare (t1, t2)
+     tree t1;
+     tree t2;
+{
+  if (tree_int_cst_lt (t1, t2))
+    return -1;
+  else if (tree_int_cst_lt (t2, t1))
+    return 1;
+  else 
+    return 0;
+}
+
 /* Return 1 if T is an INTEGER_CST that can be represented in a single
    HOST_WIDE_INT value.  If POS is nonzero, the result must be positive.  */
 
index 245f413c77b3f40916218941819b664efb667f59..baf3226666139c262b0f8d10cc63e20bdf8e3e9e 100644 (file)
@@ -1943,6 +1943,7 @@ extern int attribute_list_equal           PARAMS ((tree, tree));
 extern int attribute_list_contained    PARAMS ((tree, tree));
 extern int tree_int_cst_equal          PARAMS ((tree, tree));
 extern int tree_int_cst_lt             PARAMS ((tree, tree));
+extern int tree_int_cst_compare         PARAMS ((tree, tree));
 extern int host_integerp               PARAMS ((tree, int));
 extern HOST_WIDE_INT tree_low_cst      PARAMS ((tree, int));
 extern int tree_int_cst_msb            PARAMS ((tree));
@@ -2497,6 +2498,8 @@ extern int expand_dcc_cleanup                     PARAMS ((tree));
 extern void expand_start_case                  PARAMS ((int, tree, tree,
                                                       const char *));
 extern void expand_end_case                    PARAMS ((tree));
+extern int add_case_node                        PARAMS ((tree, tree,
+                                                        tree, tree *));
 extern int pushcase                            PARAMS ((tree,
                                                       tree (*) (tree, tree),
                                                       tree, tree *));