xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/toir.cc (revision 4ac76180e904e771b9d522c7e57296d371f06499)
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
pop_binding_label(Statement * const &,d_label_entry * ent,binding_level * bl)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
pop_label(Statement * const &,d_label_entry * ent,vec<tree> & labels)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
push_binding_level(level_kind kind)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
cmp_labels(const void * p1,const void * p2)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
pop_binding_level(void)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
push_stmt_list(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
pop_stmt_list(void)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
add_stmt(tree t)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:
IRVisitor(FuncDeclaration * fd)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 
build_stmt(Statement * s)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 
start_scope(level_kind kind)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 
end_scope(void)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 
finish_scope(void)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 
is_return_label(Identifier * ident)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 
define_label(Statement * s,Identifier * ident=NULL)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 
do_label(tree label)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 
do_jump(tree label)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 
check_goto(Statement * from,Statement * to)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 
check_previous_goto(Statement * s,d_label_use_entry * fwdref)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 
lookup_label(Statement * s,Identifier * ident=NULL)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 
lookup_bc_label(Statement * s,bc_kind bc)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 
push_break_label(Statement * s)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 
pop_break_label(tree label)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 
push_continue_label(Statement * s)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 
pop_continue_label(tree label)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   /* Generate and set a new continue label for the current unrolled loop.  */
544 
push_unrolled_continue_label(UnrolledLoopStatement * s)545   void push_unrolled_continue_label (UnrolledLoopStatement *s)
546   {
547     this->push_continue_label (s);
548   }
549 
550   /* Finish with the continue label for the unrolled loop.  */
551 
pop_unrolled_continue_label(UnrolledLoopStatement * s)552   void pop_unrolled_continue_label (UnrolledLoopStatement *s)
553   {
554     Statement *stmt = s->getRelatedLabeled ();
555     d_label_entry *ent = d_function_chain->labels->get (stmt);
556     gcc_assert (ent != NULL && ent->bc_label == true);
557 
558     this->pop_continue_label (TREE_VEC_ELT (ent->label, bc_continue));
559 
560     /* Remove the continue label from the label htab, as a new one must be
561        inserted at the end of every unrolled loop.  */
562     ent->label = TREE_VEC_ELT (ent->label, bc_break);
563   }
564 
565   /* Visitor interfaces.  */
566 
567 
568   /* This should be overridden by each statement class.  */
569 
visit(Statement *)570   void visit (Statement *)
571   {
572     gcc_unreachable ();
573   }
574 
575   /* The frontend lowers `scope (exit/failure/success)' statements as
576      try/catch/finally.  At this point, this statement is just an empty
577      placeholder.  Maybe the frontend shouldn't leak these.  */
578 
visit(OnScopeStatement *)579   void visit (OnScopeStatement *)
580   {
581   }
582 
583   /* If statements provide simple conditional execution of statements.  */
584 
visit(IfStatement * s)585   void visit (IfStatement *s)
586   {
587     this->start_scope (level_cond);
588 
589     /* Build the outer 'if' condition, which may produce temporaries
590        requiring scope destruction.  */
591     tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
592 					 s->condition->type);
593     tree ifbody = void_node;
594     tree elsebody = void_node;
595 
596     /* Build the 'then' branch.  */
597     if (s->ifbody)
598       {
599 	push_stmt_list ();
600 	this->build_stmt (s->ifbody);
601 	ifbody = pop_stmt_list ();
602       }
603 
604     /* Now build the 'else' branch, which may have nested 'else if' parts.  */
605     if (s->elsebody)
606       {
607 	push_stmt_list ();
608 	this->build_stmt (s->elsebody);
609 	elsebody = pop_stmt_list ();
610       }
611 
612     /* Wrap up our constructed if condition into a COND_EXPR.  */
613     tree cond = build_vcondition (ifcond, ifbody, elsebody);
614     add_stmt (cond);
615 
616     /* Finish the if-then scope.  */
617     this->finish_scope ();
618   }
619 
620   /* Should there be any `pragma (...)' statements requiring code generation,
621      here would be the place to do it.  For now, all pragmas are handled
622      by the frontend.  */
623 
visit(PragmaStatement *)624   void visit (PragmaStatement *)
625   {
626   }
627 
628   /* The frontend lowers `while (...)' statements as `for (...)' loops.
629      This visitor is not strictly required other than to enforce that
630      these kinds of statements never reach here.  */
631 
visit(WhileStatement *)632   void visit (WhileStatement *)
633   {
634     gcc_unreachable ();
635   }
636 
637   /* Do while statments implement simple loops.  The body is executed, then
638      the condition is evaluated.  */
639 
visit(DoStatement * s)640   void visit (DoStatement *s)
641   {
642     tree lbreak = this->push_break_label (s);
643 
644     this->start_scope (level_loop);
645     if (s->_body)
646       {
647 	tree lcontinue = this->push_continue_label (s);
648 	this->build_stmt (s->_body);
649 	this->pop_continue_label (lcontinue);
650       }
651 
652     /* Build the outer 'while' condition, which may produce temporaries
653        requiring scope destruction.  */
654     tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
655 					   s->condition->type);
656     add_stmt (build_vcondition (exitcond, void_node,
657 				build1 (GOTO_EXPR, void_type_node, lbreak)));
658     TREE_USED (lbreak) = 1;
659 
660     tree body = this->end_scope ();
661     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
662 
663     this->pop_break_label (lbreak);
664   }
665 
666   /* For statements implement loops with initialization, test, and
667      increment clauses.  */
668 
visit(ForStatement * s)669   void visit (ForStatement *s)
670   {
671     tree lbreak = this->push_break_label (s);
672     this->start_scope (level_loop);
673 
674     if (s->_init)
675       this->build_stmt (s->_init);
676 
677     if (s->condition)
678       {
679 	tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
680 					       s->condition->type);
681 	add_stmt (build_vcondition (exitcond, void_node,
682 				    build1 (GOTO_EXPR, void_type_node,
683 					    lbreak)));
684 	TREE_USED (lbreak) = 1;
685       }
686 
687     if (s->_body)
688       {
689 	tree lcontinue = this->push_continue_label (s);
690 	this->build_stmt (s->_body);
691 	this->pop_continue_label (lcontinue);
692       }
693 
694     if (s->increment)
695       {
696 	/* Force side effects?  */
697 	add_stmt (build_expr_dtor (s->increment));
698       }
699 
700     tree body = this->end_scope ();
701     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
702 
703     this->pop_break_label (lbreak);
704   }
705 
706   /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
707      This visitor is not strictly required other than to enforce that
708      these kinds of statements never reach here.  */
709 
visit(ForeachStatement *)710   void visit (ForeachStatement *)
711   {
712     gcc_unreachable ();
713   }
714 
715   /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
716      loops.  This visitor is not strictly required other than to enforce that
717      these kinds of statements never reach here.  */
718 
visit(ForeachRangeStatement *)719   void visit (ForeachRangeStatement *)
720   {
721     gcc_unreachable ();
722   }
723 
724   /* Jump to the associated exit label for the current loop.  If IDENT
725      for the Statement is not null, then the label is user defined.  */
726 
visit(BreakStatement * s)727   void visit (BreakStatement *s)
728   {
729     if (s->ident)
730       {
731 	/* The break label may actually be some levels up.
732 	   eg: on a try/finally wrapping a loop.  */
733 	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
734 	gcc_assert (label != NULL);
735 	Statement *stmt = label->statement->getRelatedLabeled ();
736 	this->do_jump (this->lookup_bc_label (stmt, bc_break));
737       }
738     else
739       this->do_jump (this->break_label_);
740   }
741 
742   /* Jump to the associated continue label for the current loop.  If IDENT
743      for the Statement is not null, then the label is user defined.  */
744 
visit(ContinueStatement * s)745   void visit (ContinueStatement *s)
746   {
747     if (s->ident)
748       {
749 	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
750 	gcc_assert (label != NULL);
751 	this->do_jump (this->lookup_bc_label (label->statement,
752 					      bc_continue));
753       }
754     else
755       this->do_jump (this->continue_label_);
756   }
757 
758   /* A goto statement jumps to the statement identified by the given label.  */
759 
visit(GotoStatement * s)760   void visit (GotoStatement *s)
761   {
762     gcc_assert (s->label->statement != NULL);
763     gcc_assert (s->tf == s->label->statement->tf);
764 
765     /* If no label found, there was an error.  */
766     tree label = this->lookup_label (s->label->statement, s->label->ident);
767     this->do_jump (label);
768 
769     /* Need to error if the goto is jumping into a try or catch block.  */
770     this->check_goto (s, s->label->statement);
771   }
772 
773   /* Statements can be labeled.  A label is an identifier that precedes
774      a statement.  */
775 
visit(LabelStatement * s)776   void visit (LabelStatement *s)
777   {
778     LabelDsymbol *sym;
779 
780     if (this->is_return_label (s->ident))
781       sym = this->func_->returnLabel;
782     else
783       sym = this->func_->searchLabel (s->ident);
784 
785     /* If no label found, there was an error.  */
786     tree label = this->define_label (sym->statement, sym->ident);
787     TREE_USED (label) = 1;
788 
789     this->do_label (label);
790 
791     if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
792       this->build_stmt (this->func_->fensure);
793     else if (s->statement)
794       this->build_stmt (s->statement);
795   }
796 
797   /* A switch statement goes to one of a collection of case statements
798      depending on the value of the switch expression.  */
799 
visit(SwitchStatement * s)800   void visit (SwitchStatement *s)
801   {
802     this->start_scope (level_switch);
803     tree lbreak = this->push_break_label (s);
804 
805     tree condition = build_expr_dtor (s->condition);
806     Type *condtype = s->condition->type->toBasetype ();
807 
808     /* A switch statement on a string gets turned into a library call,
809        which does a binary lookup on list of string cases.  */
810     if (s->condition->type->isString ())
811       {
812 	Type *etype = condtype->nextOf ()->toBasetype ();
813 	libcall_fn libcall;
814 
815 	switch (etype->ty)
816 	  {
817 	  case Tchar:
818 	    libcall = LIBCALL_SWITCH_STRING;
819 	    break;
820 
821 	  case Twchar:
822 	    libcall = LIBCALL_SWITCH_USTRING;
823 	    break;
824 
825 	  case Tdchar:
826 	    libcall = LIBCALL_SWITCH_DSTRING;
827 	    break;
828 
829 	  default:
830 	    ::error ("switch statement value must be an array of "
831 		     "some character type, not %s", etype->toChars ());
832 	    gcc_unreachable ();
833 	  }
834 
835 	/* Apparently the backend is supposed to sort and set the indexes
836 	   on the case array, have to change them to be usable.  */
837 	Type *satype = condtype->sarrayOf (s->cases->dim);
838 	vec<constructor_elt, va_gc> *elms = NULL;
839 
840 	s->cases->sort ();
841 
842 	for (size_t i = 0; i < s->cases->dim; i++)
843 	  {
844 	    CaseStatement *cs = (*s->cases)[i];
845 	    cs->index = i;
846 
847 	    if (cs->exp->op != TOKstring)
848 	      s->error ("case '%s' is not a string", cs->exp->toChars ());
849 	    else
850 	      {
851 		tree exp = build_expr (cs->exp, true);
852 		CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
853 	      }
854 	  }
855 
856 	/* Build static declaration to reference constructor.  */
857 	tree ctor = build_constructor (build_ctype (satype), elms);
858 	tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
859 	TREE_READONLY (decl) = 1;
860 	d_pushdecl (decl);
861 	rest_of_decl_compilation (decl, 1, 0);
862 
863 	/* Pass it as a dynamic array.  */
864 	decl = d_array_value (build_ctype (condtype->arrayOf ()),
865 			      size_int (s->cases->dim),
866 			      build_address (decl));
867 
868 	condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
869       }
870     else if (!condtype->isscalar ())
871       {
872 	error ("cannot handle switch condition of type %s",
873 	       condtype->toChars ());
874 	gcc_unreachable ();
875       }
876 
877     condition = fold (condition);
878 
879     /* Build LABEL_DECLs now so they can be refered to by goto case.
880        Also checking the jump from the switch to the label is allowed.  */
881     if (s->cases)
882       {
883 	for (size_t i = 0; i < s->cases->dim; i++)
884 	  {
885 	    CaseStatement *cs = (*s->cases)[i];
886 	    tree caselabel = this->lookup_label (cs);
887 
888 	    /* Write cases as a series of if-then-else blocks.
889 	       if (condition == case)
890 		 goto caselabel;  */
891 	    if (s->hasVars)
892 	      {
893 		tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
894 				      condition, build_expr_dtor (cs->exp));
895 		tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
896 					   caselabel);
897 		tree cond = build_vcondition (ifcase, ifbody, void_node);
898 		TREE_USED (caselabel) = 1;
899 		LABEL_VARIABLE_CASE (caselabel) = 1;
900 		add_stmt (cond);
901 	      }
902 
903 	    this->check_goto (s, cs);
904 	  }
905 
906 	if (s->sdefault)
907 	  {
908 	    tree defaultlabel = this->lookup_label (s->sdefault);
909 
910 	    /* The default label is the last 'else' block.  */
911 	    if (s->hasVars)
912 	      {
913 		this->do_jump (defaultlabel);
914 		LABEL_VARIABLE_CASE (defaultlabel) = 1;
915 	      }
916 
917 	    this->check_goto (s, s->sdefault);
918 	  }
919       }
920 
921     /* Switch body goes in its own statement list.  */
922     push_stmt_list ();
923     if (s->_body)
924       this->build_stmt (s->_body);
925 
926     tree casebody = pop_stmt_list ();
927 
928     /* Wrap up constructed body into a switch_expr, unless it was
929        converted to an if-then-else expression.  */
930     if (s->hasVars)
931       add_stmt (casebody);
932     else
933       {
934 	tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
935 				  condition, casebody);
936 	add_stmt (switchexpr);
937 	SWITCH_ALL_CASES_P (switchexpr) = 1;
938       }
939 
940     SWITCH_BREAK_LABEL_P (lbreak) = 1;
941 
942     /* If the switch had any 'break' statements, emit the label now.  */
943     this->pop_break_label (lbreak);
944     this->finish_scope ();
945   }
946 
947   /* Declare the case label associated with the current SwitchStatement.  */
948 
visit(CaseStatement * s)949   void visit (CaseStatement *s)
950   {
951     /* Emit the case label.  */
952     tree label = this->define_label (s);
953 
954     if (LABEL_VARIABLE_CASE (label))
955       this->do_label (label);
956     else
957       {
958 	tree casevalue;
959 	if (s->exp->type->isscalar ())
960 	  casevalue = build_expr (s->exp);
961 	else
962 	  casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
963 
964 	tree caselabel = build_case_label (casevalue, NULL_TREE, label);
965 	add_stmt (caselabel);
966       }
967 
968     /* Now do the body.  */
969     if (s->statement)
970       this->build_stmt (s->statement);
971   }
972 
973   /* Declare the default label associated with the current SwitchStatement.  */
974 
visit(DefaultStatement * s)975   void visit (DefaultStatement *s)
976   {
977     /* Emit the default case label.  */
978     tree label = this->define_label (s);
979 
980     if (LABEL_VARIABLE_CASE (label))
981       this->do_label (label);
982     else
983       {
984 	tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
985 	add_stmt (caselabel);
986       }
987 
988     /* Now do the body.  */
989     if (s->statement)
990       this->build_stmt (s->statement);
991   }
992 
993   /* Implements 'goto default' by jumping to the label associated with
994      the DefaultStatement in a switch block.  */
995 
visit(GotoDefaultStatement * s)996   void visit (GotoDefaultStatement *s)
997   {
998     tree label = this->lookup_label (s->sw->sdefault);
999     this->do_jump (label);
1000   }
1001 
1002   /* Implements 'goto case' by jumping to the label associated with the
1003      CaseStatement in a switch block.  */
1004 
visit(GotoCaseStatement * s)1005   void visit (GotoCaseStatement *s)
1006   {
1007     tree label = this->lookup_label (s->cs);
1008     this->do_jump (label);
1009   }
1010 
1011   /* Throw a SwitchError exception, called when a switch statement has
1012      no DefaultStatement, yet none of the cases match.  */
1013 
visit(SwitchErrorStatement * s)1014   void visit (SwitchErrorStatement *s)
1015   {
1016     add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
1017   }
1018 
1019   /* A return statement exits the current function and supplies its return
1020      value, if the return type is not void.  */
1021 
visit(ReturnStatement * s)1022   void visit (ReturnStatement *s)
1023   {
1024     if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
1025       {
1026 	/* Return has no value.  */
1027 	add_stmt (return_expr (NULL_TREE));
1028 	return;
1029       }
1030 
1031     TypeFunction *tf = (TypeFunction *)this->func_->type;
1032     Type *type = this->func_->tintro != NULL
1033       ? this->func_->tintro->nextOf () : tf->nextOf ();
1034 
1035     if ((this->func_->isMain () || this->func_->isCMain ())
1036 	&& type->toBasetype ()->ty == Tvoid)
1037       type = Type::tint32;
1038 
1039     if (this->func_->nrvo_can && this->func_->nrvo_var)
1040       {
1041 	/* Just refer to the DECL_RESULT; this differs from using
1042 	   NULL_TREE in that it indicates that we care about the value
1043 	   of the DECL_RESULT.  */
1044 	tree decl = DECL_RESULT (get_symbol_decl (this->func_));
1045 	add_stmt (return_expr (decl));
1046       }
1047     else
1048       {
1049 	/* Convert for initializing the DECL_RESULT.  */
1050 	tree expr = build_return_dtor (s->exp, type, tf);
1051 	add_stmt (expr);
1052       }
1053   }
1054 
1055   /* Evaluate the enclosed expression, and add it to the statement list.  */
1056 
visit(ExpStatement * s)1057   void visit (ExpStatement *s)
1058   {
1059     if (s->exp)
1060       {
1061 	/* Expression may produce temporaries requiring scope destruction.  */
1062 	tree exp = build_expr_dtor (s->exp);
1063 	add_stmt (exp);
1064       }
1065   }
1066 
1067   /* Evaluate all enclosed statements.  */
1068 
visit(CompoundStatement * s)1069   void visit (CompoundStatement *s)
1070   {
1071     if (s->statements == NULL)
1072       return;
1073 
1074     for (size_t i = 0; i < s->statements->dim; i++)
1075       {
1076 	Statement *statement = (*s->statements)[i];
1077 
1078 	if (statement != NULL)
1079 	  this->build_stmt (statement);
1080       }
1081   }
1082 
1083   /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1084      These are compiled down as a `do ... while (0)', where each unrolled loop
1085      is nested inside and given their own continue label to jump to.  */
1086 
visit(UnrolledLoopStatement * s)1087   void visit (UnrolledLoopStatement *s)
1088   {
1089     if (s->statements == NULL)
1090       return;
1091 
1092     tree lbreak = this->push_break_label (s);
1093     this->start_scope (level_loop);
1094 
1095     for (size_t i = 0; i < s->statements->dim; i++)
1096       {
1097 	Statement *statement = (*s->statements)[i];
1098 
1099 	if (statement != NULL)
1100 	  {
1101 	    this->push_unrolled_continue_label (s);
1102 	    this->build_stmt (statement);
1103 	    this->pop_unrolled_continue_label (s);
1104 	  }
1105       }
1106 
1107     this->do_jump (this->break_label_);
1108 
1109     tree body = this->end_scope ();
1110     add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1111 
1112     this->pop_break_label (lbreak);
1113   }
1114 
1115   /* Start a new scope and visit all nested statements, wrapping
1116      them up into a BIND_EXPR at the end of the scope.  */
1117 
visit(ScopeStatement * s)1118   void visit (ScopeStatement *s)
1119   {
1120     if (s->statement == NULL)
1121       return;
1122 
1123     this->start_scope (level_block);
1124     this->build_stmt (s->statement);
1125     this->finish_scope ();
1126   }
1127 
1128   /* A with statement is a way to simplify repeated references to the same
1129      object, where the handle is either a class or struct instance.  */
1130 
visit(WithStatement * s)1131   void visit (WithStatement *s)
1132   {
1133     this->start_scope (level_with);
1134 
1135     if (s->wthis)
1136       {
1137 	/* Perform initialisation of the 'with' handle.  */
1138 	ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1139 	gcc_assert (ie != NULL);
1140 
1141 	declare_local_var (s->wthis);
1142 	tree init = build_expr_dtor (ie->exp);
1143 	add_stmt (init);
1144       }
1145 
1146     if (s->_body)
1147       this->build_stmt (s->_body);
1148 
1149     this->finish_scope ();
1150   }
1151 
1152   /* Implements 'throw Object'.  Frontend already checks that the object
1153      thrown is a class type, but does not check if it is derived from
1154      Object.  Foreign objects are not currently supported at run-time.  */
1155 
visit(ThrowStatement * s)1156   void visit (ThrowStatement *s)
1157   {
1158     ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1159     InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1160     tree arg = build_expr_dtor (s->exp);
1161 
1162     if (!global.params.useExceptions)
1163       {
1164 	static int warned = 0;
1165 	if (!warned)
1166 	  {
1167 	    error_at (make_location_t (s->loc), "exception handling disabled; "
1168 		      "use %<-fexceptions%> to enable");
1169 	    warned = 1;
1170 	  }
1171       }
1172 
1173     if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1174       error_at (make_location_t (s->loc), "cannot throw C++ classes");
1175     else if (cd->com || (id != NULL && id->com))
1176       error_at (make_location_t (s->loc), "cannot throw COM objects");
1177     else
1178       arg = build_nop (build_ctype (get_object_type ()), arg);
1179 
1180     add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1181   }
1182 
1183   /* Build a try-catch statement, one of the building blocks for exception
1184      handling generated by the frontend.  This is also used to implement
1185      `scope (failure)' statements.  */
1186 
visit(TryCatchStatement * s)1187   void visit (TryCatchStatement *s)
1188   {
1189     this->start_scope (level_try);
1190     if (s->_body)
1191       this->build_stmt (s->_body);
1192 
1193     tree trybody = this->end_scope ();
1194 
1195     /* Try handlers go in their own statement list.  */
1196     push_stmt_list ();
1197 
1198     if (s->catches)
1199       {
1200 	for (size_t i = 0; i < s->catches->dim; i++)
1201 	  {
1202 	    Catch *vcatch = (*s->catches)[i];
1203 
1204 	    this->start_scope (level_catch);
1205 
1206 	    tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1207 	    tree catchtype = build_ctype (vcatch->type);
1208 	    tree object = NULL_TREE;
1209 
1210 	    ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1211 
1212 	    /* Retrieve the internal exception object, which could be for a
1213 	       D or C++ catch handler.  This is different from the generic
1214 	       exception pointer returned from gcc runtime.  */
1215 	    Type *tcatch = vcatch->type->toBasetype ();
1216 	    ClassDeclaration *cd = tcatch->isClassHandle ();
1217 
1218 	    libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1219 	      : LIBCALL_BEGIN_CATCH;
1220 	    object = build_libcall (libcall, vcatch->type, 1, ehptr);
1221 
1222 	    if (vcatch->var)
1223 	      {
1224 		tree var = get_symbol_decl (vcatch->var);
1225 		tree init = build_assign (INIT_EXPR, var, object);
1226 
1227 		declare_local_var (vcatch->var);
1228 		add_stmt (init);
1229 	      }
1230 	    else
1231 	      {
1232 		/* Still need to emit a call to __gdc_begin_catch() to
1233 		   remove the object from the uncaught exceptions list.  */
1234 		add_stmt (object);
1235 	      }
1236 
1237 	    if (vcatch->handler)
1238 	      this->build_stmt (vcatch->handler);
1239 
1240 	    tree catchbody = this->end_scope ();
1241 
1242 	    /* Need to wrap C++ handlers in a try/finally block to signal
1243 	       the end catch callback.  */
1244 	    if (cd->isCPPclass ())
1245 	      {
1246 		tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1247 					       Type::tvoid, 0);
1248 		catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1249 				    catchbody, endcatch);
1250 	      }
1251 
1252 	    add_stmt (build2 (CATCH_EXPR, void_type_node,
1253 			      catchtype, catchbody));
1254 	  }
1255       }
1256 
1257     tree catches = pop_stmt_list ();
1258 
1259     /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1260        statement list, however pop_stmt_list may optimize away the list
1261        if there is only a single catch to push.  */
1262     if (TREE_CODE (catches) != STATEMENT_LIST)
1263       {
1264 	tree stmt_list = alloc_stmt_list ();
1265 	append_to_statement_list_force (catches, &stmt_list);
1266 	catches = stmt_list;
1267       }
1268 
1269     add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1270   }
1271 
1272   /* Build a try-finally statement, one of the building blocks for exception
1273      handling generated by the frontend.  This is also used to implement
1274      `scope (exit)' statements.  */
1275 
visit(TryFinallyStatement * s)1276   void visit (TryFinallyStatement *s)
1277   {
1278     this->start_scope (level_try);
1279     if (s->_body)
1280       this->build_stmt (s->_body);
1281 
1282     tree trybody = this->end_scope ();
1283 
1284     this->start_scope (level_finally);
1285     if (s->finalbody)
1286       this->build_stmt (s->finalbody);
1287 
1288     tree finally = this->end_scope ();
1289 
1290     add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1291   }
1292 
1293   /* The frontend lowers `synchronized (...)' statements as a call to
1294      monitor/critical enter and exit wrapped around try/finally.
1295      This visitor is not strictly required other than to enforce that
1296      these kinds of statements never reach here.  */
1297 
visit(SynchronizedStatement *)1298   void visit (SynchronizedStatement *)
1299   {
1300     gcc_unreachable ();
1301   }
1302 
1303   /* D Inline Assembler is not implemented, as it would require writing
1304      an assembly parser for each supported target.  Instead we leverage
1305      GCC extended assembler using the GccAsmStatement class.  */
1306 
visit(AsmStatement *)1307   void visit (AsmStatement *)
1308   {
1309     sorry ("D inline assembler statements are not supported in GDC.");
1310   }
1311 
1312   /* Build a GCC extended assembler expression, whose components are
1313      an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS.  */
1314 
visit(GccAsmStatement * s)1315   void visit (GccAsmStatement *s)
1316   {
1317     StringExp *insn = (StringExp *)s->insn;
1318     tree outputs = NULL_TREE;
1319     tree inputs = NULL_TREE;
1320     tree clobbers = NULL_TREE;
1321     tree labels = NULL_TREE;
1322 
1323     /* Collect all arguments, which may be input or output operands.  */
1324     if (s->args)
1325       {
1326 	for (size_t i = 0; i < s->args->dim; i++)
1327 	  {
1328 	    Identifier *name = (*s->names)[i];
1329 	    const char *sname = name ? name->toChars () : NULL;
1330 	    tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1331 
1332 	    StringExp *constr = (StringExp *)(*s->constraints)[i];
1333 	    const char *cstring = (const char *)(constr->len
1334 						 ? constr->string : "");
1335 	    tree str = build_string (constr->len, cstring);
1336 
1337 	    Expression *earg = (*s->args)[i];
1338 	    tree val = build_expr (earg);
1339 
1340 	    if (i < s->outputargs)
1341 	      {
1342 		tree arg = build_tree_list (id, str);
1343 		outputs = chainon (outputs, build_tree_list (arg, val));
1344 	      }
1345 	    else
1346 	      {
1347 		tree arg = build_tree_list (id, str);
1348 		inputs = chainon (inputs, build_tree_list (arg, val));
1349 	      }
1350 	  }
1351       }
1352 
1353     /* Collect all clobber arguments.  */
1354     if (s->clobbers)
1355       {
1356 	for (size_t i = 0; i < s->clobbers->dim; i++)
1357 	  {
1358 	    StringExp *clobber = (StringExp *)(*s->clobbers)[i];
1359 	    const char *cstring = (const char *)(clobber->len
1360 						 ? clobber->string : "");
1361 
1362 	    tree val = build_string (clobber->len, cstring);
1363 	    clobbers = chainon (clobbers, build_tree_list (0, val));
1364 	  }
1365       }
1366 
1367     /* Collect all goto labels, these should have been already checked
1368        by the front-end, so pass down the label symbol to the back-end.  */
1369     if (s->labels)
1370       {
1371 	for (size_t i = 0; i < s->labels->dim; i++)
1372 	  {
1373 	    Identifier *ident = (*s->labels)[i];
1374 	    GotoStatement *gs = (*s->gotos)[i];
1375 
1376 	    gcc_assert (gs->label->statement != NULL);
1377 	    gcc_assert (gs->tf == gs->label->statement->tf);
1378 
1379 	    const char *sident = ident->toChars ();
1380 	    tree name = build_string (strlen (sident), sident);
1381 	    tree label = this->lookup_label (gs->label->statement,
1382 					     gs->label->ident);
1383 	    TREE_USED (label) = 1;
1384 
1385 	    labels = chainon (labels, build_tree_list (name, label));
1386 	  }
1387       }
1388 
1389     /* Do some extra validation on all input and output operands.  */
1390     const char *insnstring = (const char *)(insn->len ? insn->string : "");
1391     tree string = build_string (insn->len, insnstring);
1392     string = resolve_asm_operand_names (string, outputs, inputs, labels);
1393 
1394     if (s->args)
1395       {
1396 	unsigned noutputs = s->outputargs;
1397 	unsigned ninputs = (s->args->dim - noutputs);
1398 	const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1399 	bool allows_mem, allows_reg, is_inout;
1400 	size_t i;
1401 	tree t;
1402 
1403 	for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1404 	  {
1405 	    tree output = TREE_VALUE (t);
1406 	    const char *constraint
1407 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1408 
1409 	    oconstraints[i] = constraint;
1410 
1411 	    if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1412 					 &allows_mem, &allows_reg, &is_inout))
1413 	      {
1414 		/* If the output argument is going to end up in memory.  */
1415 		if (!allows_reg)
1416 		  d_mark_addressable (output);
1417 	      }
1418 	    else
1419 	      output = error_mark_node;
1420 
1421 	    TREE_VALUE (t) = output;
1422 	  }
1423 
1424 	for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1425 	  {
1426 	    tree input = TREE_VALUE (t);
1427 	    const char *constraint
1428 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1429 
1430 	    if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1431 					oconstraints, &allows_mem, &allows_reg))
1432 	      {
1433 		/* If the input argument is going to end up in memory.  */
1434 		if (!allows_reg && allows_mem)
1435 		  d_mark_addressable (input);
1436 	      }
1437 	    else
1438 	      input = error_mark_node;
1439 
1440 	    TREE_VALUE (t) = input;
1441 	  }
1442       }
1443 
1444     tree exp = build5 (ASM_EXPR, void_type_node, string,
1445 		       outputs, inputs, clobbers, labels);
1446     SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1447 
1448     /* If the extended syntax was not used, mark the ASM_EXPR as being an
1449        ASM_INPUT expression instead of an ASM_OPERAND with no operands.  */
1450     if (s->args == NULL && s->clobbers == NULL)
1451       ASM_INPUT_P (exp) = 1;
1452 
1453     /* All asm statements are assumed to have a side effect.  As a future
1454        optimization, this could be unset when building in release mode.  */
1455     ASM_VOLATILE_P (exp) = 1;
1456 
1457     /* If the function has been annotated with 'pragma(inline)', then mark
1458        the asm expression as being inline as well.  */
1459     if (this->func_->inlining == PINLINEalways)
1460       ASM_INLINE_P (exp) = 1;
1461 
1462     add_stmt (exp);
1463   }
1464 
1465   /* Import symbols from another module.  */
1466 
visit(ImportStatement * s)1467   void visit (ImportStatement *s)
1468   {
1469     if (s->imports == NULL)
1470       return;
1471 
1472     for (size_t i = 0; i < s->imports->dim; i++)
1473       {
1474 	Dsymbol *dsym = (*s->imports)[i];
1475 
1476 	if (dsym != NULL)
1477 	  build_decl_tree (dsym);
1478       }
1479   }
1480 };
1481 
1482 /* Main entry point for the IRVisitor interface to generate
1483    code for the body of function FD.  */
1484 
1485 void
build_function_body(FuncDeclaration * fd)1486 build_function_body (FuncDeclaration *fd)
1487 {
1488   IRVisitor v = IRVisitor (fd);
1489   location_t saved_location = input_location;
1490   input_location = make_location_t (fd->loc);
1491   v.build_stmt (fd->fbody);
1492   input_location = saved_location;
1493 }
1494