OSDN Git Service

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