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]
Other format: [Raw text]

Reorganize C statement parsing


Since we're no longer constrained to emit rtl (or statements) in
a linear fashion, a lot of the complex statement parsing can be
cleaned up.  In particular:

  * No more external stack of if statements.  No more stmt_count.
    We can generate the warnings that we tracked with that external
    state directly from the parser state.

  * Break and continue statements resolved to loop labels immediately.

  * Loop constructs lowered immediately.

All of which should minimize the memory allocated for parsing and
gimplification.  Though I've not actually measured anything yet.


r~


	* c-decl.c (c_in_iteration_stmt, c_in_case_stmt): Remove.
	(c_break_label, c_cont_label): New.
	(start_function): Update initializations.
	(c_push_function_context): Update saves.
	(c_pop_function_context): Update restores.
	* c-parse.in: Update expected conflicts.
	(stmt_count, compstmt_count): Remove.  Remove all updates.
	(if_prefix, simple_if, do_stmt_start): Remove.
	(lineno_labeled_stmt): Remove.
	(lineno_labels): New.
	(c99_block_lineno_labeled_stmt): Use it.
	(lineno_stmt, lineno_label): Don't clear EXPR_LOCUS before calling
	annotate_with_locus.
	(select_or_iter_stmt): Replace by ...
	(condition, if_statement_1, if_statement_2, if_statement,
	start_break, start_continue, while_statement, do_statement,
	for_cond_expr, for_incr_expr, for_statement, switch_statement): New.
	(stmt): Split out ...
	(stmt_nocomp): ... this.  Use c_finish_bc_stmt, c_finish_goto_label,
	c_finish_goto_ptr.
	* c-semantics.c (add_stmt): Don't add line numbers to labels.
	* c-tree.h: Update prototypes.
	(struct language_function): Remove x_in_iteration_stmt, x_in_case_stmt;
	add x_break_label, x_cont_label, x_switch_stack.
	(c_switch_stack): Declare.
	* c-typeck.c (c_finish_goto_label, c_finish_goto_ptr): New.
	(c_finish_return): Return the statement.
	(c_switch_stack): Rename from switch_stack; export.
	(if_elt, if_stack, if_stack_space, if_stack_pointer): Remove.
	(c_begin_if_stmt, c_finish_if_cond, c_finish_then, c_begin_else,
	c_finish_else): Remove.
	(c_finish_if_stmt): Rewrite to perform the entire operation.
	(c_begin_while_stmt, c_finish_while_stmt_cond, c_finish_while_stmt,
	c_begin_for_stmt, c_finish_for_stmt_init, c_finish_for_stmt_cond,
	c_finish_for_stmt_incr, c_finish_for_stmt): Remove.
	(c_finish_loop): New.
	(c_finish_bc_stmt): New.
	(c_finish_expr_stmt): Return the statement.  Split out...
	(c_process_expr_stmt): ... this.  Don't add locus to error marks.
	* gimplify.c (gimplify_cond_expr): Accept NULL type statements.
	* tree-gimple.c (is_gimple_stmt): Likewise.
	* tree-pretty-print.c (dump_generic_node <COND_EXPR>): Likewise.
	(print_struct_decl): Delete empty compound statement.
	* objc/objc-act.c (objc_build_throw_stmt): Return the statement.
	* objc/objc-act.h: Update decl.

Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.517
diff -u -p -c -r1.517 c-decl.c
*** c-decl.c	24 Jun 2004 12:09:41 -0000	1.517
--- c-decl.c	24 Jun 2004 22:59:12 -0000
*************** static location_t current_function_proto
*** 109,116 ****
  static GTY(()) struct stmt_tree_s c_stmt_tree;
  
  /* State saving variables.  */
! int c_in_iteration_stmt;
! int c_in_case_stmt;
  
  /* Linked list of TRANSLATION_UNIT_DECLS for the translation units
     included in this invocation.  Note that the current translation
--- 109,116 ----
  static GTY(()) struct stmt_tree_s c_stmt_tree;
  
  /* State saving variables.  */
! tree c_break_label;
! tree c_cont_label;
  
  /* Linked list of TRANSLATION_UNIT_DECLS for the translation units
     included in this invocation.  Note that the current translation
*************** start_function (tree declspecs, tree dec
*** 5592,5599 ****
    current_function_returns_abnormally = 0;
    warn_about_return_type = 0;
    current_extern_inline = 0;
!   c_in_iteration_stmt = 0;
!   c_in_case_stmt = 0;
  
    /* Don't expand any sizes in the return type of the function.  */
    immediate_size_expand = 0;
--- 5592,5603 ----
    current_function_returns_abnormally = 0;
    warn_about_return_type = 0;
    current_extern_inline = 0;
!   c_switch_stack = NULL;
! 
!   /* Indicate no valid break/continue context by setting these variables
!      to some non-null, non-label value.  We'll notice and emit the proper
!      error message in c_finish_bc_stmt.  */
!   c_break_label = c_cont_label = size_zero_node;
  
    /* Don't expand any sizes in the return type of the function.  */
    immediate_size_expand = 0;
*************** c_push_function_context (struct function
*** 6410,6417 ****
    f->language = p;
  
    p->base.x_stmt_tree = c_stmt_tree;
!   p->x_in_iteration_stmt = c_in_iteration_stmt;
!   p->x_in_case_stmt = c_in_case_stmt;
    p->returns_value = current_function_returns_value;
    p->returns_null = current_function_returns_null;
    p->returns_abnormally = current_function_returns_abnormally;
--- 6414,6422 ----
    f->language = p;
  
    p->base.x_stmt_tree = c_stmt_tree;
!   p->x_break_label = c_break_label;
!   p->x_cont_label = c_cont_label;
!   p->x_switch_stack = c_switch_stack;
    p->returns_value = current_function_returns_value;
    p->returns_null = current_function_returns_null;
    p->returns_abnormally = current_function_returns_abnormally;
*************** c_pop_function_context (struct function 
*** 6437,6444 ****
      }
  
    c_stmt_tree = p->base.x_stmt_tree;
!   c_in_iteration_stmt = p->x_in_iteration_stmt;
!   c_in_case_stmt = p->x_in_case_stmt;
    current_function_returns_value = p->returns_value;
    current_function_returns_null = p->returns_null;
    current_function_returns_abnormally = p->returns_abnormally;
--- 6442,6450 ----
      }
  
    c_stmt_tree = p->base.x_stmt_tree;
!   c_break_label = p->x_break_label;
!   c_cont_label = p->x_cont_label;
!   c_switch_stack = p->x_switch_stack;
    current_function_returns_value = p->returns_value;
    current_function_returns_null = p->returns_null;
    current_function_returns_abnormally = p->returns_abnormally;
Index: c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.219
diff -u -p -c -r1.219 c-parse.in
*** c-parse.in	21 Jun 2004 23:30:19 -0000	1.219
--- c-parse.in	24 Jun 2004 22:59:13 -0000
*************** Software Foundation, 59 Temple Place - S
*** 29,35 ****
     written by AT&T, but I have never seen it.  */
  
  @@ifc
