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