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]

C/C++ PATCH: `case' handling



The C++ semantic analysis for case statements was still happenning at
RTL-generation time.  Fixed with this patch, which also shares a
little more code between the C and C++ front-ends, and continues to
prepare the C front-end for function-at-a-time mode.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

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-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.
	
Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.149
diff -c -p -r1.149 c-common.c
*** c-common.c	2000/09/07 17:20:03	1.149
--- c-common.c	2000/09/10 21:22:28
*************** check_case_value (value)
*** 2678,2683 ****
--- 2678,2695 ----
  
    /* 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: gcc/c-common.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.def,v
retrieving revision 1.2
diff -c -p -r1.2 c-common.def
*** c-common.def	2000/06/19 18:40:19	1.2
--- c-common.def	2000/09/10 21:22:28
*************** DEFTREECODE (SCOPE_STMT, "scope_stmt", '
*** 95,102 ****
  /* 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)
  
  /* A STMT_EXPR represents a statement-expression.  The
     STMT_EXPR_STMT is the statement given by the expression.  */
--- 95,102 ----
  /* 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.  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: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.h,v
retrieving revision 1.36
diff -c -p -r1.36 c-common.h
*** c-common.h	2000/09/07 06:55:48	1.36
--- c-common.h	2000/09/10 21:22:28
*************** typedef tree (*walk_tree_fn)            
*** 256,262 ****
  
  extern stmt_tree current_stmt_tree              PARAMS ((void));
  extern void begin_stmt_tree                     PARAMS ((tree *));
! extern void add_stmt				PARAMS ((tree));
  extern void finish_stmt_tree                    PARAMS ((tree *));
  
  extern int statement_code_p                     PARAMS ((enum tree_code));
--- 256,262 ----
  
  extern stmt_tree current_stmt_tree              PARAMS ((void));
  extern void begin_stmt_tree                     PARAMS ((tree *));
! extern tree add_stmt				PARAMS ((tree));
  extern void finish_stmt_tree                    PARAMS ((tree *));
  
  extern int statement_code_p                     PARAMS ((enum tree_code));
*************** extern void prep_stmt                   
*** 268,273 ****
--- 268,285 ----
  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.  */
  
*************** extern tree simple_type_promotes_to		PAR
*** 457,462 ****
--- 469,475 ----
     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. */
*************** extern void genrtl_break_stmt           
*** 570,576 ****
  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_compound_stmt                PARAMS ((tree));
  extern void genrtl_asm_stmt                     PARAMS ((tree, tree,
  							 tree, tree,
--- 583,589 ----
  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));
  extern void genrtl_compound_stmt                PARAMS ((tree));
  extern void genrtl_asm_stmt                     PARAMS ((tree, tree,
  							 tree, tree,
*************** extern void emit_local_var              
*** 589,598 ****
  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_continue_stmt                 PARAMS ((void));
  extern tree build_break_stmt                    PARAMS ((void));
  extern tree build_return_stmt                   PARAMS ((tree));
--- 602,610 ----
  extern void make_rtl_for_local_static           PARAMS ((tree));
  extern tree expand_cond                         PARAMS ((tree));
  extern void c_expand_return			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, tree));
  extern tree build_continue_stmt                 PARAMS ((void));
  extern tree build_break_stmt                    PARAMS ((void));
  extern tree build_return_stmt                   PARAMS ((tree));
*************** extern tree default_conversion          
*** 619,624 ****
--- 631,638 ----
  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.  */
Index: gcc/c-parse.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-parse.in,v
retrieving revision 1.56
diff -c -p -r1.56 c-parse.in
*** c-parse.in	2000/09/10 07:07:20	1.56
--- c-parse.in	2000/09/10 21:22:30
*************** stmt:
*** 1879,1891 ****
                    stmt_count++;
  		  genrtl_continue_stmt (); }
  	| RETURN ';'
!                 { tree return_stmt = build_return_stmt (NULL_TREE);
!                   stmt_count++;
! 		  genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
  	| RETURN expr ';'
!                 { tree return_stmt = build_return_stmt ($2);
!                   stmt_count++;
! 		  genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
  	| ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
  		{ stmt_count++;
  		  emit_line_note ($<filename>-1, $<lineno>0);
--- 1879,1889 ----
                    stmt_count++;
  		  genrtl_continue_stmt (); }
  	| RETURN ';'
!                 { stmt_count++;
! 		  c_expand_return (NULL_TREE); }
  	| RETURN expr ';'
!                 { stmt_count++;
! 		  c_expand_return ($2); }
  	| ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
  		{ stmt_count++;
  		  emit_line_note ($<filename>-1, $<lineno>0);
*************** stmt:
*** 1943,1962 ****
     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));
! 		}
  	| 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));
! 		}
  	| 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));
! 		}
  	| identifier save_filename save_lineno ':' maybe_attribute
  		{ tree label = define_label ($2, $3, $1);
  		  stmt_count++;
--- 1941,1954 ----
     also at the end of a compound statement.  */
  
  label:	  CASE expr_no_commas ':'
!                 { stmt_count++;
! 		  do_case ($2, NULL_TREE); }
  	| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
!                 { stmt_count++;
! 		  do_case ($2, $4); }
  	| DEFAULT ':'
!                 { 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: gcc/c-semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-semantics.c,v
retrieving revision 1.6
diff -c -p -r1.6 c-semantics.c
*** c-semantics.c	2000/09/07 06:55:49	1.6
--- c-semantics.c	2000/09/10 21:22:30
*************** begin_stmt_tree (t)
*** 58,64 ****
  
  /* T is a statement.  Add it to the statement-tree.  */
  
! void
  add_stmt (t)
       tree t;
  {
--- 58,64 ----
  
  /* T is a statement.  Add it to the statement-tree.  */
  
! tree
  add_stmt (t)
       tree t;
  {
*************** add_stmt (t)
*** 68,73 ****
--- 68,74 ----
    /* 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
*************** build_return_stmt (expr)
*** 434,447 ****
    return (build_stmt (RETURN_STMT, expr));
  }
  
! /* Generate the RTL for EXPR, which is a RETURN_STMT. */
  
  void
! genrtl_return_stmt (expr)
!      tree expr;
  {
    emit_line_note (input_filename, lineno);
!   c_expand_return (expr);
  }
  
  /* Generate the RTL for T, which is a FOR_STMT. */
--- 435,457 ----
    return (build_stmt (RETURN_STMT, expr));
  }
  
! /* Generate the RTL for STMT, which is a RETURN_STMT. */
  
  void
! genrtl_return_stmt (stmt)
!      tree stmt;
  {
+   tree expr = RETURN_EXPR (stmt);
+ 
    emit_line_note (input_filename, lineno);
!   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. */
*************** genrtl_switch_stmt (t)
*** 547,586 ****
    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
      /* The code is in error, but we don't want expand_end_case to
         crash. */
!     c_expand_start_case (boolean_false_node);
  
    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)
       tree low_value;
       tree high_value;
  {
!   return build_stmt (CASE_LABEL, low_value, high_value);
  }
  
  
  /* Generate the RTL for a CASE_LABEL. */
  
  void 
! genrtl_case_label (low_value, high_value)
!      tree low_value;
!      tree high_value;
  {
!   do_case (low_value, high_value);
  }
  
  /* Generate the RTL for T, which is a COMPOUND_STMT. */
--- 557,594 ----
    genrtl_do_pushlevel ();
   
    cond = expand_cond (SWITCH_COND (t));
!   if (cond == error_mark_node)
      /* The code is in error, but we don't want expand_end_case to
         crash. */
!     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, label_decl)
       tree low_value;
       tree high_value;
+      tree label_decl;
  {
!   return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
  }
  
  
  /* Generate the RTL for a CASE_LABEL. */
  
  void 
! genrtl_case_label (case_label)
!      tree case_label;
  {
!   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. */
*************** expand_stmt (t)
*** 677,683 ****
        switch (TREE_CODE (t))
  	{
  	case RETURN_STMT:
! 	  genrtl_return_stmt (RETURN_EXPR (t));
  	  break;
  
  	case EXPR_STMT:
--- 685,691 ----
        switch (TREE_CODE (t))
  	{
  	case RETURN_STMT:
! 	  genrtl_return_stmt (t);
  	  break;
  
  	case EXPR_STMT:
*************** expand_stmt (t)
*** 721,727 ****
  	  break;
  
  	case CASE_LABEL:
! 	  genrtl_case_label (CASE_LOW (t), CASE_HIGH (t));
  	  break;
  
  	case LABEL_STMT:
--- 729,735 ----
  	  break;
  
  	case CASE_LABEL:
! 	  genrtl_case_label (t);
  	  break;
  
  	case LABEL_STMT:
Index: gcc/c-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-tree.h,v
retrieving revision 1.44
diff -c -p -r1.44 c-tree.h
*** c-tree.h	2000/09/07 00:37:09	1.44
--- c-tree.h	2000/09/10 21:22:31
*************** extern void set_init_label			PARAMS ((tr
*** 268,273 ****
--- 268,274 ----
  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: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-typeck.c,v
retrieving revision 1.85
diff -c -p -r1.85 c-typeck.c
*** c-typeck.c	2000/08/25 00:58:26	1.85
--- c-typeck.c	2000/09/10 21:22:34
*************** static tree qualify_type		PARAMS ((tree,
*** 54,60 ****
  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));
--- 54,59 ----
*************** c_alignof_expr (expr)
*** 838,844 ****
  
  /* Return either DECL or its known constant value (if it has one).  */
  
! static tree
  decl_constant_value (decl)
       tree decl;
  {
--- 837,843 ----
  
  /* Return either DECL or its known constant value (if it has one).  */
  
! tree
  decl_constant_value (decl)
       tree decl;
  {
*************** c_expand_return (retval)
*** 6629,6642 ****
        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
      {
--- 6628,6639 ----
*************** c_expand_return (retval)
*** 6701,6711 ****
  	  break;
  	}
  
!       t = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
!       TREE_SIDE_EFFECTS (t) = 1;
!       expand_return (t);
        current_function_returns_value = 1;
      }
  }
  
  /* Start a C switch statement, testing expression EXP.
--- 6698,6708 ----
  	  break;
  	}
  
!       retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
        current_function_returns_value = 1;
      }
+ 
+   genrtl_return_stmt (build_return_stmt (retval));
  }
  
  /* Start a C switch statement, testing expression EXP.
Index: gcc/stmt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stmt.c,v
retrieving revision 1.165
diff -c -p -r1.165 stmt.c
*** stmt.c	2000/09/02 02:54:55	1.165
--- stmt.c	2000/09/10 21:22:38
*************** struct nesting
*** 240,247 ****
  	  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.
--- 240,245 ----
*************** static int node_has_high_bound		PARAMS (
*** 421,427 ****
  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 *));
--- 419,424 ----
*************** expand_start_case (exit_flag, expr, type
*** 4426,4432 ****
    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;
--- 4423,4428 ----
*************** expand_start_case_dummy ()
*** 4464,4470 ****
    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 ();
--- 4460,4465 ----
*************** pushcase (value, converter, label, dupli
*** 4580,4600 ****
  	  || ! 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;
  }
  
  /* Like pushcase but this case applies to all values between VALUE1 and
--- 4575,4581 ----
  	  || ! int_fits_type_p (value, index_type)))
      return 3;
  
!   return add_case_node (value, value, label, duplicate);
  }
  
  /* Like pushcase but this case applies to all values between VALUE1 and
*************** pushcase_range (value1, value2, converte
*** 4670,4676 ****
     into case_stack->data.case_stmt.case_list.  Use an AVL tree to avoid
     slowdown for large switch statements.  */
  
! static int
  add_case_node (low, high, label, duplicate)
       tree low, high;
       tree label;
--- 4651,4657 ----
     into case_stack->data.case_stmt.case_list.  Use an AVL tree to avoid
     slowdown for large switch statements.  */
  
! int
  add_case_node (low, high, label, duplicate)
       tree low, high;
       tree label;
*************** add_case_node (low, high, label, duplica
*** 4678,4683 ****
--- 4659,4683 ----
  {
    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;
  
*************** add_case_node (low, high, label, duplica
*** 4709,4722 ****
    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->code_label = label;
    expand_label (label);
--- 4709,4718 ----
    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);
  
    r->code_label = label;
    expand_label (label);
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.c,v
retrieving revision 1.156
diff -c -p -r1.156 tree.c
*** tree.c	2000/08/29 21:39:45	1.156
--- tree.c	2000/09/10 21:22:41
*************** tree_int_cst_lt (t1, t2)
*** 4293,4298 ****
--- 4293,4313 ----
    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: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.195
diff -c -p -r1.195 tree.h
*** tree.h	2000/08/30 22:50:52	1.195
--- tree.h	2000/09/10 21:22:44
*************** extern int attribute_list_equal		PARAMS 
*** 1943,1948 ****
--- 1943,1949 ----
  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));
*************** extern int expand_dcc_cleanup			PARAMS (
*** 2497,2502 ****
--- 2498,2505 ----
  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 *));
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.526
diff -c -p -r1.526 cp-tree.h
*** cp-tree.h	2000/09/07 06:55:51	1.526
--- cp-tree.h	2000/09/10 21:22:52
*************** extern void pop_nested_namespace		PARAMS
*** 3829,3835 ****
  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 pop_switch				PARAMS ((void));
  extern tree identifier_type_value		PARAMS ((tree));
  extern void set_identifier_type_value		PARAMS ((tree, tree));
--- 3829,3835 ----
  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 ((tree));
  extern void pop_switch				PARAMS ((void));
  extern tree identifier_type_value		PARAMS ((tree));
  extern void set_identifier_type_value		PARAMS ((tree, tree));
*************** extern tree reparse_absdcl_as_casts		PAR
*** 3990,3996 ****
  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));
--- 3990,3995 ----
*************** extern tree get_type_value			PARAMS ((tr
*** 4075,4081 ****
  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));
--- 4074,4079 ----
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.686
diff -c -p -r1.686 decl.c
*** decl.c	2000/09/07 03:50:52	1.686
--- decl.c	2000/09/10 21:23:01
*************** static tree check_special_function_retur
*** 187,192 ****
--- 187,193 ----
    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));
*************** struct cp_switch
*** 5176,5192 ****
  {
    struct binding_level *level;
    struct cp_switch *next;
  };
  
  static struct cp_switch *switch_stack;
  
  void
! push_switch ()
  {
    struct cp_switch *p
      = (struct cp_switch *) xmalloc (sizeof (struct cp_switch));
    p->level = current_binding_level;
    p->next = switch_stack;
    switch_stack = p;
  }
  
--- 5177,5228 ----
  {
    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 (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;
  }
  
*************** pop_switch ()
*** 5196,5201 ****
--- 5232,5238 ----
    struct cp_switch *cs;
    
    cs = switch_stack;
+   splay_tree_delete (cs->cases);
    switch_stack = switch_stack->next;
    free (cs);
  }
*************** pop_switch ()
*** 5204,5217 ****
     is a bad place for one.  */
  
  void
! define_case_label ()
  {
!   tree cleanup = last_cleanup_this_contour ();
  
    if (! switch_stack)
!     /* Don't crash; we'll complain in do_case.  */
      return;
  
    if (cleanup)
      {
        static int explained = 0;
--- 5241,5390 ----
     is a bad place for one.  */
  
  void
! finish_case_label (low_value, high_value)
!      tree low_value;
!      tree high_value;
  {
!   tree label;
!   tree cleanup;
!   tree type;
!   tree cond;
!   tree case_label;
!   splay_tree_node node;
  
    if (! switch_stack)
!     {
!       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;
*************** define_case_label ()
*** 5228,5236 ****
  
    /* 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;
  }
  
  /* Return the list of declarations of the current level.
--- 5401,5418 ----
  
    /* 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);
  }
  
  /* Return the list of declarations of the current level.
*************** start_function (declspecs, declarator, a
*** 13601,13607 ****
    if (flags & SF_INCLASS_INLINE)
      maybe_begin_member_template_processing (decl1);
  
!   /* Effective C++ rule 15.  See also c_expand_return.  */
    if (warn_ecpp
        && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
        && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
--- 13783,13789 ----
    if (flags & SF_INCLASS_INLINE)
      maybe_begin_member_template_processing (decl1);
  
!   /* Effective C++ rule 15.  */
    if (warn_ecpp
        && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
        && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.394
diff -c -p -r1.394 decl2.c
*** decl2.c	2000/09/07 00:37:12	1.394
--- decl2.c	2000/09/10 21:23:04
*************** finish_decl_parsing (decl)
*** 4329,4363 ****
      }
  }
  
- 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
--- 4329,4334 ----
Index: gcc/cp/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/expr.c,v
retrieving revision 1.51
diff -c -p -r1.51 expr.c
*** expr.c	2000/06/04 21:12:27	1.51
--- expr.c	2000/09/10 21:23:04
*************** extract_init (decl, init)
*** 205,286 ****
    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;
- }
--- 205,207 ----
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.465
diff -c -p -r1.465 pt.c
*** pt.c	2000/09/06 09:34:00	1.465
--- pt.c	2000/09/10 21:23:10
*************** tsubst_expr (t, args, complain, in_decl)
*** 7269,7275 ****
      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));
        break;
  
      case LABEL_STMT:
--- 7269,7276 ----
      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));
        break;
  
      case LABEL_STMT:
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.172
diff -c -p -r1.172 semantics.c
*** semantics.c	2000/09/07 06:55:51	1.172
--- semantics.c	2000/09/10 21:23:11
*************** static void genrtl_handler PARAMS ((tree
*** 55,77 ****
  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) 		\
--- 55,63 ----
*************** finish_for_stmt (for_stmt)
*** 520,526 ****
  void
  finish_break_stmt ()
  {
!   add_stmt (build_stmt (BREAK_STMT));
  }
  
  /* Finish a continue-statement.  */
--- 506,512 ----
  void
  finish_break_stmt ()
  {
!   add_stmt (build_break_stmt ());
  }
  
  /* Finish a continue-statement.  */
*************** finish_break_stmt ()
*** 528,534 ****
  void
  finish_continue_stmt ()
  {
!   add_stmt (build_stmt (CONTINUE_STMT));
  }
  
  /* Begin a switch-statement.  Returns a new SWITCH_STMT if
--- 514,520 ----
  void
  finish_continue_stmt ()
  {
!   add_stmt (build_continue_stmt ());
  }
  
  /* Begin a switch-statement.  Returns a new SWITCH_STMT if
*************** finish_switch_cond (cond, switch_stmt)
*** 553,558 ****
--- 539,547 ----
  {
    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)
*************** finish_switch_cond (cond, switch_stmt)
*** 565,573 ****
  	  cond = default_conversion (cond);
  	  cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
  	}
      }
    FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
!   push_switch ();
  }
  
  /* Finish the body of a switch-statement, which may be given by
--- 554,572 ----
  	  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 (switch_stmt);
  }
  
  /* Finish the body of a switch-statement, which may be given by
*************** finish_switch_stmt (switch_stmt)
*** 581,601 ****
    pop_switch (); 
    do_poplevel ();
    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. */
--- 580,585 ----
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.309
diff -c -p -r1.309 typeck.c
*** typeck.c	2000/09/06 09:21:35	1.309
--- typeck.c	2000/09/10 21:23:15
*************** check_return_expr (retval)
*** 6839,6894 ****
    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 ();
-     }
- }
  
- /* 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
--- 6839,6845 ----

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