! %expect 10 /* shift/reduce conflicts, and no reduce/reduce conflicts.  */
  @@end_ifc
  
  %{
--- 29,35 ----
     written by AT&T, but I have never seen it.  */
  
  @@ifc
! %expect 13 /* shift/reduce conflicts, and no reduce/reduce conflicts.  */
  @@end_ifc
  
  %{
*************** do {									\
*** 210,218 ****
  %type <ttype> any_word
  
  %type <ttype> compstmt compstmt_start compstmt_primary_start
! %type <ttype> do_stmt_start stmt label
  
  %type <ttype> c99_block_start c99_block_lineno_labeled_stmt
  %type <ttype> declarator
  %type <ttype> notype_declarator after_type_declarator
  %type <ttype> parm_declarator
--- 210,219 ----
  %type <ttype> any_word
  
  %type <ttype> compstmt compstmt_start compstmt_primary_start
! %type <ttype> stmt label stmt_nocomp start_break start_continue
  
  %type <ttype> c99_block_start c99_block_lineno_labeled_stmt
+ %type <ttype> if_statement_1 if_statement_2
  %type <ttype> declarator
  %type <ttype> notype_declarator after_type_declarator
  %type <ttype> parm_declarator
*************** do {									\
*** 227,233 ****
  %type <ttype> struct_head union_head enum_head
  %type <ttype> typename absdcl absdcl1 absdcl1_ea absdcl1_noea
  %type <ttype> direct_absdcl1 absdcl_maybe_attribute
! %type <ttype> xexpr parms parm firstparm identifiers
  
  %type <ttype> parmlist parmlist_1 parmlist_2
  %type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
--- 228,235 ----
  %type <ttype> struct_head union_head enum_head
  %type <ttype> typename absdcl absdcl1 absdcl1_ea absdcl1_noea
  %type <ttype> direct_absdcl1 absdcl_maybe_attribute
! %type <ttype> condition xexpr for_cond_expr for_incr_expr
! %type <ttype> parms parm firstparm identifiers
  
  %type <ttype> parmlist parmlist_1 parmlist_2
  %type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
*************** do {									\
*** 254,264 ****
  @@end_ifobjc
  
  %{
- /* Number of statements (loosely speaking) and compound statements
-    seen so far.  */
- static int stmt_count;
- static int compstmt_count;
- 
  /* List of types and structure classes of the current declaration.  */
  static GTY(()) tree current_declspecs;
  static GTY(()) tree prefix_attributes;
--- 256,261 ----
*************** compstmt_or_error:
*** 2032,2039 ****
  	| error compstmt
  	;
  
! compstmt_start: '{' { compstmt_count++;
!                       $$ = c_begin_compound_stmt (true); }
          ;
  
  compstmt_nostart: '}'
--- 2029,2035 ----
  	| error compstmt
  	;
  
! compstmt_start: '{' { $$ = c_begin_compound_stmt (true); }
          ;
  
  compstmt_nostart: '}'
*************** compstmt_primary_start:
*** 2053,2059 ****
  			     "only inside a function");
  		      YYERROR;
  		    }
- 		  compstmt_count++;
  		  $$ = c_begin_stmt_expr ();
  		}
          ;
--- 2049,2054 ----
*************** compstmt: compstmt_start compstmt_nostar
*** 2062,2108 ****
  		{ $$ = c_end_compound_stmt ($1, true); }
  	;
  
- if_prefix:
- 	  /* We must build the if statement node before parsing its
- 	     condition so that we get its location pointing to the
- 	     line containing the "if", and not the line containing
- 	     the close-parenthesis.  */
-           IF
-                 { c_begin_if_stmt (); }
-             '(' expr ')'
- 		{ c_finish_if_cond ($4, compstmt_count, ++stmt_count); }
-         ;
- 
- simple_if:
- 	  if_prefix c99_block_lineno_labeled_stmt
-                 { c_finish_then ($2); }
- 	/* Make sure c_finish_if_stmt is run for each call to
- 	   c_begin_if_stmt.  Otherwise a crash is likely.  */
- 	| if_prefix error
- 	;
- 
- /* This is a subroutine of stmt.
-    It is used twice, once for valid DO statements
-    and once for catching errors in parsing the end test.  */
- do_stmt_start:
- 	  DO
- 		{ stmt_count++;
- 		  compstmt_count++;
- 		  c_in_iteration_stmt++;
- 		  $<ttype>$
- 		    = add_stmt (build_stmt (DO_STMT, NULL_TREE,
- 					    NULL_TREE));
- 		  /* In the event that a parse error prevents
- 		     parsing the complete do-statement, set the
- 		     condition now.  Otherwise, we can get crashes at
- 		     RTL-generation time.  */
- 		  DO_COND ($<ttype>$) = error_mark_node; }
- 	  c99_block_lineno_labeled_stmt WHILE
- 		{ $$ = $<ttype>2;
- 		  DO_BODY ($$) = $3;
- 		  c_in_iteration_stmt--; }
- 	;
- 
  /* The forced readahead in here is because we might be at the end of a
     line, and the line and file won't be bumped until yylex absorbs the
     first token on the next line.  */
--- 2057,2062 ----
*************** save_location:
*** 2113,2126 ****
  		  $$ = input_location; }
  	;
  
! lineno_labeled_stmt:
! 	  lineno_stmt
! 	| lineno_label lineno_labeled_stmt
  	;
  
! /* Like lineno_labeled_stmt, but a block in C99.  */
  c99_block_lineno_labeled_stmt:
! 	  c99_block_start lineno_labeled_stmt
                  { $$ = c_end_compound_stmt ($1, flag_isoc99); }
  	;
  
--- 2067,2080 ----
  		  $$ = input_location; }
  	;
  
! lineno_labels:
! 	  /* empty */
! 	| lineno_labels lineno_label
  	;
  
! /* A labeled statement.  In C99 it also generates an implicit block.  */
  c99_block_lineno_labeled_stmt:
! 	  c99_block_start lineno_labels lineno_stmt
                  { $$ = c_end_compound_stmt ($1, flag_isoc99); }
  	;
  
*************** lineno_stmt:
*** 2138,2211 ****
  		     because (recursively) all of the component statments
  		     should already have line numbers assigned.  */
  		  if ($2 && EXPR_P ($2))
! 		    {
! 		      SET_EXPR_LOCUS ($2, NULL);
! 		      annotate_with_locus ($2, $1);
! 		    }
  		}
  	;
  
  lineno_label:
  	  save_location label
! 		{ if ($2)
! 		    {
! 		      SET_EXPR_LOCUS ($2, NULL);
! 		      annotate_with_locus ($2, $1);
! 		    }
! 		}
  	;
  
