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