xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/toir.cc (revision c64d4171c6f912972428361000d29636c687d68b)
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2    Copyright (C) 2006-2020 Free Software Foundation, Inc.
3 
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8 
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3.  If not see
16 <http://www.gnu.org/licenses/>.  */
17 
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
21 
22 #include "dmd/aggregate.h"
23 #include "dmd/declaration.h"
24 #include "dmd/expression.h"
25 #include "dmd/identifier.h"
26 #include "dmd/init.h"
27 #include "dmd/statement.h"
28 
29 #include "tree.h"
30 #include "tree-iterator.h"
31 #include "options.h"
32 #include "stmt.h"
33 #include "fold-const.h"
34 #include "diagnostic.h"
35 #include "stringpool.h"
36 #include "function.h"
37 #include "toplev.h"
38 
39 #include "d-tree.h"
40 
41 
42 /* Update data for defined and undefined labels when leaving a scope.  */
43 
44 bool
45 pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl)
46 {
47   binding_level *obl = bl->level_chain;
48 
49   if (ent->level == bl)
50     {
51       if (bl->kind == level_try)
52 	ent->in_try_scope = true;
53       else if (bl->kind == level_catch)
54 	ent->in_catch_scope = true;
55 
56       ent->level = obl;
57     }
58   else if (ent->fwdrefs)
59     {
60       for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next)
61 	ref->level = obl;
62     }
63 
64   return true;
65 }
66 
67 /* At the end of a function, all labels declared within the function
68    go out of scope.  Queue them in LABELS.  */
69 
70 bool
71 pop_label (Statement * const &, d_label_entry *ent, vec<tree> &labels)
72 {
73   if (!ent->bc_label)
74     {
75       /* Put the labels into the "variables" of the top-level block,
76 	 so debugger can see them.  */
77       if (DECL_NAME (ent->label))
78 	{
79 	  gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE);
80 	  labels.safe_push (ent->label);
81 	}
82     }
83 
84   return true;
85 }
86 
87 /* The D front-end does not use the 'binding level' system for a symbol table,
88    however it has been the goto structure for tracking code flow.
89    Primarily it is only needed to get debugging information for local variables
90    and otherwise support the back-end.  */
91 
92 void
93 push_binding_level (level_kind kind)
94 {
95   /* Add it to the front of currently active scopes stack.  */
96   binding_level *new_level = ggc_cleared_alloc<binding_level> ();
97   new_level->level_chain = current_binding_level;
98   new_level->kind = kind;
99 
100   current_binding_level = new_level;
101 }
102 
103 static int
104 cmp_labels (const void *p1, const void *p2)
105 {
106   const tree *l1 = (const tree *)p1;
107   const tree *l2 = (const tree *)p2;
108   return DECL_UID (*l1) - DECL_UID (*l2);
109 }
110 
111 tree
112 pop_binding_level (void)
113 {
114   binding_level *level = current_binding_level;
115   current_binding_level = level->level_chain;
116 
117   tree block = make_node (BLOCK);
118   BLOCK_VARS (block) = level->names;
119   BLOCK_SUBBLOCKS (block) = level->blocks;
120 
121   /* In each subblock, record that this is its superior.  */
122   for (tree t = level->blocks; t; t = BLOCK_CHAIN (t))
123     BLOCK_SUPERCONTEXT (t) = block;
124 
125   if (level->kind == level_function)
126     {
127       /* Dispose of the block that we just made inside some higher level.  */
128       DECL_INITIAL (current_function_decl) = block;
129       BLOCK_SUPERCONTEXT (block) = current_function_decl;
130 
131       /* Pop all the labels declared in the function.  */
132       if (d_function_chain->labels)
133 	{
134 	  auto_vec<tree> labels;
135 	  d_function_chain->labels->traverse<vec<tree> &, &pop_label> (labels);
136 	  d_function_chain->labels->empty ();
137 	  labels.qsort (cmp_labels);
138 	  for (unsigned i = 0; i < labels.length (); ++i)
139 	    {
140 	      DECL_CHAIN (labels[i]) = BLOCK_VARS (block);
141 	      BLOCK_VARS (block) = labels[i];
142 	    }
143 	}
144     }
145   else
146     {
147       /* Any uses of undefined labels, and any defined labels, now operate
148 	 under constraints of next binding contour.  */
149       if (d_function_chain && d_function_chain->labels)
150 	{
151 	  language_function *f = d_function_chain;
152 	  f->labels->traverse<binding_level *, &pop_binding_label> (level);
153 	}
154 
155       current_binding_level->blocks
156 	= block_chainon (current_binding_level->blocks, block);
157     }
158 
159   TREE_USED (block) = 1;
160   return block;
161 }
162 
163 /* Create an empty statement tree rooted at T.  */
164 
165 void
166 push_stmt_list (void)
167 {
168   tree t = alloc_stmt_list ();
169   vec_safe_push (d_function_chain->stmt_list, t);
170   d_keep (t);
171 }
172 
173 /* Finish the statement tree rooted at T.  */
174 
175 tree
176 pop_stmt_list (void)
177 {
178   tree t = d_function_chain->stmt_list->pop ();
179 
180   /* If the statement list is completely empty, just return it.  This is just
181      as good as build_empty_stmt, with the advantage that statement lists
182      are merged when they are appended to one another.  So using the
183      STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements.  */
184   if (TREE_SIDE_EFFECTS (t))
185     {
186       /* If the statement list contained exactly one statement, then extract
187 	 it immediately.  */
188       tree_stmt_iterator i = tsi_start (t);
189 
190       if (tsi_one_before_end_p (i))
191 	{
192 	  tree u = tsi_stmt (i);
193 	  tsi_delink (&i);
194 	  free_stmt_list (t);
195 	  t = u;
196 	}
197     }
198 
199   return t;
200 }
201 
202 /* T is an expression statement.  Add it to the statement-tree.  */
203 
204 void
205 add_stmt (tree t)
206 {
207   /* Ignore (void) 0; expression statements received from the frontend.
208      Likewise void_node is used when contracts become nops in release code.  */
209   if (t == void_node || IS_EMPTY_STMT (t))
210     return;
211 
212   /* At this point, we no longer care about the value of expressions,
213      so if there's no side-effects, then don't add it.  */
214   if (!TREE_SIDE_EFFECTS (t))
215     return;
216 
217   if (TREE_CODE (t) == COMPOUND_EXPR)
218     {
219       /* Push out each comma expressions as separate statements.  */
220       add_stmt (TREE_OPERAND (t, 0));
221       add_stmt (TREE_OPERAND (t, 1));
222     }
223   else
224     {
225       /* Force the type to be void so we don't need to create a temporary
226 	 variable to hold the inner expression.  */
227       if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
228 	TREE_TYPE (t) = void_type_node;
229 
230       /* Append the expression to the statement list.
231 	 Make sure it has a proper location.  */
232       if (EXPR_P (t) && !EXPR_HAS_LOCATION (t))
233 	SET_EXPR_LOCATION (t, input_location);
234 
235       tree stmt_list = d_function_chain->stmt_list->last ();
236       append_to_statement_list_force (t, &stmt_list);
237     }
238 }
239 
240 /* Implements the visitor interface to build the GCC trees of all Statement
241    AST classes emitted from the D Front-end.
242    All visit methods accept one parameter S, which holds the frontend AST
243    of the statement to compile.  They also don't return any value, instead
244    generated code are pushed to add_stmt(), which appends them to the
245    statement list in the current_binding_level.  */
246 
247 class IRVisitor : public Visitor
248 {
249   using Visitor::visit;
250 
251   FuncDeclaration *func_;
252 
253   /* Stack of labels which are targets for "break" and "continue",
254      linked through TREE_CHAIN.  */
255   tree break_label_;
256   tree continue_label_;
257 
258 public:
259   IRVisitor (FuncDeclaration *fd)
260   {
261     this->func_ = fd;
262     this->break_label_ = NULL_TREE;
263     this->continue_label_ = NULL_TREE;
264   }
265 
266   /* Helper for generating code for the statement AST class S.
267      Sets up the location of the statement before lowering.  */
268 
269   void build_stmt (Statement *s)
270   {
271     location_t saved_location = input_location;
272     input_location = make_location_t (s->loc);
273     s->accept (this);
274     input_location = saved_location;
275   }
276 
277   /* Start a new scope for a KIND statement.
278      Each user-declared variable will have a binding contour that begins
279      where the variable is declared and ends at its containing scope.  */
280 
281   void start_scope (level_kind kind)
282   {
283     push_binding_level (kind);
284     push_stmt_list ();
285   }
286 
287   /* Leave scope pushed by start_scope, returning a new bind_expr if
288      any variables where declared in the scope.  */
289 
290   tree end_scope (void)
291   {
292     tree block = pop_binding_level ();
293     tree body = pop_stmt_list ();
294 
295     if (! BLOCK_VARS (block))
296       return body;
297 
298     tree bind = build3 (BIND_EXPR, void_type_node,
299 			BLOCK_VARS (block), body, block);
300     TREE_SIDE_EFFECTS (bind) = 1;
301     return bind;
302   }
303 
304   /* Like end_scope, but also push it into the outer statement-tree.  */
305 
306   void finish_scope (void)
307   {
308     tree scope = this->end_scope ();
309     add_stmt (scope);
310   }
311 
312   /* Return TRUE if IDENT is the current function return label.  */
313 
314   bool is_return_label (Identifier *ident)
315   {
316     if (this->func_->returnLabel)
317       return this->func_->returnLabel->ident == ident;
318 
319     return false;
320   }
321 
322   /* Define a label, specifying the location in the source file.
323      Return the LABEL_DECL node for the label.  */
324 
325   tree define_label (Statement *s, Identifier *ident = NULL)
326   {
327     tree label = this->lookup_label (s, ident);
328     gcc_assert (DECL_INITIAL (label) == NULL_TREE);
329 
330     d_label_entry *ent = d_function_chain->labels->get (s);
331     gcc_assert (ent != NULL);
332 
333     /* Mark label as having been defined.  */
334     DECL_INITIAL (label) = error_mark_node;
335 
336     ent->level = current_binding_level;
337 
338     for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next)
339       this->check_previous_goto (ent->statement, ref);
340     ent->fwdrefs = NULL;
341 
342     return label;
343   }
344 
345   /* Emit a LABEL expression.  */
346 
347   void do_label (tree label)
348   {
349     /* Don't write out label unless it is marked as used by the frontend.
350        This makes auto-vectorization possible in conditional loops.
351        The only excemption to this is in the LabelStatement visitor,
352        in which all computed labels are marked regardless.  */
353     if (TREE_USED (label))
354       add_stmt (build1 (LABEL_EXPR, void_type_node, label));
355   }
356 
357   /* Emit a goto expression to LABEL.  */
358 
359   void do_jump (tree label)
360   {
361     add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
362     TREE_USED (label) = 1;
363   }
364 
365   /* Check that a new jump at statement scope FROM to a label declared in
366      statement scope TO is valid.  */
367 
368   void check_goto (Statement *from, Statement *to)
369   {
370     d_label_entry *ent = d_function_chain->labels->get (to);
371     gcc_assert (ent != NULL);
372 
373     /* If the label hasn't been defined yet, defer checking.  */
374     if (! DECL_INITIAL (ent->label))
375       {
376 	d_label_use_entry *fwdref = ggc_alloc<d_label_use_entry> ();
377 	fwdref->level = current_binding_level;
378 	fwdref->statement = from;
379 	fwdref->next = ent->fwdrefs;
380 	ent->fwdrefs = fwdref;
381 	return;
382       }
383 
384     if (ent->in_try_scope)
385       error_at (make_location_t (from->loc),
386 		"cannot %<goto%> into %<try%> block");
387     else if (ent->in_catch_scope)
388       error_at (make_location_t (from->loc),
389 		"cannot %<goto%> into %<catch%> block");
390   }
391 
392   /* Check that a previously seen jump to a newly defined label is valid.
393      S is the label statement; FWDREF is the jump context.  This is called
394      for both user-defined and case labels.  */
395 
396   void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
397   {
398     for (binding_level *b = current_binding_level; b ; b = b->level_chain)
399       {
400 	if (b == fwdref->level)
401 	  break;
402 
403 	if (b->kind == level_try || b->kind == level_catch)
404 	  {
405 	    location_t location;
406 
407 	    if (s->isLabelStatement ())
408 	      {
409 		location = make_location_t (fwdref->statement->loc);
410 		if (b->kind == level_try)
411 		  error_at (location, "cannot %<goto%> into %<try%> block");
412 		else
413 		  error_at (location, "cannot %<goto%> into %<catch%> block");
414 	      }
415 	    else if (s->isCaseStatement ())
416 	      {
417 		location = make_location_t (s->loc);
418 		error_at (location, "case cannot be in different "
419 			  "%<try%> block level from %<switch%>");
420 	      }
421 	    else if (s->isDefaultStatement ())
422 	      {
423 		location = make_location_t (s->loc);
424 		error_at (location, "default cannot be in different "
425 			  "%<try%> block level from %<switch%>");
426 	      }
427 	    else
428 	      gcc_unreachable ();
429 	  }
430       }
431   }
432 
433   /* Get or build LABEL_DECL using the IDENT and statement block S given.  */
434 
435   tree lookup_label (Statement *s, Identifier *ident = NULL)
436   {
437     /* You can't use labels at global scope.  */
438     if (d_function_chain == NULL)
439       {
440 	error ("label %s referenced outside of any function",
441 	       ident ? ident->toChars () : "(unnamed)");
442 	return NULL_TREE;
443       }
444 
445     /* Create the label htab for the function on demand.  */
446     if (!d_function_chain->labels)
447       {
448 	d_function_chain->labels
449 	  = hash_map<Statement *, d_label_entry>::create_ggc (13);
450       }
451 
452     d_label_entry *ent = d_function_chain->labels->get (s);
453     if (ent != NULL)
454       return ent->label;
455     else
456       {
457 	tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
458 	tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
459 				name, void_type_node);
460 	DECL_CONTEXT (decl) = current_function_decl;
461 	DECL_MODE (decl) = VOIDmode;
462 
463 	/* Create new empty slot.  */
464 	ent = ggc_cleared_alloc<d_label_entry> ();
465 	ent->statement = s;
466 	ent->label = decl;
467 
468 	bool existed = d_function_chain->labels->put (s, *ent);
469 	gcc_assert (!existed);
470 
471 	return decl;
472       }
473   }
474 
475   /* Get the LABEL_DECL to represent a break or continue for the
476      statement S given.  BC indicates which.  */
477 
478   tree lookup_bc_label (Statement *s, bc_kind bc)
479   {
480     tree vec = this->lookup_label (s);
481 
482     /* The break and continue labels are put into a TREE_VEC.  */
483     if (TREE_CODE (vec) == LABEL_DECL)
484       {
485 	d_label_entry *ent = d_function_chain->labels->get (s);
486 	gcc_assert (ent != NULL);
487 
488 	vec = make_tree_vec (2);
489 	TREE_VEC_ELT (vec, bc_break) = ent->label;
490 
491 	/* Build the continue label.  */
492 	tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
493 				 NULL_TREE, void_type_node);
494 	DECL_CONTEXT (label) = current_function_decl;
495 	DECL_MODE (label) = VOIDmode;
496 	TREE_VEC_ELT (vec, bc_continue) = label;
497 
498 	ent->label = vec;
499 	ent->bc_label = true;
500       }
501 
502     return TREE_VEC_ELT (vec, bc);
503   }
504 
505   /* Set and return the current break label for the current block.  */
506 
507   tree push_break_label (Statement *s)
508   {
509     tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
510     DECL_CHAIN (label) = this->break_label_;
511     this->break_label_ = label;
512     return label;
513   }
514 
515   /* Finish with the current break label.  */
516 
517   void pop_break_label (tree label)
518   {
519     gcc_assert (this->break_label_ == label);
520     this->break_label_ = DECL_CHAIN (this->break_label_);
521     this->do_label (label);
522   }
523 
524   /* Set and return the continue label for the current block.  */
525 
526   tree push_continue_label (Statement *s)
527   {
528     tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
529     DECL_CHAIN (label) = this->continue_label_;
530     this->continue_label_ = label;
531     return label;
532   }
533 
534   /* Finish with the current continue label.  */
535 
536   void pop_continue_label (tree label)
537   {
538     gcc_assert (this->continue_label_ == label);
539     this->continue_label_ = DECL_CHAIN (this->continue_label_);
540     this->do_label (label);
541   }
542 
543   /* Visitor interfaces.  */
544 
545 
546   /* This should be overridden by each statement class.  */
547 
548   void visit (Statement *)
549   {
550     gcc_unreachable ();
551   }
552 
553   /* The frontend lowers `scope (exit/failure/success)' statements as
554      try/catch/finally.  At this point, this statement is just an empty
555      placeholder.  Maybe the frontend shouldn't leak these.  */
556 
557   void visit (OnScopeStatement *)
558   {
559   }
560 
561   /* If statements provide simple conditional execution of statements.  */
562 
563   void visit (IfStatement *s)
564   {
565     this->start_scope (level_cond);
566 
567     /* Build the outer 'if' condition, which may produce temporaries
568        requiring scope destruction.  */
569     tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
570 					 s->condition->type);
571     tree ifbody = void_node;
572     tree elsebody = void_node;
573 
574     /* Build the 'then' branch.  */
575     if (s->ifbody)
576       {
577 	push_stmt_list ();
578 	this->build_stmt (s->ifbody);
579 	ifbody = pop_stmt_list ();
580       }
581 
582     /* Now build the 'else' branch, which may have nested 'else if' parts.  */
583     if (s->elsebody)
584       {
585 	push_stmt_list ();
586 	this->build_stmt (s->elsebody);
587 	elsebody = pop_stmt_list ();
588       }
589 
590     /* Wrap up our constructed if condition into a COND_EXPR.  */
591     tree cond = build_vcondition (ifcond, ifbody, elsebody);
592     add_stmt (cond);
593 
594     /* Finish the if-then scope.  */
595     this->finish_scope ();
596   }
597 
598   /* Should there be any `pragma (...)' statements requiring code generation,
599      here would be the place to do it.  For now, all pragmas are handled
600      by the frontend.  */
601 
602   void visit (PragmaStatement *)
603   {
604   }
605 
606   /* The frontend lowers `while (...)' statements as `for (...)' loops.
607      This visitor is not strictly required other than to enforce that
608      these kinds of statements never reach here.  */
609 
610   void visit (WhileStatement *)
611   {
612     gcc_unreachable ();
613   }
614 
615   /* Do while statments implement simple loops.  The body is executed, then
616      the condition is evaluated.  */
617 
618   void visit (DoStatement *s)
619   {
620     tree lbreak = this->push_break_label (s);
621 
622     this->start_scope (level_loop);
623     if (s->_body)
624       {
625 	tree lcontinue = this->push_continue_label (s);
626 	this->build_stmt (s->_body);
627 	this->pop_continue_label (lcontinue);
628       }
629 
630     /* Build the outer 'while' condition, which may produce temporaries
631        requiring scope destruction.  */
632     tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
633 					   s->condition->type);
634     add_stmt (build_vcondition (exitcond, void_node,
635 				build1 (GOTO_EXPR, void_type_node, lbreak)));
636     TREE_USED (lbreak) = 1;
637 
638     tree body = this->end_scope ();
639     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
640 
641     this->pop_break_label (lbreak);
642   }
643 
644   /* For statements implement loops with initialization, test, and
645      increment clauses.  */
646 
647   void visit (ForStatement *s)
648   {
649     tree lbreak = this->push_break_label (s);
650     this->start_scope (level_loop);
651 
652     if (s->_init)
653       this->build_stmt (s->_init);
654 
655     if (s->condition)
656       {
657 	tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
658 					       s->condition->type);
659 	add_stmt (build_vcondition (exitcond, void_node,
660 				    build1 (GOTO_EXPR, void_type_node,
661 					    lbreak)));
662 	TREE_USED (lbreak) = 1;
663       }
664 
665     if (s->_body)
666       {
667 	tree lcontinue = this->push_continue_label (s);
668 	this->build_stmt (s->_body);
669 	this->pop_continue_label (lcontinue);
670       }
671 
672     if (s->increment)
673       {
674 	/* Force side effects?  */
675 	add_stmt (build_expr_dtor (s->increment));
676       }
677 
678     tree body = this->end_scope ();
679     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
680 
681     this->pop_break_label (lbreak);
682   }
683 
684   /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
685      This visitor is not strictly required other than to enforce that
686      these kinds of statements never reach here.  */
687 
688   void visit (ForeachStatement *)
689   {
690     gcc_unreachable ();
691   }
692 
693   /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
694      loops.  This visitor is not strictly required other than to enforce that
695      these kinds of statements never reach here.  */
696 
697   void visit (ForeachRangeStatement *)
698   {
699     gcc_unreachable ();
700   }
701 
702   /* Jump to the associated exit label for the current loop.  If IDENT
703      for the Statement is not null, then the label is user defined.  */
704 
705   void visit (BreakStatement *s)
706   {
707     if (s->ident)
708       {
709 	/* The break label may actually be some levels up.
710 	   eg: on a try/finally wrapping a loop.  */
711 	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
712 	gcc_assert (label != NULL);
713 	Statement *stmt = label->statement->getRelatedLabeled ();
714 	this->do_jump (this->lookup_bc_label (stmt, bc_break));
715       }
716     else
717       this->do_jump (this->break_label_);
718   }
719 
720   /* Jump to the associated continue label for the current loop.  If IDENT
721      for the Statement is not null, then the label is user defined.  */
722 
723   void visit (ContinueStatement *s)
724   {
725     if (s->ident)
726       {
727 	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
728 	gcc_assert (label != NULL);
729 	this->do_jump (this->lookup_bc_label (label->statement,
730 					      bc_continue));
731       }
732     else
733       this->do_jump (this->continue_label_);
734   }
735 
736   /* A goto statement jumps to the statement identified by the given label.  */
737 
738   void visit (GotoStatement *s)
739   {
740     gcc_assert (s->label->statement != NULL);
741     gcc_assert (s->tf == s->label->statement->tf);
742 
743     /* If no label found, there was an error.  */
744     tree label = this->lookup_label (s->label->statement, s->label->ident);
745     this->do_jump (label);
746 
747     /* Need to error if the goto is jumping into a try or catch block.  */
748     this->check_goto (s, s->label->statement);
749   }
750 
751   /* Statements can be labeled.  A label is an identifier that precedes
752      a statement.  */
753 
754   void visit (LabelStatement *s)
755   {
756     LabelDsymbol *sym;
757 
758     if (this->is_return_label (s->ident))
759       sym = this->func_->returnLabel;
760     else
761       sym = this->func_->searchLabel (s->ident);
762 
763     /* If no label found, there was an error.  */
764     tree label = this->define_label (sym->statement, sym->ident);
765     TREE_USED (label) = 1;
766 
767     this->do_label (label);
768 
769     if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
770       this->build_stmt (this->func_->fensure);
771     else if (s->statement)
772       this->build_stmt (s->statement);
773   }
774 
775   /* A switch statement goes to one of a collection of case statements
776      depending on the value of the switch expression.  */
777 
778   void visit (SwitchStatement *s)
779   {
780     this->start_scope (level_switch);
781     tree lbreak = this->push_break_label (s);
782 
783     tree condition = build_expr_dtor (s->condition);
784     Type *condtype = s->condition->type->toBasetype ();
785 
786     /* A switch statement on a string gets turned into a library call,
787        which does a binary lookup on list of string cases.  */
788     if (s->condition->type->isString ())
789       {
790 	Type *etype = condtype->nextOf ()->toBasetype ();
791 	libcall_fn libcall;
792 
793 	switch (etype->ty)
794 	  {
795 	  case Tchar:
796 	    libcall = LIBCALL_SWITCH_STRING;
797 	    break;
798 
799 	  case Twchar:
800 	    libcall = LIBCALL_SWITCH_USTRING;
801 	    break;
802 
803 	  case Tdchar:
804 	    libcall = LIBCALL_SWITCH_DSTRING;
805 	    break;
806 
807 	  default:
808 	    ::error ("switch statement value must be an array of "
809 		     "some character type, not %s", etype->toChars ());
810 	    gcc_unreachable ();
811 	  }
812 
813 	/* Apparently the backend is supposed to sort and set the indexes
814 	   on the case array, have to change them to be usable.  */
815 	Type *satype = condtype->sarrayOf (s->cases->dim);
816 	vec<constructor_elt, va_gc> *elms = NULL;
817 
818 	s->cases->sort ();
819 
820 	for (size_t i = 0; i < s->cases->dim; i++)
821 	  {
822 	    CaseStatement *cs = (*s->cases)[i];
823 	    cs->index = i;
824 
825 	    if (cs->exp->op != TOKstring)
826 	      s->error ("case '%s' is not a string", cs->exp->toChars ());
827 	    else
828 	      {
829 		tree exp = build_expr (cs->exp, true);
830 		CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
831 	      }
832 	  }
833 
834 	/* Build static declaration to reference constructor.  */
835 	tree ctor = build_constructor (build_ctype (satype), elms);
836 	tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
837 	TREE_READONLY (decl) = 1;
838 	d_pushdecl (decl);
839 	rest_of_decl_compilation (decl, 1, 0);
840 
841 	/* Pass it as a dynamic array.  */
842 	decl = d_array_value (build_ctype (condtype->arrayOf ()),
843 			      size_int (s->cases->dim),
844 			      build_address (decl));
845 
846 	condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
847       }
848     else if (!condtype->isscalar ())
849       {
850 	error ("cannot handle switch condition of type %s",
851 	       condtype->toChars ());
852 	gcc_unreachable ();
853       }
854 
855     condition = fold (condition);
856 
857     /* Build LABEL_DECLs now so they can be refered to by goto case.
858        Also checking the jump from the switch to the label is allowed.  */
859     if (s->cases)
860       {
861 	for (size_t i = 0; i < s->cases->dim; i++)
862 	  {
863 	    CaseStatement *cs = (*s->cases)[i];
864 	    tree caselabel = this->lookup_label (cs);
865 
866 	    /* Write cases as a series of if-then-else blocks.
867 	       if (condition == case)
868 		 goto caselabel;  */
869 	    if (s->hasVars)
870 	      {
871 		tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
872 				      condition, build_expr_dtor (cs->exp));
873 		tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
874 					   caselabel);
875 		tree cond = build_vcondition (ifcase, ifbody, void_node);
876 		TREE_USED (caselabel) = 1;
877 		LABEL_VARIABLE_CASE (caselabel) = 1;
878 		add_stmt (cond);
879 	      }
880 
881 	    this->check_goto (s, cs);
882 	  }
883 
884 	if (s->sdefault)
885 	  {
886 	    tree defaultlabel = this->lookup_label (s->sdefault);
887 
888 	    /* The default label is the last 'else' block.  */
889 	    if (s->hasVars)
890 	      {
891 		this->do_jump (defaultlabel);
892 		LABEL_VARIABLE_CASE (defaultlabel) = 1;
893 	      }
894 
895 	    this->check_goto (s, s->sdefault);
896 	  }
897       }
898 
899     /* Switch body goes in its own statement list.  */
900     push_stmt_list ();
901     if (s->_body)
902       this->build_stmt (s->_body);
903 
904     tree casebody = pop_stmt_list ();
905 
906     /* Wrap up constructed body into a switch_expr, unless it was
907        converted to an if-then-else expression.  */
908     if (s->hasVars)
909       add_stmt (casebody);
910     else
911       {
912 	tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
913 				  condition, casebody);
914 	add_stmt (switchexpr);
915 	SWITCH_ALL_CASES_P (switchexpr) = 1;
916       }
917 
918     SWITCH_BREAK_LABEL_P (lbreak) = 1;
919 
920     /* If the switch had any 'break' statements, emit the label now.  */
921     this->pop_break_label (lbreak);
922     this->finish_scope ();
923   }
924 
925   /* Declare the case label associated with the current SwitchStatement.  */
926 
927   void visit (CaseStatement *s)
928   {
929     /* Emit the case label.  */
930     tree label = this->define_label (s);
931 
932     if (LABEL_VARIABLE_CASE (label))
933       this->do_label (label);
934     else
935       {
936 	tree casevalue;
937 	if (s->exp->type->isscalar ())
938 	  casevalue = build_expr (s->exp);
939 	else
940 	  casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
941 
942 	tree caselabel = build_case_label (casevalue, NULL_TREE, label);
943 	add_stmt (caselabel);
944       }
945 
946     /* Now do the body.  */
947     if (s->statement)
948       this->build_stmt (s->statement);
949   }
950 
951   /* Declare the default label associated with the current SwitchStatement.  */
952 
953   void visit (DefaultStatement *s)
954   {
955     /* Emit the default case label.  */
956     tree label = this->define_label (s);
957 
958     if (LABEL_VARIABLE_CASE (label))
959       this->do_label (label);
960     else
961       {
962 	tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
963 	add_stmt (caselabel);
964       }
965 
966     /* Now do the body.  */
967     if (s->statement)
968       this->build_stmt (s->statement);
969   }
970 
971   /* Implements 'goto default' by jumping to the label associated with
972      the DefaultStatement in a switch block.  */
973 
974   void visit (GotoDefaultStatement *s)
975   {
976     tree label = this->lookup_label (s->sw->sdefault);
977     this->do_jump (label);
978   }
979 
980   /* Implements 'goto case' by jumping to the label associated with the
981      CaseStatement in a switch block.  */
982 
983   void visit (GotoCaseStatement *s)
984   {
985     tree label = this->lookup_label (s->cs);
986     this->do_jump (label);
987   }
988 
989   /* Throw a SwitchError exception, called when a switch statement has
990      no DefaultStatement, yet none of the cases match.  */
991 
992   void visit (SwitchErrorStatement *s)
993   {
994     add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
995   }
996 
997   /* A return statement exits the current function and supplies its return
998      value, if the return type is not void.  */
999 
1000   void visit (ReturnStatement *s)
1001   {
1002     if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
1003       {
1004 	/* Return has no value.  */
1005 	add_stmt (return_expr (NULL_TREE));
1006 	return;
1007       }
1008 
1009     TypeFunction *tf = (TypeFunction *)this->func_->type;
1010     Type *type = this->func_->tintro != NULL
1011       ? this->func_->tintro->nextOf () : tf->nextOf ();
1012 
1013     if ((this->func_->isMain () || this->func_->isCMain ())
1014 	&& type->toBasetype ()->ty == Tvoid)
1015       type = Type::tint32;
1016 
1017     if (this->func_->nrvo_can && this->func_->nrvo_var)
1018       {
1019 	/* Just refer to the DECL_RESULT; this differs from using
1020 	   NULL_TREE in that it indicates that we care about the value
1021 	   of the DECL_RESULT.  */
1022 	tree decl = DECL_RESULT (get_symbol_decl (this->func_));
1023 	add_stmt (return_expr (decl));
1024       }
1025     else
1026       {
1027 	/* Convert for initializing the DECL_RESULT.  */
1028 	tree expr = build_return_dtor (s->exp, type, tf);
1029 	add_stmt (expr);
1030       }
1031   }
1032 
1033   /* Evaluate the enclosed expression, and add it to the statement list.  */
1034 
1035   void visit (ExpStatement *s)
1036   {
1037     if (s->exp)
1038       {
1039 	/* Expression may produce temporaries requiring scope destruction.  */
1040 	tree exp = build_expr_dtor (s->exp);
1041 	add_stmt (exp);
1042       }
1043   }
1044 
1045   /* Evaluate all enclosed statements.  */
1046 
1047   void visit (CompoundStatement *s)
1048   {
1049     if (s->statements == NULL)
1050       return;
1051 
1052     for (size_t i = 0; i < s->statements->dim; i++)
1053       {
1054 	Statement *statement = (*s->statements)[i];
1055 
1056 	if (statement != NULL)
1057 	  this->build_stmt (statement);
1058       }
1059   }
1060 
1061   /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1062      These are compiled down as a `do ... while (0)', where each unrolled loop
1063      is nested inside and given their own continue label to jump to.  */
1064 
1065   void visit (UnrolledLoopStatement *s)
1066   {
1067     if (s->statements == NULL)
1068       return;
1069 
1070     tree lbreak = this->push_break_label (s);
1071     this->start_scope (level_loop);
1072 
1073     for (size_t i = 0; i < s->statements->dim; i++)
1074       {
1075 	Statement *statement = (*s->statements)[i];
1076 
1077 	if (statement != NULL)
1078 	  {
1079 	    tree lcontinue = this->push_continue_label (statement);
1080 	    this->build_stmt (statement);
1081 	    this->pop_continue_label (lcontinue);
1082 	  }
1083       }
1084 
1085     this->do_jump (this->break_label_);
1086 
1087     tree body = this->end_scope ();
1088     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1089 
1090     this->pop_break_label (lbreak);
1091   }
1092 
1093   /* Start a new scope and visit all nested statements, wrapping
1094      them up into a BIND_EXPR at the end of the scope.  */
1095 
1096   void visit (ScopeStatement *s)
1097   {
1098     if (s->statement == NULL)
1099       return;
1100 
1101     this->start_scope (level_block);
1102     this->build_stmt (s->statement);
1103     this->finish_scope ();
1104   }
1105 
1106   /* A with statement is a way to simplify repeated references to the same
1107      object, where the handle is either a class or struct instance.  */
1108 
1109   void visit (WithStatement *s)
1110   {
1111     this->start_scope (level_with);
1112 
1113     if (s->wthis)
1114       {
1115 	/* Perform initialisation of the 'with' handle.  */
1116 	ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1117 	gcc_assert (ie != NULL);
1118 
1119 	declare_local_var (s->wthis);
1120 	tree init = build_expr_dtor (ie->exp);
1121 	add_stmt (init);
1122       }
1123 
1124     if (s->_body)
1125       this->build_stmt (s->_body);
1126 
1127     this->finish_scope ();
1128   }
1129 
1130   /* Implements 'throw Object'.  Frontend already checks that the object
1131      thrown is a class type, but does not check if it is derived from
1132      Object.  Foreign objects are not currently supported at run-time.  */
1133 
1134   void visit (ThrowStatement *s)
1135   {
1136     ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1137     InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1138     tree arg = build_expr_dtor (s->exp);
1139 
1140     if (!global.params.useExceptions)
1141       {
1142 	static int warned = 0;
1143 	if (!warned)
1144 	  {
1145 	    error_at (make_location_t (s->loc), "exception handling disabled; "
1146 		      "use %<-fexceptions%> to enable");
1147 	    warned = 1;
1148 	  }
1149       }
1150 
1151     if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1152       error_at (make_location_t (s->loc), "cannot throw C++ classes");
1153     else if (cd->com || (id != NULL && id->com))
1154       error_at (make_location_t (s->loc), "cannot throw COM objects");
1155     else
1156       arg = build_nop (build_ctype (get_object_type ()), arg);
1157 
1158     add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1159   }
1160 
1161   /* Build a try-catch statement, one of the building blocks for exception
1162      handling generated by the frontend.  This is also used to implement
1163      `scope (failure)' statements.  */
1164 
1165   void visit (TryCatchStatement *s)
1166   {
1167     this->start_scope (level_try);
1168     if (s->_body)
1169       this->build_stmt (s->_body);
1170 
1171     tree trybody = this->end_scope ();
1172 
1173     /* Try handlers go in their own statement list.  */
1174     push_stmt_list ();
1175 
1176     if (s->catches)
1177       {
1178 	for (size_t i = 0; i < s->catches->dim; i++)
1179 	  {
1180 	    Catch *vcatch = (*s->catches)[i];
1181 
1182 	    this->start_scope (level_catch);
1183 
1184 	    tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1185 	    tree catchtype = build_ctype (vcatch->type);
1186 	    tree object = NULL_TREE;
1187 
1188 	    ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1189 
1190 	    /* Retrieve the internal exception object, which could be for a
1191 	       D or C++ catch handler.  This is different from the generic
1192 	       exception pointer returned from gcc runtime.  */
1193 	    Type *tcatch = vcatch->type->toBasetype ();
1194 	    ClassDeclaration *cd = tcatch->isClassHandle ();
1195 
1196 	    libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1197 	      : LIBCALL_BEGIN_CATCH;
1198 	    object = build_libcall (libcall, vcatch->type, 1, ehptr);
1199 
1200 	    if (vcatch->var)
1201 	      {
1202 		tree var = get_symbol_decl (vcatch->var);
1203 		tree init = build_assign (INIT_EXPR, var, object);
1204 
1205 		declare_local_var (vcatch->var);
1206 		add_stmt (init);
1207 	      }
1208 	    else
1209 	      {
1210 		/* Still need to emit a call to __gdc_begin_catch() to
1211 		   remove the object from the uncaught exceptions list.  */
1212 		add_stmt (object);
1213 	      }
1214 
1215 	    if (vcatch->handler)
1216 	      this->build_stmt (vcatch->handler);
1217 
1218 	    tree catchbody = this->end_scope ();
1219 
1220 	    /* Need to wrap C++ handlers in a try/finally block to signal
1221 	       the end catch callback.  */
1222 	    if (cd->isCPPclass ())
1223 	      {
1224 		tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1225 					       Type::tvoid, 0);
1226 		catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1227 				    catchbody, endcatch);
1228 	      }
1229 
1230 	    add_stmt (build2 (CATCH_EXPR, void_type_node,
1231 			      catchtype, catchbody));
1232 	  }
1233       }
1234 
1235     tree catches = pop_stmt_list ();
1236 
1237     /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1238        statement list, however pop_stmt_list may optimize away the list
1239        if there is only a single catch to push.  */
1240     if (TREE_CODE (catches) != STATEMENT_LIST)
1241       {
1242 	tree stmt_list = alloc_stmt_list ();
1243 	append_to_statement_list_force (catches, &stmt_list);
1244 	catches = stmt_list;
1245       }
1246 
1247     add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1248   }
1249 
1250   /* Build a try-finally statement, one of the building blocks for exception
1251      handling generated by the frontend.  This is also used to implement
1252      `scope (exit)' statements.  */
1253 
1254   void visit (TryFinallyStatement *s)
1255   {
1256     this->start_scope (level_try);
1257     if (s->_body)
1258       this->build_stmt (s->_body);
1259 
1260     tree trybody = this->end_scope ();
1261 
1262     this->start_scope (level_finally);
1263     if (s->finalbody)
1264       this->build_stmt (s->finalbody);
1265 
1266     tree finally = this->end_scope ();
1267 
1268     add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1269   }
1270 
1271   /* The frontend lowers `synchronized (...)' statements as a call to
1272      monitor/critical enter and exit wrapped around try/finally.
1273      This visitor is not strictly required other than to enforce that
1274      these kinds of statements never reach here.  */
1275 
1276   void visit (SynchronizedStatement *)
1277   {
1278     gcc_unreachable ();
1279   }
1280 
1281   /* D Inline Assembler is not implemented, as it would require writing
1282      an assembly parser for each supported target.  Instead we leverage
1283      GCC extended assembler using the GccAsmStatement class.  */
1284 
1285   void visit (AsmStatement *)
1286   {
1287     sorry ("D inline assembler statements are not supported in GDC.");
1288   }
1289 
1290   /* Build a GCC extended assembler expression, whose components are
1291      an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS.  */
1292 
1293   void visit (GccAsmStatement *s)
1294   {
1295     StringExp *insn = (StringExp *)s->insn;
1296     tree outputs = NULL_TREE;
1297     tree inputs = NULL_TREE;
1298     tree clobbers = NULL_TREE;
1299     tree labels = NULL_TREE;
1300 
1301     /* Collect all arguments, which may be input or output operands.  */
1302     if (s->args)
1303       {
1304 	for (size_t i = 0; i < s->args->dim; i++)
1305 	  {
1306 	    Identifier *name = (*s->names)[i];
1307 	    const char *sname = name ? name->toChars () : NULL;
1308 	    tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1309 
1310 	    StringExp *constr = (StringExp *)(*s->constraints)[i];
1311 	    const char *cstring = (const char *)(constr->len
1312 						 ? constr->string : "");
1313 	    tree str = build_string (constr->len, cstring);
1314 
1315 	    Expression *earg = (*s->args)[i];
1316 	    tree val = build_expr (earg);
1317 
1318 	    if (i < s->outputargs)
1319 	      {
1320 		tree arg = build_tree_list (id, str);
1321 		outputs = chainon (outputs, build_tree_list (arg, val));
1322 	      }
1323 	    else
1324 	      {
1325 		tree arg = build_tree_list (id, str);
1326 		inputs = chainon (inputs, build_tree_list (arg, val));
1327 	      }
1328 	  }
1329       }
1330 
1331     /* Collect all clobber arguments.  */
1332     if (s->clobbers)
1333       {
1334 	for (size_t i = 0; i < s->clobbers->dim; i++)
1335 	  {
1336 	    StringExp *clobber = (StringExp *)(*s->clobbers)[i];
1337 	    const char *cstring = (const char *)(clobber->len
1338 						 ? clobber->string : "");
1339 
1340 	    tree val = build_string (clobber->len, cstring);
1341 	    clobbers = chainon (clobbers, build_tree_list (0, val));
1342 	  }
1343       }
1344 
1345     /* Collect all goto labels, these should have been already checked
1346        by the front-end, so pass down the label symbol to the back-end.  */
1347     if (s->labels)
1348       {
1349 	for (size_t i = 0; i < s->labels->dim; i++)
1350 	  {
1351 	    Identifier *ident = (*s->labels)[i];
1352 	    GotoStatement *gs = (*s->gotos)[i];
1353 
1354 	    gcc_assert (gs->label->statement != NULL);
1355 	    gcc_assert (gs->tf == gs->label->statement->tf);
1356 
1357 	    const char *sident = ident->toChars ();
1358 	    tree name = build_string (strlen (sident), sident);
1359 	    tree label = this->lookup_label (gs->label->statement,
1360 					     gs->label->ident);
1361 	    TREE_USED (label) = 1;
1362 
1363 	    labels = chainon (labels, build_tree_list (name, label));
1364 	  }
1365       }
1366 
1367     /* Do some extra validation on all input and output operands.  */
1368     const char *insnstring = (const char *)(insn->len ? insn->string : "");
1369     tree string = build_string (insn->len, insnstring);
1370     string = resolve_asm_operand_names (string, outputs, inputs, labels);
1371 
1372     if (s->args)
1373       {
1374 	unsigned noutputs = s->outputargs;
1375 	unsigned ninputs = (s->args->dim - noutputs);
1376 	const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1377 	bool allows_mem, allows_reg, is_inout;
1378 	size_t i;
1379 	tree t;
1380 
1381 	for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1382 	  {
1383 	    tree output = TREE_VALUE (t);
1384 	    const char *constraint
1385 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1386 
1387 	    oconstraints[i] = constraint;
1388 
1389 	    if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1390 					 &allows_mem, &allows_reg, &is_inout))
1391 	      {
1392 		/* If the output argument is going to end up in memory.  */
1393 		if (!allows_reg)
1394 		  d_mark_addressable (output);
1395 	      }
1396 	    else
1397 	      output = error_mark_node;
1398 
1399 	    TREE_VALUE (t) = output;
1400 	  }
1401 
1402 	for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1403 	  {
1404 	    tree input = TREE_VALUE (t);
1405 	    const char *constraint
1406 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1407 
1408 	    if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1409 					oconstraints, &allows_mem, &allows_reg))
1410 	      {
1411 		/* If the input argument is going to end up in memory.  */
1412 		if (!allows_reg && allows_mem)
1413 		  d_mark_addressable (input);
1414 	      }
1415 	    else
1416 	      input = error_mark_node;
1417 
1418 	    TREE_VALUE (t) = input;
1419 	  }
1420       }
1421 
1422     tree exp = build5 (ASM_EXPR, void_type_node, string,
1423 		       outputs, inputs, clobbers, labels);
1424     SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1425 
1426     /* If the extended syntax was not used, mark the ASM_EXPR as being an
1427        ASM_INPUT expression instead of an ASM_OPERAND with no operands.  */
1428     if (s->args == NULL && s->clobbers == NULL)
1429       ASM_INPUT_P (exp) = 1;
1430 
1431     /* All asm statements are assumed to have a side effect.  As a future
1432        optimization, this could be unset when building in release mode.  */
1433     ASM_VOLATILE_P (exp) = 1;
1434 
1435     /* If the function has been annotated with 'pragma(inline)', then mark
1436        the asm expression as being inline as well.  */
1437     if (this->func_->inlining == PINLINEalways)
1438       ASM_INLINE_P (exp) = 1;
1439 
1440     add_stmt (exp);
1441   }
1442 
1443   /* Import symbols from another module.  */
1444 
1445   void visit (ImportStatement *s)
1446   {
1447     if (s->imports == NULL)
1448       return;
1449 
1450     for (size_t i = 0; i < s->imports->dim; i++)
1451       {
1452 	Dsymbol *dsym = (*s->imports)[i];
1453 
1454 	if (dsym != NULL)
1455 	  build_decl_tree (dsym);
1456       }
1457   }
1458 };
1459 
1460 /* Main entry point for the IRVisitor interface to generate
1461    code for the body of function FD.  */
1462 
1463 void
1464 build_function_body (FuncDeclaration *fd)
1465 {
1466   IRVisitor v = IRVisitor (fd);
1467   location_t saved_location = input_location;
1468   input_location = make_location_t (fd->loc);
1469   v.build_stmt (fd->fbody);
1470   input_location = saved_location;
1471 }
1472