! select_or_iter_stmt:
! 	  simple_if ELSE
! 		{ c_begin_else (stmt_count); }
! 	  c99_block_lineno_labeled_stmt
!                 { c_finish_else ($4); c_finish_if_stmt (stmt_count); }
! 	| simple_if %prec IF
! 		{ c_finish_if_stmt (stmt_count); }
! 	| simple_if ELSE error
! 		{ c_finish_if_stmt (stmt_count + 1); }
!        /* We must build the WHILE_STMT node before parsing its
! 	  condition so that EXPR_LOCUS refers to the line
! 	  containing the "while", and not the line containing
! 	  the close-parenthesis.
! 
! 	  c_begin_while_stmt returns the WHILE_STMT node, which
! 	  we later pass to c_finish_while_stmt_cond to fill
! 	  in the condition and other tidbits.  */
! 	| WHILE
!                 { stmt_count++;
! 		  $<ttype>$ = c_begin_while_stmt (); }
! 	  '(' expr ')'
!                 { c_in_iteration_stmt++;
! 		  c_finish_while_stmt_cond ($4, $<ttype>2); }
! 	  c99_block_lineno_labeled_stmt
!                 { c_in_iteration_stmt--;
! 		  c_finish_while_stmt ($7, $<ttype>2); }
! 	| do_stmt_start
! 	  '(' expr ')' ';'
!                 { DO_COND ($1) = lang_hooks.truthvalue_conversion ($3); }
! 	| do_stmt_start error
! 		{ }
! 	| FOR
! 		{ $<ttype>$ = c_begin_for_stmt (); }
! 	  '(' for_init_stmt
! 		{ stmt_count++;
! 		  c_finish_for_stmt_init ($<ttype>2); }
! 	  xexpr ';'
!                 { c_finish_for_stmt_cond ($6, $<ttype>2); }
! 	  xexpr ')'
!                 { c_in_iteration_stmt++;
! 		  c_finish_for_stmt_incr ($9, $<ttype>2); }
! 	  c99_block_lineno_labeled_stmt
!                 { c_finish_for_stmt ($12, $<ttype>2);
! 		  c_in_iteration_stmt--; }
! 	| SWITCH '(' expr ')'
! 		{ stmt_count++;
! 		  $<ttype>$ = c_start_case ($3);
! 		  c_in_case_stmt++; }
! 	  c99_block_lineno_labeled_stmt
!                 { c_finish_case ($6);
! 		  c_in_case_stmt--; }
  	;
  
  for_init_stmt:
--- 2092,2182 ----
  		     because (recursively) all of the component statments
  		     should already have line numbers assigned.  */
  		  if ($2 && EXPR_P ($2))
! 		    annotate_with_locus ($2, $1);
  		}
  	;
  
  lineno_label:
  	  save_location label
! 		{ if ($2) annotate_with_locus ($2, $1); }
  	;
  
