OSDN Git Service

bf85f7fcc138b7778e8b37443d27a148391050ae
[pf3gnuchains/gcc-fork.git] / gcc / c-semantics.c
1 /* This file contains the definitions and documentation for the common
2    tree codes used in the GNU C and C++ compilers (see c-common.def
3    for the standard codes).  
4    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
5    Written by Benjamin Chelf (chelf@codesourcery.com).
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 #include "config.h"
25 #include "system.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "splay-tree.h"
29 #include "varray.h"
30 #include "c-common.h"
31 #include "except.h"
32 #include "toplev.h"
33 #include "flags.h"
34 #include "ggc.h"
35 #include "rtl.h"
36 #include "output.h"
37 #include "timevar.h"
38
39 /* If non-NULL, the address of a language-specific function for
40    expanding statements.  */
41 void (*lang_expand_stmt) PARAMS ((tree));
42
43 /* If non-NULL, the address of a language-specific function for
44    expanding a DECL_STMT.  After the language-independent cases are
45    handled, this function will be called.  If this function is not
46    defined, it is assumed that declarations other than those for
47    variables and labels do not require any RTL generation.  */
48 void (*lang_expand_decl_stmt) PARAMS ((tree));
49
50 static tree prune_unused_decls PARAMS ((tree *, int *, void *));
51
52 /* Create an empty statement tree rooted at T.  */
53
54 void
55 begin_stmt_tree (t)
56      tree *t;
57 {
58   /* We create a trivial EXPR_STMT so that last_tree is never NULL in
59      what follows.  We remove the extraneous statement in
60      finish_stmt_tree.  */
61   *t = build_nt (EXPR_STMT, void_zero_node);
62   last_tree = *t;
63   last_expr_type = NULL_TREE;
64 }
65
66 /* T is a statement.  Add it to the statement-tree.  */
67
68 tree
69 add_stmt (t)
70      tree t;
71 {
72   /* Add T to the statement-tree.  */
73   TREE_CHAIN (last_tree) = t;
74   last_tree = t;
75   /* When we expand a statement-tree, we must know whether or not the
76      statements are full-expresions.  We record that fact here.  */
77   STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
78   return t;
79 }
80
81 /* Create a declaration statement for the declaration given by the
82    DECL.  */
83
84 void
85 add_decl_stmt (decl)
86      tree decl;
87 {
88   tree decl_stmt;
89
90   /* We need the type to last until instantiation time.  */
91   decl_stmt = build_stmt (DECL_STMT, decl);
92   add_stmt (decl_stmt); 
93 }
94
95 /* Add a scope-statement to the statement-tree.  BEGIN_P indicates
96    whether this statements opens or closes a scope.  PARTIAL_P is true
97    for a partial scope, i.e, the scope that begins after a label when
98    an object that needs a cleanup is created.  If BEGIN_P is nonzero,
99    returns a new TREE_LIST representing the top of the SCOPE_STMT
100    stack.  The TREE_PURPOSE is the new SCOPE_STMT.  If BEGIN_P is
101    zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
102    and whose TREE_PURPOSE is the matching SCOPE_STMT iwth
103    SCOPE_BEGIN_P set.  */
104
105 tree
106 add_scope_stmt (begin_p, partial_p)
107      int begin_p;
108      int partial_p;
109 {
110   tree ss;
111   tree top;
112
113   /* Build the statement.  */
114   ss = build_stmt (SCOPE_STMT, NULL_TREE);
115   SCOPE_BEGIN_P (ss) = begin_p;
116   SCOPE_PARTIAL_P (ss) = partial_p;
117
118   /* Keep the scope stack up to date.  */
119   if (begin_p)
120     {
121       *current_scope_stmt_stack () 
122         = tree_cons (ss, NULL_TREE, *current_scope_stmt_stack ());
123       top = *current_scope_stmt_stack ();
124     }
125   else
126     {
127       top = *current_scope_stmt_stack ();
128       TREE_VALUE (top) = ss;
129       *current_scope_stmt_stack () = TREE_CHAIN (top);
130     }
131
132   /* Add the new statement to the statement-tree.  */
133   add_stmt (ss);
134
135   return top;
136 }
137
138 /* Remove declarations of internal variables that are not used from a
139    stmt tree.  To qualify, the variable must have a name and must have
140    a zero DECL_SOURCE_LINE.  We tried to remove all variables for
141    which TREE_USED was false, but it turns out that there's tons of
142    variables for which TREE_USED is false but that are still in fact
143    used.  */
144
145 static tree
146 prune_unused_decls (tp, walk_subtrees, data)
147      tree *tp;
148      int *walk_subtrees ATTRIBUTE_UNUSED;
149      void *data ATTRIBUTE_UNUSED;
150 {
151   tree t = *tp;
152
153   if (t == NULL_TREE)
154     return (tree) 1;
155
156   if (TREE_CODE (t) == DECL_STMT)
157     {
158       tree d = DECL_STMT_DECL (t);
159       if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
160         {
161           *tp = TREE_CHAIN (t);
162           /* Recurse on the new value of tp, otherwise we will skip
163              the next statement.  */
164           return prune_unused_decls (tp, walk_subtrees, data);
165         }
166     }
167   else if (TREE_CODE (t) == SCOPE_STMT)
168     {
169       /* Remove all unused decls from the BLOCK of this SCOPE_STMT.  */
170       tree block = SCOPE_STMT_BLOCK (t);
171
172       if (block)
173         {
174           tree *vp;
175
176           for (vp = &BLOCK_VARS (block); *vp; )
177             {
178               tree v = *vp;
179               if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
180                 *vp = TREE_CHAIN (v);  /* drop */
181               else
182                 vp = &TREE_CHAIN (v);  /* advance */
183             }
184           /* If there are now no variables, the entire BLOCK can be dropped.
185              (This causes SCOPE_NULLIFIED_P (t) to be true.)  */
186           if (BLOCK_VARS (block) == NULL_TREE)
187             SCOPE_STMT_BLOCK (t) = NULL_TREE;
188         }
189     }
190   return NULL_TREE;
191 }
192
193 /* Finish the statement tree rooted at T.  */
194
195 void
196 finish_stmt_tree (t)
197      tree *t;
198 {
199   tree stmt;
200   
201   /* Remove the fake extra statement added in begin_stmt_tree.  */
202   stmt = TREE_CHAIN (*t);
203   *t = stmt;
204   last_tree = NULL_TREE;
205
206   /* Remove unused decls from the stmt tree.  */
207   walk_stmt_tree (t, prune_unused_decls, NULL);
208
209   if (cfun && stmt)
210     {
211       /* The line-number recorded in the outermost statement in a function
212          is the line number of the end of the function.  */
213       STMT_LINENO (stmt) = lineno;
214       STMT_LINENO_FOR_FN_P (stmt) = 1;
215     }
216 }
217
218 /* Build a generic statement based on the given type of node and
219    arguments. Similar to `build_nt', except that we set
220    STMT_LINENO to be the current line number.  */
221 /* ??? This should be obsolete with the lineno_stmt productions
222    in the grammar.  */
223
224 tree
225 build_stmt VPARAMS ((enum tree_code code, ...))
226 {
227 #ifndef ANSI_PROTOTYPES
228   enum tree_code code;
229 #endif
230   va_list p;
231   register tree t;
232   register int length;
233   register int i;
234
235   VA_START (p, code);
236
237 #ifndef ANSI_PROTOTYPES
238   code = va_arg (p, enum tree_code);
239 #endif
240
241   t = make_node (code);
242   length = TREE_CODE_LENGTH (code);
243   STMT_LINENO (t) = lineno;
244
245   for (i = 0; i < length; i++)
246     TREE_OPERAND (t, i) = va_arg (p, tree);
247
248   va_end (p);
249   return t;
250 }
251
252 /* Some statements, like for-statements or if-statements, require a
253    condition.  This condition can be a declaration.  If T is such a
254    declaration it is processed, and an expression appropriate to use
255    as the condition is returned.  Otherwise, T itself is returned.  */
256
257 tree
258 expand_cond (t)
259      tree t;
260 {
261   if (t && TREE_CODE (t) == TREE_LIST)
262     {
263       expand_stmt (TREE_PURPOSE (t));
264       return TREE_VALUE (t);
265     }
266   else 
267     return t;
268 }
269
270 /* Create RTL for the local static variable DECL.  */
271
272 void
273 make_rtl_for_local_static (decl)
274      tree decl;
275 {
276   const char *asmspec = NULL;
277
278   /* If we inlined this variable, we could see it's declaration
279      again.  */
280   if (TREE_ASM_WRITTEN (decl))
281     return;
282
283   /* If the DECL_ASSEMBLER_NAME is not the same as the DECL_NAME, then
284      either we already created RTL for this DECL (and since it was a
285      local variable, its DECL_ASSEMBLER_NAME got hacked up to prevent
286      clashes with other local statics with the same name by a previous
287      call to make_decl_rtl), or the user explicitly requested a
288      particular assembly name for this variable, using the GNU
289      extension for this purpose:
290
291        int i asm ("j");
292
293      There's no way to know which case we're in, here.  But, it turns
294      out we're safe.  If there's already RTL, then
295      rest_of_decl_compilation ignores the ASMSPEC parameter, so we
296      may as well not pass it in.  If there isn't RTL, then we didn't
297      already create RTL, which means that the modification to
298      DECL_ASSEMBLER_NAME came only via the explicit extension.  */
299   if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
300       && !DECL_RTL (decl))
301     asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
302
303   rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0);
304 }
305
306 /* Let the back-end know about DECL.  */
307
308 void
309 emit_local_var (decl)
310      tree decl;
311 {
312   /* Create RTL for this variable.  */
313   if (!DECL_RTL (decl))
314     {
315       if (DECL_C_HARD_REGISTER (decl))
316         /* The user specified an assembler name for this variable.
317            Set that up now.  */
318         rest_of_decl_compilation
319           (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
320            /*top_level=*/0, /*at_end=*/0);
321       else
322         expand_decl (decl);
323     }
324
325   /* Actually do the initialization.  */
326   if (stmts_are_full_exprs_p ())
327     expand_start_target_temps ();
328
329   expand_decl_init (decl);
330
331   if (stmts_are_full_exprs_p ())
332     expand_end_target_temps ();
333 }
334
335 /* Helper for generating the RTL at the beginning of a scope. */
336
337 void
338 genrtl_do_pushlevel ()
339 {
340   emit_line_note (input_filename, lineno);
341   clear_last_expr ();
342 }
343
344 /* Generate the RTL for DESTINATION, which is a GOTO_STMT. */
345
346 void
347 genrtl_goto_stmt (destination)
348      tree destination;
349 {
350   if (TREE_CODE (destination) == IDENTIFIER_NODE)
351     abort ();
352   
353   /* We warn about unused labels with -Wunused.  That means we have to
354      mark the used labels as used.  */
355   if (TREE_CODE (destination) == LABEL_DECL)
356     TREE_USED (destination) = 1;
357   
358   emit_line_note (input_filename, lineno);
359   
360   if (TREE_CODE (destination) == LABEL_DECL)
361     {
362       label_rtx (destination);
363       expand_goto (destination); 
364     }
365   else
366     expand_computed_goto (destination);
367 }
368
369 /* Generate the RTL for EXPR, which is an EXPR_STMT. */
370
371 void 
372 genrtl_expr_stmt (expr)
373      tree expr;
374 {
375   if (expr != NULL_TREE)
376     {
377       emit_line_note (input_filename, lineno);
378       
379       if (stmts_are_full_exprs_p ())
380         expand_start_target_temps ();
381       
382       if (expr != error_mark_node)
383         expand_expr_stmt (expr);
384       
385       if (stmts_are_full_exprs_p ())
386         expand_end_target_temps ();
387     }
388 }
389
390 /* Generate the RTL for T, which is a DECL_STMT. */
391
392 void
393 genrtl_decl_stmt (t)
394      tree t;
395 {
396   tree decl;
397   emit_line_note (input_filename, lineno);
398   decl = DECL_STMT_DECL (t);
399   /* If this is a declaration for an automatic local
400      variable, initialize it.  Note that we might also see a
401      declaration for a namespace-scope object (declared with
402      `extern').  We don't have to handle the initialization
403      of those objects here; they can only be declarations,
404      rather than definitions.  */
405   if (TREE_CODE (decl) == VAR_DECL 
406       && !TREE_STATIC (decl)
407       && !DECL_EXTERNAL (decl))
408     {
409       /* Let the back-end know about this variable.  */
410       if (!anon_aggr_type_p (TREE_TYPE (decl)))
411         emit_local_var (decl);
412       else
413         expand_anon_union_decl (decl, NULL_TREE, 
414                                 DECL_ANON_UNION_ELEMS (decl));
415     }
416   else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
417     {
418       if (DECL_ARTIFICIAL (decl) && ! TREE_USED (decl))
419         /* Do not emit unused decls. This is not just an
420            optimization. We really do not want to emit
421            __PRETTY_FUNCTION__ etc, if they're never used.  */
422         DECL_IGNORED_P (decl) = 1;
423       else
424         make_rtl_for_local_static (decl);
425     }
426   else if (TREE_CODE (decl) == LABEL_DECL 
427            && C_DECLARED_LABEL_FLAG (decl))
428     declare_nonlocal_label (decl);
429   else if (lang_expand_decl_stmt)
430     (*lang_expand_decl_stmt) (t);
431 }
432
433 /* Generate the RTL for T, which is an IF_STMT. */
434
435 void
436 genrtl_if_stmt (t)
437      tree t;
438 {
439   tree cond;
440   genrtl_do_pushlevel ();
441   cond = expand_cond (IF_COND (t));
442   emit_line_note (input_filename, lineno);
443   expand_start_cond (cond, 0);
444   if (THEN_CLAUSE (t))
445     expand_stmt (THEN_CLAUSE (t));
446   if (ELSE_CLAUSE (t))
447     {
448       expand_start_else ();
449       expand_stmt (ELSE_CLAUSE (t));
450     }
451   expand_end_cond ();
452 }
453
454 /* Generate the RTL for T, which is a WHILE_STMT. */
455
456 void
457 genrtl_while_stmt (t)
458      tree t;
459 {
460   tree cond;
461   emit_nop ();
462   emit_line_note (input_filename, lineno);
463   expand_start_loop (1); 
464   genrtl_do_pushlevel ();
465
466   cond = expand_cond (WHILE_COND (t));
467   emit_line_note (input_filename, lineno);
468   expand_exit_loop_if_false (0, cond);
469   genrtl_do_pushlevel ();
470   
471   expand_stmt (WHILE_BODY (t));
472
473   expand_end_loop ();
474 }
475
476 /* Generate the RTL for T, which is a DO_STMT. */
477
478 void
479 genrtl_do_stmt (t)
480      tree t;
481 {
482   tree cond = DO_COND (t);
483
484   /* Recognize the common special-case of do { ... } while (0) and do
485      not emit the loop widgetry in this case.  In particular this
486      avoids cluttering the rtl with dummy loop notes, which can affect
487      alignment of adjacent labels.  */
488   if (integer_zerop (cond))
489     {
490       expand_start_null_loop ();
491       expand_stmt (DO_BODY (t));
492       expand_end_null_loop ();
493     }
494   else
495     {
496       emit_nop ();
497       emit_line_note (input_filename, lineno);
498       expand_start_loop_continue_elsewhere (1);
499
500       expand_stmt (DO_BODY (t));
501
502       expand_loop_continue_here ();
503       cond = expand_cond (cond);
504       emit_line_note (input_filename, lineno);
505       expand_exit_loop_if_false (0, cond);
506       expand_end_loop ();
507     }
508 }
509
510 /* Build the node for a return statement and return it. */
511
512 tree
513 build_return_stmt (expr)
514      tree expr;
515 {
516   return (build_stmt (RETURN_STMT, expr));
517 }
518
519 /* Generate the RTL for STMT, which is a RETURN_STMT. */
520
521 void
522 genrtl_return_stmt (stmt)
523      tree stmt;
524 {
525   tree expr = RETURN_EXPR (stmt);
526
527   emit_line_note (input_filename, lineno);
528   if (!expr)
529     expand_null_return ();
530   else
531     {
532       expand_start_target_temps ();
533       expand_return (expr);
534       expand_end_target_temps ();
535     }
536 }
537
538 /* Generate the RTL for T, which is a FOR_STMT. */
539
540 void
541 genrtl_for_stmt (t)
542      tree t;
543 {
544   tree cond;
545   const char *saved_filename;
546   int saved_lineno;
547
548   if (NEW_FOR_SCOPE_P (t))
549     genrtl_do_pushlevel ();
550
551   expand_stmt (FOR_INIT_STMT (t));
552
553   /* Expand the initialization.  */
554   emit_nop ();
555   emit_line_note (input_filename, lineno);
556   expand_start_loop_continue_elsewhere (1); 
557   genrtl_do_pushlevel ();
558   cond = expand_cond (FOR_COND (t));
559
560   /* Save the filename and line number so that we expand the FOR_EXPR
561      we can reset them back to the saved values.  */
562   saved_filename = input_filename;
563   saved_lineno = lineno;
564
565   /* Expand the condition.  */
566   emit_line_note (input_filename, lineno);
567   if (cond)
568     expand_exit_loop_if_false (0, cond);
569
570   /* Expand the body.  */
571   genrtl_do_pushlevel ();
572   expand_stmt (FOR_BODY (t));
573
574   /* Expand the increment expression.  */
575   input_filename = saved_filename;
576   lineno = saved_lineno;
577   emit_line_note (input_filename, lineno);
578   expand_loop_continue_here ();
579   if (FOR_EXPR (t))
580     genrtl_expr_stmt (FOR_EXPR (t));
581   expand_end_loop ();
582 }
583
584 /* Build a break statement node and return it. */
585
586 tree
587 build_break_stmt ()
588 {
589   return (build_stmt (BREAK_STMT));
590 }
591
592 /* Generate the RTL for a BREAK_STMT. */
593
594 void
595 genrtl_break_stmt ()
596 {
597   emit_line_note (input_filename, lineno);
598   if ( ! expand_exit_something ())
599     error ("break statement not within loop or switch");
600 }
601
602 /* Build a continue statement node and return it. */
603
604 tree
605 build_continue_stmt ()
606 {
607   return (build_stmt (CONTINUE_STMT));
608 }
609
610 /* Generate the RTL for a CONTINUE_STMT. */
611
612 void
613 genrtl_continue_stmt ()
614 {
615   emit_line_note (input_filename, lineno);
616   if (! expand_continue_loop (0))
617     error ("continue statement not within a loop");   
618 }
619
620 /* Generate the RTL for T, which is a SCOPE_STMT. */
621
622 void
623 genrtl_scope_stmt (t)
624      tree t;
625 {
626   if (!SCOPE_NO_CLEANUPS_P (t))
627     {
628       if (SCOPE_BEGIN_P (t))
629         expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
630                                          SCOPE_STMT_BLOCK (t));
631       else if (SCOPE_END_P (t))
632         expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
633     }
634   else if (!SCOPE_NULLIFIED_P (t))
635     {
636       rtx note = emit_note (NULL,
637                             (SCOPE_BEGIN_P (t) 
638                              ? NOTE_INSN_BLOCK_BEG
639                              : NOTE_INSN_BLOCK_END));
640       NOTE_BLOCK (note) = SCOPE_STMT_BLOCK (t);
641     }
642 }
643
644 /* Generate the RTL for T, which is a SWITCH_STMT. */
645
646 void
647 genrtl_switch_stmt (t)
648      tree t;
649 {
650   tree cond;
651   genrtl_do_pushlevel ();
652  
653   cond = expand_cond (SWITCH_COND (t));
654   if (cond == error_mark_node)
655     /* The code is in error, but we don't want expand_end_case to
656        crash. */
657     cond = boolean_false_node;
658
659   emit_line_note (input_filename, lineno);
660   expand_start_case (1, cond, TREE_TYPE (cond), "switch statement");
661   expand_stmt (SWITCH_BODY (t));
662   expand_end_case (cond);
663 }
664
665 /* Create a CASE_LABEL tree node and return it. */
666
667 tree
668 build_case_label (low_value, high_value, label_decl)
669      tree low_value;
670      tree high_value;
671      tree label_decl;
672 {
673   return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
674 }
675
676
677 /* Generate the RTL for a CASE_LABEL. */
678
679 void 
680 genrtl_case_label (case_label)
681      tree case_label;
682 {
683   tree duplicate;
684   tree cleanup;
685
686   cleanup = last_cleanup_this_contour ();
687   if (cleanup)
688     {
689       static int explained = 0;
690       warning_with_decl (TREE_PURPOSE (cleanup), 
691                          "destructor needed for `%#D'");
692       warning ("where case label appears here");
693       if (!explained)
694         {
695           warning ("(enclose actions of previous case statements requiring destructors in their own scope.)");
696           explained = 1;
697         }
698     }
699
700   add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label), 
701                  CASE_LABEL_DECL (case_label), &duplicate);
702 }
703
704 /* Generate the RTL for T, which is a COMPOUND_STMT. */
705
706 void
707 genrtl_compound_stmt (t)
708     tree t;
709 {
710   expand_stmt (COMPOUND_BODY (t));
711 }
712
713 /* Generate the RTL for an ASM_STMT. */
714
715 void
716 genrtl_asm_stmt (cv_qualifier, string, output_operands,
717                  input_operands, clobbers, asm_input_p)
718      tree cv_qualifier;
719      tree string;
720      tree output_operands;
721      tree input_operands;
722      tree clobbers;
723      int asm_input_p;
724 {
725   if (cv_qualifier != NULL_TREE
726       && cv_qualifier != ridpointers[(int) RID_VOLATILE])
727     {
728       warning ("%s qualifier ignored on asm",
729                IDENTIFIER_POINTER (cv_qualifier));
730       cv_qualifier = NULL_TREE;
731     }
732
733   emit_line_note (input_filename, lineno);
734   if (asm_input_p)
735     expand_asm (string);
736   else
737     c_expand_asm_operands (string, output_operands, input_operands, 
738                            clobbers, cv_qualifier != NULL_TREE,
739                            input_filename, lineno);
740 }
741
742 /* Generate the RTL for a DECL_CLEANUP. */
743
744 void 
745 genrtl_decl_cleanup (decl, cleanup)
746      tree decl;
747      tree cleanup;
748 {
749   if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
750     expand_decl_cleanup (decl, cleanup);
751 }
752
753 /* We're about to expand T, a statement.  Set up appropriate context
754    for the substitution.  */
755
756 void
757 prep_stmt (t)
758      tree t;
759 {
760   if (!STMT_LINENO_FOR_FN_P (t))
761     lineno = STMT_LINENO (t);
762   current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
763 }
764
765 /* Generate the RTL for the statement T, its substatements, and any
766    other statements at its nesting level. */
767
768 void
769 expand_stmt (t)
770      tree t;
771 {
772   while (t && t != error_mark_node)
773     {
774       int saved_stmts_are_full_exprs_p;
775
776       /* Set up context appropriately for handling this statement.  */
777       saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
778       prep_stmt (t);
779
780       switch (TREE_CODE (t))
781         {
782         case RETURN_STMT:
783           genrtl_return_stmt (t);
784           break;
785
786         case EXPR_STMT:
787           genrtl_expr_stmt (EXPR_STMT_EXPR (t));
788           break;
789
790         case DECL_STMT:
791           genrtl_decl_stmt (t);
792           break;
793
794         case FOR_STMT:
795           genrtl_for_stmt (t);
796           break;
797
798         case WHILE_STMT:
799           genrtl_while_stmt (t);
800           break;
801
802         case DO_STMT:
803           genrtl_do_stmt (t);
804           break;
805
806         case IF_STMT:
807           genrtl_if_stmt (t);
808           break;
809
810         case COMPOUND_STMT:
811           genrtl_compound_stmt (t);
812           break;
813
814         case BREAK_STMT:
815           genrtl_break_stmt ();
816           break;
817
818         case CONTINUE_STMT:
819           genrtl_continue_stmt ();
820           break;
821
822         case SWITCH_STMT:
823           genrtl_switch_stmt (t);
824           break;
825
826         case CASE_LABEL:
827           genrtl_case_label (t);
828           break;
829
830         case LABEL_STMT:
831           expand_label (LABEL_STMT_LABEL (t));
832           break;
833
834         case GOTO_STMT:
835           genrtl_goto_stmt (GOTO_DESTINATION (t));
836           break;
837
838         case ASM_STMT:
839           genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
840                            ASM_OUTPUTS (t), ASM_INPUTS (t),
841                            ASM_CLOBBERS (t), ASM_INPUT_P (t));
842           break;
843
844         case SCOPE_STMT:
845           genrtl_scope_stmt (t);
846           break;
847
848         default:
849           if (lang_expand_stmt)
850             (*lang_expand_stmt) (t);
851           else 
852             abort ();
853           break;
854         }
855
856       /* Restore saved state.  */
857       current_stmt_tree ()->stmts_are_full_exprs_p = 
858         saved_stmts_are_full_exprs_p;
859
860       /* Go on to the next statement in this scope.  */
861       t = TREE_CHAIN (t);
862     }
863 }
864