! condition: save_location expr
! 		{ $$ = lang_hooks.truthvalue_conversion ($2);
! 		  if (EXPR_P ($$))
! 		    annotate_with_locus ($$, $1); }
! 	;
! 
! /* Implement -Wparenthesis by special casing IF statement directly nested
!    within IF statement.  This requires some amount of duplication of the
!    productions under c99_block_lineno_labeled_stmt in order to work out.
!    But it's still likely more maintainable than lots of state outside the
!    parser...  */
! 
! if_statement_1:
! 	c99_block_start lineno_labels if_statement
! 		{ $$ = c_end_compound_stmt ($1, flag_isoc99); }
! 	;
! 
! if_statement_2:
! 	  c99_block_start lineno_labels ';'
! 		{ if (extra_warnings)
! 		    add_stmt (build (NOP_EXPR, NULL_TREE, NULL_TREE));
! 		  $$ = c_end_compound_stmt ($1, flag_isoc99); }
! 	| c99_block_lineno_labeled_stmt
! 	;
! 
! if_statement:
! 	  IF c99_block_start save_location '(' condition ')'
! 	    if_statement_1 ELSE if_statement_2
! 		{ c_finish_if_stmt ($3, $5, $7, $9, true);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	| IF c99_block_start save_location '(' condition ')'
! 	    if_statement_2 ELSE if_statement_2
! 		{ c_finish_if_stmt ($3, $5, $7, $9, false);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	| IF c99_block_start save_location '(' condition ')'
! 	    if_statement_1				%prec IF
! 		{ c_finish_if_stmt ($3, $5, $7, NULL, true);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	| IF c99_block_start save_location '(' condition ')'
! 	    if_statement_2				%prec IF
! 		{ c_finish_if_stmt ($3, $5, $7, NULL, false);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	;
! 
! start_break: /* empty */
! 		{ $$ = c_break_label; c_break_label = NULL; }
! 	;
! 
! start_continue: /* empty */
! 		{ $$ = c_cont_label; c_cont_label = NULL; }
! 	;
! 
! while_statement:
! 	WHILE c99_block_start save_location '(' condition ')'
! 	start_break start_continue c99_block_lineno_labeled_stmt
! 		{ c_finish_loop ($3, $5, NULL, $9, c_break_label,
! 				 c_cont_label, true);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99));
! 		  c_break_label = $7; c_cont_label = $8; }
! 	;
! 
! do_statement:
! 	DO c99_block_start save_location start_break start_continue
! 	c99_block_lineno_labeled_stmt WHILE
! 		{ $<ttype>$ = c_break_label; c_break_label = $4; }
! 		{ $<ttype>$ = c_cont_label; c_cont_label = $5; }
! 	'(' condition ')' ';'
!                 { c_finish_loop ($3, $11, NULL, $6, $<ttype>8,
! 				 $<ttype>9, false);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	;
! 
! xexpr:
! 	/* empty */
! 		{ $$ = NULL_TREE; }
! 	| expr
  	;
  
  for_init_stmt:
*************** for_init_stmt:
*** 2215,2278 ****
  		{ check_for_loop_decls (); }
  	;
  
! xexpr:
! 	/* empty */
! 		{ $$ = NULL_TREE; }
! 	| expr
  	;
  
! /* Parse a single real statement, not including any labels.  */
! stmt:
! 	  compstmt
! 		{ stmt_count++; add_stmt ($1); }
! 	| expr ';'
! 		{ stmt_count++; c_finish_expr_stmt ($1); }
! 	| c99_block_start select_or_iter_stmt
!                 { add_stmt (c_end_compound_stmt ($1, flag_isoc99)); }
  	| BREAK ';'
! 	        { stmt_count++;
! 		  if (!(c_in_iteration_stmt || c_in_case_stmt))
! 		    error ("break statement not within loop or switch");
! 		  else
! 		    add_stmt (build_break_stmt ()); }
  	| CONTINUE ';'
!                 { stmt_count++;
! 		  if (!c_in_iteration_stmt)
! 		    error ("continue statement not within a loop");
! 		  else
! 		    add_stmt (build_continue_stmt ()); }
  	| RETURN ';'
!                 { stmt_count++; c_finish_return (NULL_TREE); }
  	| RETURN expr ';'
!                 { stmt_count++; c_finish_return ($2); }
  	| asm_stmt
  	| GOTO identifier ';'
! 		{ tree decl;
! 		  stmt_count++;
! 		  decl = lookup_label ($2);
! 		  if (decl != 0)
! 		    {
! 		      TREE_USED (decl) = 1;
! 		      add_stmt (build_stmt (GOTO_EXPR, decl));
! 		    }
! 		}
  	| GOTO '*' expr ';'
! 		{ if (pedantic)
! 		    pedwarn ("ISO C forbids `goto *expr;'");
! 		  stmt_count++;
! 		  $3 = convert (ptr_type_node, $3);
! 		  add_stmt (build_stmt (GOTO_EXPR, $3)); }
  	| ';'
! 		{ }
  @@ifobjc
  	| AT_THROW expr ';'
! 		{ stmt_count++; objc_build_throw_stmt ($2); }
  	| AT_THROW ';'
! 		{ stmt_count++; objc_build_throw_stmt (NULL_TREE); }
  	| objc_try_catch_stmt
! 		{ }
! 	| AT_SYNCHRONIZED '(' expr ')' save_location compstmt
! 		{ stmt_count++; objc_build_synchronized ($5, $3, $6); }
  	;
  
  objc_catch_prefix:
--- 2186,2267 ----
  		{ check_for_loop_decls (); }
  	;
  
! for_cond_expr: save_location xexpr
! 		{ if ($2)
! 		    {
! 		      $$ = lang_hooks.truthvalue_conversion ($2);
! 		      if (EXPR_P ($$))
! 			annotate_with_locus ($$, $1);
! 		    }
! 		  else
! 		    $$ = NULL;
! 		}
  	;
  
! for_incr_expr: xexpr
! 		{ $$ = c_process_expr_stmt ($1); }
! 	;
! 
! for_statement:
! 	FOR c99_block_start '(' for_init_stmt
! 	save_location for_cond_expr ';' for_incr_expr ')'
! 	start_break start_continue c99_block_lineno_labeled_stmt
! 		{ c_finish_loop ($5, $6, $8, $12, c_break_label,
! 				 c_cont_label, true);
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99));
! 		  c_break_label = $10; c_cont_label = $11; }
! 	;
! 
! switch_statement:
! 	SWITCH c99_block_start '(' expr ')'
! 		{ $<ttype>$ = c_start_case ($4); }
! 	start_break c99_block_lineno_labeled_stmt
!                 { c_finish_case ($8);
! 		  if (c_break_label)
! 		    add_stmt (build (LABEL_EXPR, void_type_node,
! 				     c_break_label));
! 		  c_break_label = $7;
! 		  add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
! 	;
! 
! /* Parse a single real statement, not including any labels or compounds.  */
! stmt_nocomp:
! 	  expr ';'
! 		{ $$ = c_finish_expr_stmt ($1); }
! 	| if_statement
! 		{ $$ = NULL_TREE; }
! 	| while_statement
! 		{ $$ = NULL_TREE; }
! 	| do_statement
! 		{ $$ = NULL_TREE; }
! 	| for_statement
! 		{ $$ = NULL_TREE; }
! 	| switch_statement
! 		{ $$ = NULL_TREE; }
  	| BREAK ';'
! 	        { $$ = c_finish_bc_stmt (&c_break_label, true); }
  	| CONTINUE ';'
!                 { $$ = c_finish_bc_stmt (&c_cont_label, false); }
  	| RETURN ';'
!                 { $$ = c_finish_return (NULL_TREE); }
  	| RETURN expr ';'
!                 { $$ = c_finish_return ($2); }
  	| asm_stmt
  	| GOTO identifier ';'
! 		{ $$ = c_finish_goto_label ($2); }
  	| GOTO '*' expr ';'
! 		{ $$ = c_finish_goto_ptr ($3); }
  	| ';'
! 		{ $$ = NULL_TREE; }
  @@ifobjc
  	| AT_THROW expr ';'
! 		{ $$ = objc_build_throw_stmt ($2); }
  	| AT_THROW ';'
! 		{ $$ = objc_build_throw_stmt (NULL_TREE); }
  	| objc_try_catch_stmt
! 		{ $$ = NULL_TREE; }
! 	| AT_SYNCHRONIZED save_location '(' expr ')' compstmt
! 		{ objc_build_synchronized ($2, $4, $6); $$ = NULL_TREE; }
  	;
  
  objc_catch_prefix:
*************** objc_opt_catch_list:
*** 2294,2300 ****
  
  objc_try_catch_clause:
  	AT_TRY save_location compstmt
! 		{ stmt_count++; objc_begin_try_stmt ($2, $3); }
  	objc_opt_catch_list
  	;
  
--- 2283,2289 ----
  
  objc_try_catch_clause:
  	AT_TRY save_location compstmt
! 		{ objc_begin_try_stmt ($2, $3); }
  	objc_opt_catch_list
  	;
  
*************** objc_try_catch_stmt:
*** 2311,2332 ****
  @@end_ifobjc
  	;
  
  /* Any kind of label, including jump labels and case labels.
     ANSI C accepts labels only before statements, but we allow them
     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_location ':' maybe_attribute
  		{ tree label = define_label ($2, $1);
- 		  stmt_count++;
  		  if (label)
  		    {
  		      decl_attributes (&label, $4, 0);
--- 2300,2324 ----
  @@end_ifobjc
  	;
  
+ /* Parse a single or compound real statement, not including any labels.  */
+ stmt:
+ 	  compstmt
+ 		{ add_stmt ($1); $$ = NULL_TREE; }
+ 	| stmt_nocomp
+ 	;
+ 
  /* Any kind of label, including jump labels and case labels.
     ANSI C accepts labels only before statements, but we allow them
     also at the end of a compound statement.  */
  
  label:	  CASE expr_no_commas ':'
!                 { $$ = do_case ($2, NULL_TREE); }
  	| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
!                 { $$ = do_case ($2, $4); }
  	| DEFAULT ':'
!                 { $$ = do_case (NULL_TREE, NULL_TREE); }
  	| identifier save_location ':' maybe_attribute
  		{ tree label = define_label ($2, $1);
  		  if (label)
  		    {
  		      decl_attributes (&label, $4, 0);
*************** asmdef:
*** 2367,2374 ****
  asm_stmt:
  	ASM_KEYWORD maybe_volatile stop_string_translation
  	        '(' asm_argument ')' start_string_translation ';'
! 		{ stmt_count++;
! 		  $$ = build_asm_stmt ($2, $5); }
  	;
  
  asm_argument:
--- 2359,2365 ----
  asm_stmt:
  	ASM_KEYWORD maybe_volatile stop_string_translation
  	        '(' asm_argument ')' start_string_translation ';'
! 		{ $$ = build_asm_stmt ($2, $5); }
  	;
  
  asm_argument:
Index: c-semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-semantics.c,v
retrieving revision 1.88
diff -u -p -c -r1.88 c-semantics.c
*** c-semantics.c	21 Jun 2004 23:30:19 -0000	1.88
--- c-semantics.c	24 Jun 2004 22:59:14 -0000
*************** pop_stmt_list (tree t)
*** 128,134 ****
  tree
  add_stmt (tree t)
  {
!   if (EXPR_P (t) || STATEMENT_CODE_P (TREE_CODE (t)))
      {
        if (!EXPR_LOCUS (t))
  	annotate_with_locus (t, input_location);
--- 128,136 ----
  tree
  add_stmt (tree t)
  {
!   enum tree_code code = TREE_CODE (t);
! 
!   if ((EXPR_P (t) || STATEMENT_CODE_P (code)) && code != LABEL_EXPR)
      {
        if (!EXPR_LOCUS (t))
  	annotate_with_locus (t, input_location);
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.156
diff -u -p -c -r1.156 c-tree.h
*** c-tree.h	22 Jun 2004 03:06:33 -0000	1.156
--- c-tree.h	24 Jun 2004 22:59:14 -0000
*************** struct lang_type GTY(())
*** 126,138 ****
  struct language_function GTY(())
  {
    struct c_language_function base;
    int returns_value;
    int returns_null;
    int returns_abnormally;
    int warn_about_return_type;
    int extern_inline;
-   int x_in_iteration_stmt;
-   int x_in_case_stmt;
  };
  
  
--- 126,139 ----
  struct language_function GTY(())
  {
    struct c_language_function base;
+   tree x_break_label;
+   tree x_cont_label;
+   struct c_switch * GTY((skip)) x_switch_stack;
    int returns_value;
    int returns_null;
    int returns_abnormally;
    int warn_about_return_type;
    int extern_inline;
  };
  
  
*************** extern void c_parse_init (void);
*** 143,150 ****
  extern void gen_aux_info_record (tree, int, int, int);
  
  /* in c-decl.c */
! extern int c_in_iteration_stmt;
! extern int c_in_case_stmt;
  
  extern int global_bindings_p (void);
  extern void push_scope (void);
--- 144,151 ----
  extern void gen_aux_info_record (tree, int, int, int);
  
  /* in c-decl.c */
! extern tree c_break_label;
! extern tree c_cont_label;
  
  extern int global_bindings_p (void);
  extern void push_scope (void);
*************** extern bool c_warn_unused_global_decl (t
*** 212,217 ****
--- 213,219 ----
  #define c_sizeof_nowarn(T)  c_sizeof_or_alignof_type (T, SIZEOF_EXPR, 0)
  
  /* in c-typeck.c */
+ extern struct c_switch *c_switch_stack;
  
  extern tree require_complete_type (tree);
  extern int same_translation_unit_p (tree, tree);
*************** extern tree c_convert_parm_for_inlining 
*** 254,277 ****
  extern int c_types_compatible_p (tree, tree);
  extern tree c_begin_compound_stmt (bool);
  extern tree c_end_compound_stmt (tree, bool);
! extern void c_begin_if_stmt (void);
! extern void c_finish_if_cond (tree, int, int);
! extern void c_finish_then (tree);
! extern void c_begin_else (int);
! extern void c_finish_else (tree);
! extern void c_finish_if_stmt (int);
! extern tree c_begin_while_stmt (void);
! extern void c_finish_while_stmt_cond (tree, tree);
! extern void c_finish_while_stmt (tree, tree);
! extern tree c_begin_for_stmt (void);
! extern void c_finish_for_stmt_init (tree);
! extern void c_finish_for_stmt_cond (tree, tree);
! extern void c_finish_for_stmt_incr (tree, tree);
! extern void c_finish_for_stmt (tree, tree);
  extern tree c_begin_stmt_expr (void);
  extern tree c_finish_stmt_expr (tree);
! extern void c_finish_expr_stmt (tree);
! extern void c_finish_return (tree);
  extern tree build_offsetof (tree, tree);
  
  /* Set to 0 at beginning of a function definition, set to 1 if
--- 256,271 ----
  extern int c_types_compatible_p (tree, tree);
  extern tree c_begin_compound_stmt (bool);
  extern tree c_end_compound_stmt (tree, bool);
! extern void c_finish_if_stmt (location_t, tree, tree, tree, bool);
! extern void c_finish_loop (location_t, tree, tree, tree, tree, tree, bool);
  extern tree c_begin_stmt_expr (void);
  extern tree c_finish_stmt_expr (tree);
! extern tree c_process_expr_stmt (tree);
! extern tree c_finish_expr_stmt (tree);
! extern tree c_finish_return (tree);
! extern tree c_finish_bc_stmt (tree *, bool);
! extern tree c_finish_goto_label (tree);
! extern tree c_finish_goto_ptr (tree);
  extern tree build_offsetof (tree, tree);
  
  /* Set to 0 at beginning of a function definition, set to 1 if
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.330
diff -u -p -c -r1.330 c-typeck.c
*** c-typeck.c	24 Jun 2004 05:26:01 -0000	1.330
--- c-typeck.c	24 Jun 2004 22:59:17 -0000
*************** c_expand_asm_operands (tree string, tree
*** 6249,6258 ****
    emit_queue ();
  }
  
  /* Generate a C `return' statement.  RETVAL is the expression for what
     to return, or a null pointer for `return;' with no value.  */
  
! void
  c_finish_return (tree retval)
  {
    tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
--- 6249,6282 ----
    emit_queue ();
  }
  
+ /* Generate a goto statement to LABEL.  */
+ 
+ tree
+ c_finish_goto_label (tree label)
+ {
+   tree decl = lookup_label (label);
+   if (!decl)
+     return NULL_TREE;
+ 
+   TREE_USED (decl) = 1;
+   return add_stmt (build (GOTO_EXPR, void_type_node, decl));
+ }
+ 
+ /* Generate a computed goto statement to EXPR.  */
+ 
+ tree
+ c_finish_goto_ptr (tree expr)
+ {
+   if (pedantic)
+     pedwarn ("ISO C forbids `goto *expr;'");
+   expr = convert (ptr_type_node, expr);
+   return add_stmt (build (GOTO_EXPR, void_type_node, expr));
+ }
+ 
  /* Generate a C `return' statement.  RETVAL is the expression for what
     to return, or a null pointer for `return;' with no value.  */
  
! tree
  c_finish_return (tree retval)
  {
    tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
*************** c_finish_return (tree retval)
*** 6282,6288 ****
  
        current_function_returns_value = 1;
        if (t == error_mark_node)
! 	return;
  
        inner = t = convert (TREE_TYPE (res), t);
  
--- 6306,6312 ----
  
        current_function_returns_value = 1;
        if (t == error_mark_node)
! 	return NULL_TREE;
  
        inner = t = convert (TREE_TYPE (res), t);
  
*************** c_finish_return (tree retval)
*** 6340,6346 ****
        retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
      }
  
!   add_stmt (build_stmt (RETURN_EXPR, retval));
  }
  
  struct c_switch {
--- 6364,6370 ----
        retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
      }
  
!   return add_stmt (build_stmt (RETURN_EXPR, retval));
  }
  
  struct c_switch {
*************** struct c_switch {
*** 6362,6368 ****
     during the processing of the body of a function, and we never
     collect at that point.  */
  
! static struct c_switch *switch_stack;
  
  /* Start a C switch statement, testing expression EXP.  Return the new
     SWITCH_STMT.  */
--- 6386,6392 ----
     during the processing of the body of a function, and we never
     collect at that point.  */
  
! struct c_switch *c_switch_stack;
  
  /* Start a C switch statement, testing expression EXP.  Return the new
     SWITCH_STMT.  */
*************** c_start_case (tree exp)
*** 6403,6412 ****
    cs = xmalloc (sizeof (*cs));
    cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
    cs->cases = splay_tree_new (case_compare, NULL, NULL);
!   cs->next = switch_stack;
!   switch_stack = cs;
  
!   return add_stmt (switch_stack->switch_stmt);
  }
  
  /* Process a case label.  */
--- 6427,6436 ----
    cs = xmalloc (sizeof (*cs));
    cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
    cs->cases = splay_tree_new (case_compare, NULL, NULL);
!   cs->next = c_switch_stack;
!   c_switch_stack = cs;
  
!   return add_stmt (cs->switch_stmt);
  }
  
  /* Process a case label.  */
*************** do_case (tree low_value, tree high_value
*** 6416,6425 ****
  {
    tree label = NULL_TREE;
  
!   if (switch_stack)
      {
!       label = c_add_case_label (switch_stack->cases,
! 				SWITCH_COND (switch_stack->switch_stmt),
  				low_value, high_value);
        if (label == error_mark_node)
  	label = NULL_TREE;
--- 6440,6449 ----
  {
    tree label = NULL_TREE;
  
!   if (c_switch_stack)
      {
!       label = c_add_case_label (c_switch_stack->cases,
! 				SWITCH_COND (c_switch_stack->switch_stmt),
  				low_value, high_value);
        if (label == error_mark_node)
  	label = NULL_TREE;
*************** do_case (tree low_value, tree high_value
*** 6437,6443 ****
  void
  c_finish_case (tree body)
  {
!   struct c_switch *cs = switch_stack;
  
    SWITCH_BODY (cs->switch_stmt) = body;
  
--- 6461,6467 ----
  void
  c_finish_case (tree body)
  {
!   struct c_switch *cs = c_switch_stack;
  
    SWITCH_BODY (cs->switch_stmt) = body;
  
*************** c_finish_case (tree body)
*** 6445,6650 ****
    c_do_switch_warnings (cs->cases, cs->switch_stmt);
  
    /* Pop the stack.  */
!   switch_stack = switch_stack->next;
    splay_tree_delete (cs->cases);
    free (cs);
  }
  
! /* Keep a stack of if statements.  We record the number of compound
!    statements seen up to the if keyword, as well as the line number
!    and file of the if.  If a potentially ambiguous else is seen, that
!    fact is recorded; the warning is issued when we can be sure that
!    the enclosing if statement does not have an else branch.  */
! typedef struct
! {
!   tree if_stmt;
!   location_t empty_locus;
!   int compstmt_count;
!   int stmt_count;
!   unsigned int needs_warning : 1;
!   unsigned int saw_else : 1;
! } if_elt;
! 
! static if_elt *if_stack;
! 
! /* Amount of space in the if statement stack.  */
! static int if_stack_space = 0;
! 
! /* Stack pointer.  */
! static int if_stack_pointer = 0;
! 
! /* Begin an if-statement.  */
  
  void
! c_begin_if_stmt (void)
  {
!   tree r;
!   if_elt *elt;
  
!   /* Make sure there is enough space on the stack.  */
!   if (if_stack_space == 0)
      {
!       if_stack_space = 10;
!       if_stack = xmalloc (10 * sizeof (if_elt));
      }
!   else if (if_stack_space == if_stack_pointer)
      {
!       if_stack_space += 10;
!       if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
      }
  
!   r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE));
! 
!   /* Record this if statement.  */
!   elt = &if_stack[if_stack_pointer++];
!   memset (elt, 0, sizeof (*elt));
!   elt->if_stmt = r;
! }
! 
! /* Record the start of an if-then, and record the start of it
!    for ambiguous else detection.
! 
!    COND is the condition for the if-then statement.
! 
!    IF_STMT is the statement node that has already been created for
!    this if-then statement.  It is created before parsing the
!    condition to keep line number information accurate.  */
! 
! void
! c_finish_if_cond (tree cond, int compstmt_count, int stmt_count)
! {
!   if_elt *elt = &if_stack[if_stack_pointer - 1];
!   elt->compstmt_count = compstmt_count;
!   elt->stmt_count = stmt_count;
!   COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond);
! }
! 
! /* Called after the then-clause for an if-statement is processed.  */
! 
! void
! c_finish_then (tree then_stmt)
! {
!   if_elt *elt = &if_stack[if_stack_pointer - 1];
!   COND_EXPR_THEN (elt->if_stmt) = then_stmt;
!   elt->empty_locus = input_location;
! }
! 
! /* Called between the then-clause and the else-clause
!    of an if-then-else.  */
! 
! void
! c_begin_else (int stmt_count)
! {
!   if_elt *elt = &if_stack[if_stack_pointer - 1];
! 
!   /* An ambiguous else warning must be generated for the enclosing if
!      statement, unless we see an else branch for that one, too.  */
!   if (warn_parentheses
!       && if_stack_pointer > 1
!       && (elt[0].compstmt_count == elt[-1].compstmt_count))
!     elt[-1].needs_warning = 1;
! 
!   /* Even if a nested if statement had an else branch, it can't be
!      ambiguous if this one also has an else.  So don't warn in that
!      case.  Also don't warn for any if statements nested in this else.  */
!   elt->needs_warning = 0;
!   elt->compstmt_count--;
!   elt->saw_else = 1;
!   elt->stmt_count = stmt_count;
! }
! 
! /* Called after the else-clause for an if-statement is processed.  */
! 
! void
! c_finish_else (tree else_stmt)
! {
!   if_elt *elt = &if_stack[if_stack_pointer - 1];
!   COND_EXPR_ELSE (elt->if_stmt) = else_stmt;
!   elt->empty_locus = input_location;
  }
  
! /* Record the end of an if-then.  Optionally warn if a nested
!    if statement had an ambiguous else clause.  */
  
  void
! c_finish_if_stmt (int stmt_count)
  {
!   if_elt *elt = &if_stack[--if_stack_pointer];
  
!   if (elt->needs_warning)
!     warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
! 	     EXPR_LOCUS (elt->if_stmt));
  
!   if (extra_warnings && stmt_count == elt->stmt_count)
      {
!       if (elt->saw_else)
! 	warning ("%Hempty body in an else-statement", &elt->empty_locus);
!       else
! 	warning ("%Hempty body in an if-statement", &elt->empty_locus);
      }
  }
- 
- /* Begin a while statement.  Returns a newly created WHILE_STMT if
-    appropriate.  */
  
  tree
! c_begin_while_stmt (void)
! {
!   tree r;
!   r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
!   return r;
! }
! 
! void
! c_finish_while_stmt_cond (tree cond, tree while_stmt)
  {
!   WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
! }
  
! void
! c_finish_while_stmt (tree body, tree while_stmt)
! {
!   WHILE_BODY (while_stmt) = body;
! }
! 
! /* Create a for statement.  */
! 
! tree
! c_begin_for_stmt (void)
! {
!   tree r;
!   r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
! 			    NULL_TREE, NULL_TREE));
!   FOR_INIT_STMT (r) = push_stmt_list ();
!   return r;
! }
! 
! void
! c_finish_for_stmt_init (tree for_stmt)
! {
!   FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
! }
! 
! void
! c_finish_for_stmt_cond (tree cond, tree for_stmt)
! {
!   if (cond)
!     FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
! }
  
! void
! c_finish_for_stmt_incr (tree expr, tree for_stmt)
! {
!   FOR_EXPR (for_stmt) = expr;
  }
  
! void
! c_finish_for_stmt (tree body, tree for_stmt)
! {
!   FOR_BODY (for_stmt) = body;
! }
! 
! /* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr.  */
  
  static void
  emit_side_effect_warnings (tree expr)
--- 6469,6639 ----
    c_do_switch_warnings (cs->cases, cs->switch_stmt);
  
    /* Pop the stack.  */
!   c_switch_stack = cs->next;
    splay_tree_delete (cs->cases);
    free (cs);
  }
  
! /* Emit an if statement.  IF_LOCUS is the location of the 'if'.  COND,
!    THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK
!    may be null.  NESTED_IF is true if THEN_BLOCK contains another IF
!    statement, and was not surrounded with parenthesis.  */
  
  void
! c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
! 		  tree else_block, bool nested_if)
  {
!   tree stmt;
  
!   /* Diagnose an ambiguous else if if-then-else is nested inside if-then.  */
!   if (warn_parentheses && nested_if && else_block == NULL)
      {
!       tree inner_if = then_block;
! 
!       /* We know from the grammer productions that there is an IF nested
! 	 within THEN_BLOCK.  Due to labels and c99 conditional declarations,
! 	 it might not be exactly THEN_BLOCK, but should be the last
! 	 non-container statement within.  */
!       while (1)
! 	switch (TREE_CODE (inner_if))
! 	  {
! 	  case COND_EXPR:
! 	    goto found;
! 	  case BIND_EXPR:
! 	    inner_if = BIND_EXPR_BODY (inner_if);
! 	    break;
! 	  case STATEMENT_LIST:
! 	    inner_if = expr_last (then_block);
! 	    break;
! 	  case TRY_FINALLY_EXPR:
! 	  case TRY_CATCH_EXPR:
! 	    inner_if = TREE_OPERAND (inner_if, 0);
! 	    break;
! 	  default:
! 	    abort ();
! 	  }
!     found:
! 
!       if (COND_EXPR_ELSE (inner_if))
! 	 warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
! 		  &if_locus);
      }
! 
!   /* Diagnose ";" via the special empty statement node that we create.  */
!   if (extra_warnings)
      {
!       if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
! 	{
! 	  if (!else_block)
! 	    warning ("%Hempty body in an if-statement",
! 		     EXPR_LOCUS (then_block));
! 	  then_block = alloc_stmt_list ();
! 	}
!       if (else_block
! 	  && TREE_CODE (else_block) == NOP_EXPR
! 	  && !TREE_TYPE (else_block))
! 	{
! 	  warning ("%Hempty body in an else-statement",
! 		   EXPR_LOCUS (else_block));
! 	  else_block = alloc_stmt_list ();
! 	}
      }
  
!   stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
!   annotate_with_locus (stmt, if_locus);
!   add_stmt (stmt);
  }
  
! /* Emit a general-purpose loop construct.  START_LOCUS is the location of
!    the beginning of the loop.  COND is the loop condition.  COND_IS_FIRST
!    is false for DO loops.  INCR is the FOR increment expression.  BODY is
!    the statement controled by the loop.  BLAB is the break label.  CLAB is
!    the continue label.  Everything is allowed to be NULL.  */
  
  void
! c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
! 	       tree blab, tree clab, bool cond_is_first)
  {
!   tree entry = NULL, exit = NULL, t;
  
!   /* Force zeros to NULL so that we don't test them.  */
!   if (cond && integer_zerop (cond))
!     cond = NULL;
  
!   /* Detect do { ... } while (0) and don't generate loop construct.  */
!   if (cond_is_first || cond)
      {
!       tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
!  
!       /* If we have an exit condition, then we build an IF with gotos either
!          out of the loop, or to the top of it.  If there's no exit condition,
!          then we just build a jump back to the top.  */
!       exit = build_and_jump (&LABEL_EXPR_LABEL (top));
!  
!       if (cond)
!         {
!           /* Canonicalize the loop condition to the end.  This means
!              generating a branch to the loop condition.  Reuse the
!              continue label, if possible.  */
!           if (cond_is_first)
!             {
!               if (incr || !clab)
!                 {
!                   entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
!                   t = build_and_jump (&LABEL_EXPR_LABEL (entry));
!                 }
!               else
!                 t = build1 (GOTO_EXPR, void_type_node, clab);
! 	      annotate_with_locus (t, start_locus);
!               add_stmt (t);
!             }
!  
! 	  t = build_and_jump (&blab);
!           exit = build (COND_EXPR, void_type_node, cond, exit, t);
!           exit = fold (exit);
! 	  if (cond_is_first)
!             annotate_with_locus (exit, start_locus);
! 	  else
!             annotate_with_locus (exit, input_location);
!         }
!  
!       add_stmt (top);
      }
+  
+   if (body)
+     add_stmt (body);
+   if (clab)
+     add_stmt (build1 (LABEL_EXPR, void_type_node, clab));
+   if (incr)
+     add_stmt (incr);
+   if (entry)
+     add_stmt (entry);
+   if (exit)
+     add_stmt (exit);
+   if (blab)
+     add_stmt (build1 (LABEL_EXPR, void_type_node, blab));
  }
  
  tree
! c_finish_bc_stmt (tree *label_p, bool is_break)
  {
!   tree label = *label_p;
  
!   if (!label)
!     *label_p = label = create_artificial_label ();
!   else if (TREE_CODE (label) != LABEL_DECL)
!     {
!       if (is_break)
! 	error ("break statement not within loop or switch");
!       else
!         error ("continue statement not within a loop");
!       return NULL_TREE;
!     }
  
!   return add_stmt (build (GOTO_EXPR, void_type_node, label));
  }
  
! /* A helper routine for c_process_expr_stmt and c_finish_stmt_expr.  */
  
  static void
  emit_side_effect_warnings (tree expr)
*************** emit_side_effect_warnings (tree expr)
*** 6661,6673 ****
      warn_if_unused_value (expr, input_location);
  }
  
! /* Emit an expression as a statement.  */
  
! void
! c_finish_expr_stmt (tree expr)
  {
    if (!expr)
!     return;
  
    /* Do default conversion if safe and possibly important,
       in case within ({...}).  */
--- 6650,6663 ----
      warn_if_unused_value (expr, input_location);
  }
  
! /* Process an expression as if it were a complete statement.  Emit
!    diagnostics, but do not call ADD_STMT.  */
  
! tree
! c_process_expr_stmt (tree expr)
  {
    if (!expr)
!     return NULL_TREE;
  
    /* Do default conversion if safe and possibly important,
       in case within ({...}).  */
*************** c_finish_expr_stmt (tree expr)
*** 6696,6702 ****
    if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
      expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
  
!   add_stmt (expr);
  }
  
  /* Do the opposite and emit a statement as an expression.  To begin,
--- 6686,6706 ----
    if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
      expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
  
!   if (EXPR_P (expr))
!     annotate_with_locus (expr, input_location);
! 
!   return expr;
! }
! 
! /* Emit an expression as a statement.  */
! 
! tree
! c_finish_expr_stmt (tree expr)
! {
!   if (expr)
!     return add_stmt (c_process_expr_stmt (expr));
!   else
!     return NULL;
  }
  
  /* Do the opposite and emit a statement as an expression.  To begin,
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.25
diff -u -p -c -r2.25 gimplify.c
*** gimplify.c	24 Jun 2004 16:25:17 -0000	2.25
--- gimplify.c	24 Jun 2004 22:59:18 -0000
*************** static enum gimplify_status
*** 2511,2522 ****
  gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
  {
    tree expr = *expr_p;
!   tree tmp;
    enum gimplify_status ret;
  
    /* If this COND_EXPR has a value, copy the values into a temporary within
       the arms.  */
!   if (! VOID_TYPE_P (TREE_TYPE (expr)))
      {
        if (target)
  	{
--- 2511,2526 ----
  gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
  {
    tree expr = *expr_p;
!   tree tmp, type;
    enum gimplify_status ret;
  
+   type = TREE_TYPE (expr);
+   if (!type)
+     TREE_TYPE (expr) = void_type_node;
+ 
    /* If this COND_EXPR has a value, copy the values into a temporary within
       the arms.  */
!   else if (! VOID_TYPE_P (type))
      {
        if (target)
  	{
Index: tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.7
diff -u -p -c -r2.7 tree-gimple.c
*** tree-gimple.c	23 Jun 2004 00:25:54 -0000	2.7
--- tree-gimple.c	24 Jun 2004 22:59:18 -0000
*************** is_gimple_stmt (tree t)
*** 348,354 ****
      case BIND_EXPR:
      case COND_EXPR:
        /* These are only valid if they're void.  */
!       return VOID_TYPE_P (TREE_TYPE (t));
  
      case SWITCH_EXPR:
      case GOTO_EXPR:
--- 348,354 ----
      case BIND_EXPR:
      case COND_EXPR:
        /* These are only valid if they're void.  */
!       return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t));
  
      case SWITCH_EXPR:
      case GOTO_EXPR:
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.12
diff -u -p -c -r2.12 tree-pretty-print.c
*** tree-pretty-print.c	23 Jun 2004 20:12:43 -0000	2.12
--- tree-pretty-print.c	24 Jun 2004 22:59:19 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 765,771 ****
        break;
  
      case COND_EXPR:
!       if (TREE_TYPE (node) == void_type_node)
  	{
  	  pp_string (buffer, "if (");
  	  dump_generic_node (buffer, COND_EXPR_COND (node), spc, flags, false);
--- 765,771 ----
        break;
  
      case COND_EXPR:
!       if (TREE_TYPE (node) == NULL || TREE_TYPE (node) == void_type_node)
  	{
  	  pp_string (buffer, "if (");
  	  dump_generic_node (buffer, COND_EXPR_COND (node), spc, flags, false);
*************** print_struct_decl (pretty_printer *buffe
*** 1541,1550 ****
  	    print_declaration (buffer, tmp, spc+2, flags);
  	    pp_newline (buffer);
  	  }
- 	else
- 	  {
- 
- 	  }
  	tmp = TREE_CHAIN (tmp);
        }
    }
--- 1541,1546 ----
Index: objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.226
diff -u -p -c -r1.226 objc-act.c
*** objc/objc-act.c	23 Jun 2004 00:26:01 -0000	1.226
--- objc/objc-act.c	24 Jun 2004 22:59:24 -0000
*************** objc_finish_try_stmt (void)
*** 3188,3197 ****
    free (c);
  }
  
! void
  objc_build_throw_stmt (tree throw_expr)
  {
!   tree func_params;
  
    if (throw_expr == NULL)
      {
--- 3188,3199 ----
    free (c);
  }
  
! tree
  objc_build_throw_stmt (tree throw_expr)
  {
!   tree args;
! 
!   objc_init_exceptions ();
  
    if (throw_expr == NULL)
      {
*************** objc_build_throw_stmt (tree throw_expr)
*** 3201,3207 ****
            || cur_try_context->current_catch == NULL)
  	{
  	  error ("%<@throw%> (rethrow) used outside of a @catch block");
! 	  return;
  	}
  
        /* Otherwise the object is still sitting in the EXC_PTR_EXPR
--- 3203,3209 ----
            || cur_try_context->current_catch == NULL)
  	{
  	  error ("%<@throw%> (rethrow) used outside of a @catch block");
! 	  return NULL_TREE;
  	}
  
        /* Otherwise the object is still sitting in the EXC_PTR_EXPR
*************** objc_build_throw_stmt (tree throw_expr)
*** 3211,3220 ****
  
    /* A throw is just a call to the runtime throw function with the
       object as a parameter.  */
!   func_params = tree_cons (NULL, throw_expr, NULL);
!   add_stmt (build_function_call (objc_exception_throw_decl, func_params));
! 
!   objc_init_exceptions ();
  }
  
  void
--- 3213,3220 ----
  
    /* A throw is just a call to the runtime throw function with the
       object as a parameter.  */
!   args = tree_cons (NULL, throw_expr, NULL);
!   return add_stmt (build_function_call (objc_exception_throw_decl, args));
  }
  
  void
Index: objc/objc-act.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.24
diff -u -p -c -r1.24 objc-act.h
*** objc/objc-act.h	21 Jun 2004 01:50:18 -0000	1.24
--- objc/objc-act.h	24 Jun 2004 22:59:24 -0000
*************** void finish_method_def (void);
*** 39,45 ****
  tree start_protocol (enum tree_code, tree, tree);
  void finish_protocol (tree);
  
! void objc_build_throw_stmt (tree);
  void objc_begin_try_stmt (location_t, tree);
  void objc_begin_catch_clause (tree);
  void objc_finish_catch_clause (void);
--- 39,45 ----
  tree start_protocol (enum tree_code, tree, tree);
  void finish_protocol (tree);
  
! tree objc_build_throw_stmt (tree);
  void objc_begin_try_stmt (location_t, tree);
  void objc_begin_catch_clause (tree);
  void objc_finish_catch_clause (void);


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