toir.cc (pop_label): Only queue labels in a vector.
[official-gcc.git] / gcc / d / toir.cc
blob4c4d639d3b68ecd6c223e3dab7b71928e0ae3c7e
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2 Copyright (C) 2006-2019 Free Software Foundation, Inc.
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.
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.
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/>. */
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
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"
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"
39 #include "d-tree.h"
42 /* Update data for defined and undefined labels when leaving a scope. */
44 bool
45 pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl)
47 binding_level *obl = bl->level_chain;
49 if (ent->level == bl)
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;
56 ent->level = obl;
58 else if (ent->fwdrefs)
60 for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next)
61 ref->level = obl;
64 return true;
67 /* At the end of a function, all labels declared within the function
68 go out of scope. Queue them in LABELS. */
70 bool
71 pop_label (Statement * const &, d_label_entry *ent, vec<tree> &labels)
73 if (!ent->bc_label)
75 /* Put the labels into the "variables" of the top-level block,
76 so debugger can see them. */
77 if (DECL_NAME (ent->label))
79 gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE);
80 labels.safe_push (ent->label);
84 return true;
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. */
92 void
93 push_binding_level (level_kind kind)
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;
100 current_binding_level = new_level;
103 static int
104 cmp_labels (const void *p1, const void *p2)
106 const tree *l1 = (const tree *)p1;
107 const tree *l2 = (const tree *)p2;
108 return DECL_UID (*l1) - DECL_UID (*l2);
111 tree
112 pop_binding_level (void)
114 binding_level *level = current_binding_level;
115 current_binding_level = level->level_chain;
117 tree block = make_node (BLOCK);
118 BLOCK_VARS (block) = level->names;
119 BLOCK_SUBBLOCKS (block) = level->blocks;
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;
125 if (level->kind == level_function)
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;
131 /* Pop all the labels declared in the function. */
132 if (d_function_chain->labels)
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)
140 DECL_CHAIN (labels[i]) = BLOCK_VARS (block);
141 BLOCK_VARS (block) = labels[i];
145 else
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)
151 language_function *f = d_function_chain;
152 f->labels->traverse<binding_level *, &pop_binding_label> (level);
155 current_binding_level->blocks
156 = block_chainon (current_binding_level->blocks, block);
159 TREE_USED (block) = 1;
160 return block;
163 /* Create an empty statement tree rooted at T. */
165 void
166 push_stmt_list (void)
168 tree t = alloc_stmt_list ();
169 vec_safe_push (d_function_chain->stmt_list, t);
170 d_keep (t);
173 /* Finish the statement tree rooted at T. */
175 tree
176 pop_stmt_list (void)
178 tree t = d_function_chain->stmt_list->pop ();
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))
186 /* If the statement list contained exactly one statement, then extract
187 it immediately. */
188 tree_stmt_iterator i = tsi_start (t);
190 if (tsi_one_before_end_p (i))
192 tree u = tsi_stmt (i);
193 tsi_delink (&i);
194 free_stmt_list (t);
195 t = u;
199 return t;
202 /* T is an expression statement. Add it to the statement-tree. */
204 void
205 add_stmt (tree t)
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;
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;
217 if (TREE_CODE (t) == COMPOUND_EXPR)
219 /* Push out each comma expressions as separate statements. */
220 add_stmt (TREE_OPERAND (t, 0));
221 add_stmt (TREE_OPERAND (t, 1));
223 else
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;
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);
235 tree stmt_list = d_function_chain->stmt_list->last ();
236 append_to_statement_list_force (t, &stmt_list);
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. */
247 class IRVisitor : public Visitor
249 using Visitor::visit;
251 FuncDeclaration *func_;
253 /* Stack of labels which are targets for "break" and "continue",
254 linked through TREE_CHAIN. */
255 tree break_label_;
256 tree continue_label_;
258 public:
259 IRVisitor (FuncDeclaration *fd)
261 this->func_ = fd;
262 this->break_label_ = NULL_TREE;
263 this->continue_label_ = NULL_TREE;
266 /* Helper for generating code for the statement AST class S.
267 Sets up the location of the statement before lowering. */
269 void build_stmt (Statement *s)
271 location_t saved_location = input_location;
272 input_location = make_location_t (s->loc);
273 s->accept (this);
274 input_location = saved_location;
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. */
281 void start_scope (level_kind kind)
283 push_binding_level (kind);
284 push_stmt_list ();
287 /* Leave scope pushed by start_scope, returning a new bind_expr if
288 any variables where declared in the scope. */
290 tree end_scope (void)
292 tree block = pop_binding_level ();
293 tree body = pop_stmt_list ();
295 if (! BLOCK_VARS (block))
296 return body;
298 tree bind = build3 (BIND_EXPR, void_type_node,
299 BLOCK_VARS (block), body, block);
300 TREE_SIDE_EFFECTS (bind) = 1;
301 return bind;
304 /* Like end_scope, but also push it into the outer statement-tree. */
306 void finish_scope (void)
308 tree scope = this->end_scope ();
309 add_stmt (scope);
312 /* Return TRUE if IDENT is the current function return label. */
314 bool is_return_label (Identifier *ident)
316 if (this->func_->returnLabel)
317 return this->func_->returnLabel->ident == ident;
319 return false;
322 /* Define a label, specifying the location in the source file.
323 Return the LABEL_DECL node for the label. */
325 tree define_label (Statement *s, Identifier *ident = NULL)
327 tree label = this->lookup_label (s, ident);
328 gcc_assert (DECL_INITIAL (label) == NULL_TREE);
330 d_label_entry *ent = d_function_chain->labels->get (s);
331 gcc_assert (ent != NULL);
333 /* Mark label as having been defined. */
334 DECL_INITIAL (label) = error_mark_node;
336 ent->level = current_binding_level;
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;
342 return label;
345 /* Emit a LABEL expression. */
347 void do_label (tree label)
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));
357 /* Emit a goto expression to LABEL. */
359 void do_jump (tree label)
361 add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
362 TREE_USED (label) = 1;
365 /* Check that a new jump at statement scope FROM to a label declared in
366 statement scope TO is valid. */
368 void check_goto (Statement *from, Statement *to)
370 d_label_entry *ent = d_function_chain->labels->get (to);
371 gcc_assert (ent != NULL);
373 /* If the label hasn't been defined yet, defer checking. */
374 if (! DECL_INITIAL (ent->label))
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;
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");
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. */
396 void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
398 for (binding_level *b = current_binding_level; b ; b = b->level_chain)
400 if (b == fwdref->level)
401 break;
403 if (b->kind == level_try || b->kind == level_catch)
405 location_t location;
407 if (s->isLabelStatement ())
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");
415 else if (s->isCaseStatement ())
417 location = make_location_t (s->loc);
418 error_at (location, "case cannot be in different "
419 "%<try%> block level from %<switch%>");
421 else if (s->isDefaultStatement ())
423 location = make_location_t (s->loc);
424 error_at (location, "default cannot be in different "
425 "%<try%> block level from %<switch%>");
427 else
428 gcc_unreachable ();
433 /* Get or build LABEL_DECL using the IDENT and statement block S given. */
435 tree lookup_label (Statement *s, Identifier *ident = NULL)
437 /* You can't use labels at global scope. */
438 if (d_function_chain == NULL)
440 error ("label %s referenced outside of any function",
441 ident ? ident->toChars () : "(unnamed)");
442 return NULL_TREE;
445 /* Create the label htab for the function on demand. */
446 if (!d_function_chain->labels)
448 d_function_chain->labels
449 = hash_map<Statement *, d_label_entry>::create_ggc (13);
452 d_label_entry *ent = d_function_chain->labels->get (s);
453 if (ent != NULL)
454 return ent->label;
455 else
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;
463 /* Create new empty slot. */
464 ent = ggc_cleared_alloc<d_label_entry> ();
465 ent->statement = s;
466 ent->label = decl;
468 bool existed = d_function_chain->labels->put (s, *ent);
469 gcc_assert (!existed);
471 return decl;
475 /* Get the LABEL_DECL to represent a break or continue for the
476 statement S given. BC indicates which. */
478 tree lookup_bc_label (Statement *s, bc_kind bc)
480 tree vec = this->lookup_label (s);
482 /* The break and continue labels are put into a TREE_VEC. */
483 if (TREE_CODE (vec) == LABEL_DECL)
485 d_label_entry *ent = d_function_chain->labels->get (s);
486 gcc_assert (ent != NULL);
488 vec = make_tree_vec (2);
489 TREE_VEC_ELT (vec, bc_break) = ent->label;
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;
498 ent->label = vec;
499 ent->bc_label = true;
502 return TREE_VEC_ELT (vec, bc);
505 /* Set and return the current break label for the current block. */
507 tree push_break_label (Statement *s)
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;
515 /* Finish with the current break label. */
517 void pop_break_label (tree label)
519 gcc_assert (this->break_label_ == label);
520 this->break_label_ = DECL_CHAIN (this->break_label_);
521 this->do_label (label);
524 /* Set and return the continue label for the current block. */
526 tree push_continue_label (Statement *s)
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;
534 /* Finish with the current continue label. */
536 void pop_continue_label (tree label)
538 gcc_assert (this->continue_label_ == label);
539 this->continue_label_ = DECL_CHAIN (this->continue_label_);
540 this->do_label (label);
543 /* Visitor interfaces. */
546 /* This should be overridden by each statement class. */
548 void visit (Statement *)
550 gcc_unreachable ();
553 /* The frontend lowers `scope (exit/failure/success)' statements as
554 try/catch/finally. At this point, this statement is just an empty
555 placeholder. Maybe the frontend shouldn't leak these. */
557 void visit (OnScopeStatement *)
561 /* If statements provide simple conditional execution of statements. */
563 void visit (IfStatement *s)
565 this->start_scope (level_cond);
567 /* Build the outer 'if' condition, which may produce temporaries
568 requiring scope destruction. */
569 tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
570 s->condition->type);
571 tree ifbody = void_node;
572 tree elsebody = void_node;
574 /* Build the 'then' branch. */
575 if (s->ifbody)
577 push_stmt_list ();
578 this->build_stmt (s->ifbody);
579 ifbody = pop_stmt_list ();
582 /* Now build the 'else' branch, which may have nested 'else if' parts. */
583 if (s->elsebody)
585 push_stmt_list ();
586 this->build_stmt (s->elsebody);
587 elsebody = pop_stmt_list ();
590 /* Wrap up our constructed if condition into a COND_EXPR. */
591 tree cond = build_vcondition (ifcond, ifbody, elsebody);
592 add_stmt (cond);
594 /* Finish the if-then scope. */
595 this->finish_scope ();
598 /* Should there be any `pragma (...)' statements requiring code generation,
599 here would be the place to do it. For now, all pragmas are handled
600 by the frontend. */
602 void visit (PragmaStatement *)
606 /* The frontend lowers `while (...)' statements as `for (...)' loops.
607 This visitor is not strictly required other than to enforce that
608 these kinds of statements never reach here. */
610 void visit (WhileStatement *)
612 gcc_unreachable ();
615 /* Do while statments implement simple loops. The body is executed, then
616 the condition is evaluated. */
618 void visit (DoStatement *s)
620 tree lbreak = this->push_break_label (s);
622 this->start_scope (level_loop);
623 if (s->_body)
625 tree lcontinue = this->push_continue_label (s);
626 this->build_stmt (s->_body);
627 this->pop_continue_label (lcontinue);
630 /* Build the outer 'while' condition, which may produce temporaries
631 requiring scope destruction. */
632 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
633 s->condition->type);
634 add_stmt (build_vcondition (exitcond, void_node,
635 build1 (GOTO_EXPR, void_type_node, lbreak)));
636 TREE_USED (lbreak) = 1;
638 tree body = this->end_scope ();
639 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
641 this->pop_break_label (lbreak);
644 /* For statements implement loops with initialization, test, and
645 increment clauses. */
647 void visit (ForStatement *s)
649 tree lbreak = this->push_break_label (s);
650 this->start_scope (level_loop);
652 if (s->_init)
653 this->build_stmt (s->_init);
655 if (s->condition)
657 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
658 s->condition->type);
659 add_stmt (build_vcondition (exitcond, void_node,
660 build1 (GOTO_EXPR, void_type_node,
661 lbreak)));
662 TREE_USED (lbreak) = 1;
665 if (s->_body)
667 tree lcontinue = this->push_continue_label (s);
668 this->build_stmt (s->_body);
669 this->pop_continue_label (lcontinue);
672 if (s->increment)
674 /* Force side effects? */
675 add_stmt (build_expr_dtor (s->increment));
678 tree body = this->end_scope ();
679 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
681 this->pop_break_label (lbreak);
684 /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
685 This visitor is not strictly required other than to enforce that
686 these kinds of statements never reach here. */
688 void visit (ForeachStatement *)
690 gcc_unreachable ();
693 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
694 loops. This visitor is not strictly required other than to enforce that
695 these kinds of statements never reach here. */
697 void visit (ForeachRangeStatement *)
699 gcc_unreachable ();
702 /* Jump to the associated exit label for the current loop. If IDENT
703 for the Statement is not null, then the label is user defined. */
705 void visit (BreakStatement *s)
707 if (s->ident)
709 /* The break label may actually be some levels up.
710 eg: on a try/finally wrapping a loop. */
711 LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
712 gcc_assert (label != NULL);
713 Statement *stmt = label->statement->getRelatedLabeled ();
714 this->do_jump (this->lookup_bc_label (stmt, bc_break));
716 else
717 this->do_jump (this->break_label_);
720 /* Jump to the associated continue label for the current loop. If IDENT
721 for the Statement is not null, then the label is user defined. */
723 void visit (ContinueStatement *s)
725 if (s->ident)
727 LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
728 gcc_assert (label != NULL);
729 this->do_jump (this->lookup_bc_label (label->statement,
730 bc_continue));
732 else
733 this->do_jump (this->continue_label_);
736 /* A goto statement jumps to the statement identified by the given label. */
738 void visit (GotoStatement *s)
740 gcc_assert (s->label->statement != NULL);
741 gcc_assert (s->tf == s->label->statement->tf);
743 /* If no label found, there was an error. */
744 tree label = this->lookup_label (s->label->statement, s->label->ident);
745 this->do_jump (label);
747 /* Need to error if the goto is jumping into a try or catch block. */
748 this->check_goto (s, s->label->statement);
751 /* Statements can be labeled. A label is an identifier that precedes
752 a statement. */
754 void visit (LabelStatement *s)
756 LabelDsymbol *sym;
758 if (this->is_return_label (s->ident))
759 sym = this->func_->returnLabel;
760 else
761 sym = this->func_->searchLabel (s->ident);
763 /* If no label found, there was an error. */
764 tree label = this->define_label (sym->statement, sym->ident);
765 TREE_USED (label) = 1;
767 this->do_label (label);
769 if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
770 this->build_stmt (this->func_->fensure);
771 else if (s->statement)
772 this->build_stmt (s->statement);
775 /* A switch statement goes to one of a collection of case statements
776 depending on the value of the switch expression. */
778 void visit (SwitchStatement *s)
780 this->start_scope (level_switch);
781 tree lbreak = this->push_break_label (s);
783 tree condition = build_expr_dtor (s->condition);
784 Type *condtype = s->condition->type->toBasetype ();
786 /* A switch statement on a string gets turned into a library call,
787 which does a binary lookup on list of string cases. */
788 if (s->condition->type->isString ())
790 Type *etype = condtype->nextOf ()->toBasetype ();
791 libcall_fn libcall;
793 switch (etype->ty)
795 case Tchar:
796 libcall = LIBCALL_SWITCH_STRING;
797 break;
799 case Twchar:
800 libcall = LIBCALL_SWITCH_USTRING;
801 break;
803 case Tdchar:
804 libcall = LIBCALL_SWITCH_DSTRING;
805 break;
807 default:
808 ::error ("switch statement value must be an array of "
809 "some character type, not %s", etype->toChars ());
810 gcc_unreachable ();
813 /* Apparently the backend is supposed to sort and set the indexes
814 on the case array, have to change them to be usable. */
815 Type *satype = condtype->sarrayOf (s->cases->dim);
816 vec<constructor_elt, va_gc> *elms = NULL;
818 s->cases->sort ();
820 for (size_t i = 0; i < s->cases->dim; i++)
822 CaseStatement *cs = (*s->cases)[i];
823 cs->index = i;
825 if (cs->exp->op != TOKstring)
826 s->error ("case '%s' is not a string", cs->exp->toChars ());
827 else
829 tree exp = build_expr (cs->exp, true);
830 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
834 /* Build static declaration to reference constructor. */
835 tree ctor = build_constructor (build_ctype (satype), elms);
836 tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
837 TREE_READONLY (decl) = 1;
838 d_pushdecl (decl);
839 rest_of_decl_compilation (decl, 1, 0);
841 /* Pass it as a dynamic array. */
842 decl = d_array_value (build_ctype (condtype->arrayOf ()),
843 size_int (s->cases->dim),
844 build_address (decl));
846 condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
848 else if (!condtype->isscalar ())
850 error ("cannot handle switch condition of type %s",
851 condtype->toChars ());
852 gcc_unreachable ();
855 condition = fold (condition);
857 /* Build LABEL_DECLs now so they can be refered to by goto case.
858 Also checking the jump from the switch to the label is allowed. */
859 if (s->cases)
861 for (size_t i = 0; i < s->cases->dim; i++)
863 CaseStatement *cs = (*s->cases)[i];
864 tree caselabel = this->lookup_label (cs);
866 /* Write cases as a series of if-then-else blocks.
867 if (condition == case)
868 goto caselabel; */
869 if (s->hasVars)
871 tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
872 condition, build_expr_dtor (cs->exp));
873 tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
874 caselabel);
875 tree cond = build_vcondition (ifcase, ifbody, void_node);
876 TREE_USED (caselabel) = 1;
877 LABEL_VARIABLE_CASE (caselabel) = 1;
878 add_stmt (cond);
881 this->check_goto (s, cs);
884 if (s->sdefault)
886 tree defaultlabel = this->lookup_label (s->sdefault);
888 /* The default label is the last 'else' block. */
889 if (s->hasVars)
891 this->do_jump (defaultlabel);
892 LABEL_VARIABLE_CASE (defaultlabel) = 1;
895 this->check_goto (s, s->sdefault);
899 /* Switch body goes in its own statement list. */
900 push_stmt_list ();
901 if (s->_body)
902 this->build_stmt (s->_body);
904 tree casebody = pop_stmt_list ();
906 /* Wrap up constructed body into a switch_expr, unless it was
907 converted to an if-then-else expression. */
908 if (s->hasVars)
909 add_stmt (casebody);
910 else
912 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
913 condition, casebody);
914 add_stmt (switchexpr);
915 SWITCH_ALL_CASES_P (switchexpr) = 1;
918 SWITCH_BREAK_LABEL_P (lbreak) = 1;
920 /* If the switch had any 'break' statements, emit the label now. */
921 this->pop_break_label (lbreak);
922 this->finish_scope ();
925 /* Declare the case label associated with the current SwitchStatement. */
927 void visit (CaseStatement *s)
929 /* Emit the case label. */
930 tree label = this->define_label (s);
932 if (LABEL_VARIABLE_CASE (label))
933 this->do_label (label);
934 else
936 tree casevalue;
937 if (s->exp->type->isscalar ())
938 casevalue = build_expr (s->exp);
939 else
940 casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
942 tree caselabel = build_case_label (casevalue, NULL_TREE, label);
943 add_stmt (caselabel);
946 /* Now do the body. */
947 if (s->statement)
948 this->build_stmt (s->statement);
951 /* Declare the default label associated with the current SwitchStatement. */
953 void visit (DefaultStatement *s)
955 /* Emit the default case label. */
956 tree label = this->define_label (s);
958 if (LABEL_VARIABLE_CASE (label))
959 this->do_label (label);
960 else
962 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
963 add_stmt (caselabel);
966 /* Now do the body. */
967 if (s->statement)
968 this->build_stmt (s->statement);
971 /* Implements 'goto default' by jumping to the label associated with
972 the DefaultStatement in a switch block. */
974 void visit (GotoDefaultStatement *s)
976 tree label = this->lookup_label (s->sw->sdefault);
977 this->do_jump (label);
980 /* Implements 'goto case' by jumping to the label associated with the
981 CaseStatement in a switch block. */
983 void visit (GotoCaseStatement *s)
985 tree label = this->lookup_label (s->cs);
986 this->do_jump (label);
989 /* Throw a SwitchError exception, called when a switch statement has
990 no DefaultStatement, yet none of the cases match. */
992 void visit (SwitchErrorStatement *s)
994 add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
997 /* A return statement exits the current function and supplies its return
998 value, if the return type is not void. */
1000 void visit (ReturnStatement *s)
1002 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
1004 /* Return has no value. */
1005 add_stmt (return_expr (NULL_TREE));
1006 return;
1009 TypeFunction *tf = (TypeFunction *)this->func_->type;
1010 Type *type = this->func_->tintro != NULL
1011 ? this->func_->tintro->nextOf () : tf->nextOf ();
1013 if ((this->func_->isMain () || this->func_->isCMain ())
1014 && type->toBasetype ()->ty == Tvoid)
1015 type = Type::tint32;
1017 if (this->func_->nrvo_can && this->func_->nrvo_var)
1019 /* Just refer to the DECL_RESULT; this differs from using
1020 NULL_TREE in that it indicates that we care about the value
1021 of the DECL_RESULT. */
1022 tree decl = DECL_RESULT (get_symbol_decl (this->func_));
1023 add_stmt (return_expr (decl));
1025 else
1027 /* Convert for initializing the DECL_RESULT. */
1028 tree expr = build_return_dtor (s->exp, type, tf);
1029 add_stmt (expr);
1033 /* Evaluate the enclosed expression, and add it to the statement list. */
1035 void visit (ExpStatement *s)
1037 if (s->exp)
1039 /* Expression may produce temporaries requiring scope destruction. */
1040 tree exp = build_expr_dtor (s->exp);
1041 add_stmt (exp);
1045 /* Evaluate all enclosed statements. */
1047 void visit (CompoundStatement *s)
1049 if (s->statements == NULL)
1050 return;
1052 for (size_t i = 0; i < s->statements->dim; i++)
1054 Statement *statement = (*s->statements)[i];
1056 if (statement != NULL)
1057 this->build_stmt (statement);
1061 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1062 These are compiled down as a `do ... while (0)', where each unrolled loop
1063 is nested inside and given their own continue label to jump to. */
1065 void visit (UnrolledLoopStatement *s)
1067 if (s->statements == NULL)
1068 return;
1070 tree lbreak = this->push_break_label (s);
1071 this->start_scope (level_loop);
1073 for (size_t i = 0; i < s->statements->dim; i++)
1075 Statement *statement = (*s->statements)[i];
1077 if (statement != NULL)
1079 tree lcontinue = this->push_continue_label (statement);
1080 this->build_stmt (statement);
1081 this->pop_continue_label (lcontinue);
1085 this->do_jump (this->break_label_);
1087 tree body = this->end_scope ();
1088 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1090 this->pop_break_label (lbreak);
1093 /* Start a new scope and visit all nested statements, wrapping
1094 them up into a BIND_EXPR at the end of the scope. */
1096 void visit (ScopeStatement *s)
1098 if (s->statement == NULL)
1099 return;
1101 this->start_scope (level_block);
1102 this->build_stmt (s->statement);
1103 this->finish_scope ();
1106 /* A with statement is a way to simplify repeated references to the same
1107 object, where the handle is either a class or struct instance. */
1109 void visit (WithStatement *s)
1111 this->start_scope (level_with);
1113 if (s->wthis)
1115 /* Perform initialisation of the 'with' handle. */
1116 ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1117 gcc_assert (ie != NULL);
1119 declare_local_var (s->wthis);
1120 tree init = build_expr_dtor (ie->exp);
1121 add_stmt (init);
1124 if (s->_body)
1125 this->build_stmt (s->_body);
1127 this->finish_scope ();
1130 /* Implements 'throw Object'. Frontend already checks that the object
1131 thrown is a class type, but does not check if it is derived from
1132 Object. Foreign objects are not currently supported at run-time. */
1134 void visit (ThrowStatement *s)
1136 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1137 InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1138 tree arg = build_expr_dtor (s->exp);
1140 if (!global.params.useExceptions)
1142 static int warned = 0;
1143 if (!warned)
1145 error_at (make_location_t (s->loc), "exception handling disabled; "
1146 "use %<-fexceptions%> to enable");
1147 warned = 1;
1151 if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1152 error_at (make_location_t (s->loc), "cannot throw C++ classes");
1153 else if (cd->com || (id != NULL && id->com))
1154 error_at (make_location_t (s->loc), "cannot throw COM objects");
1155 else
1156 arg = build_nop (build_ctype (get_object_type ()), arg);
1158 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1161 /* Build a try-catch statement, one of the building blocks for exception
1162 handling generated by the frontend. This is also used to implement
1163 `scope (failure)' statements. */
1165 void visit (TryCatchStatement *s)
1167 this->start_scope (level_try);
1168 if (s->_body)
1169 this->build_stmt (s->_body);
1171 tree trybody = this->end_scope ();
1173 /* Try handlers go in their own statement list. */
1174 push_stmt_list ();
1176 if (s->catches)
1178 for (size_t i = 0; i < s->catches->dim; i++)
1180 Catch *vcatch = (*s->catches)[i];
1182 this->start_scope (level_catch);
1184 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1185 tree catchtype = build_ctype (vcatch->type);
1186 tree object = NULL_TREE;
1188 ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1190 /* Retrieve the internal exception object, which could be for a
1191 D or C++ catch handler. This is different from the generic
1192 exception pointer returned from gcc runtime. */
1193 Type *tcatch = vcatch->type->toBasetype ();
1194 ClassDeclaration *cd = tcatch->isClassHandle ();
1196 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1197 : LIBCALL_BEGIN_CATCH;
1198 object = build_libcall (libcall, vcatch->type, 1, ehptr);
1200 if (vcatch->var)
1202 tree var = get_symbol_decl (vcatch->var);
1203 tree init = build_assign (INIT_EXPR, var, object);
1205 declare_local_var (vcatch->var);
1206 add_stmt (init);
1208 else
1210 /* Still need to emit a call to __gdc_begin_catch() to
1211 remove the object from the uncaught exceptions list. */
1212 add_stmt (object);
1215 if (vcatch->handler)
1216 this->build_stmt (vcatch->handler);
1218 tree catchbody = this->end_scope ();
1220 /* Need to wrap C++ handlers in a try/finally block to signal
1221 the end catch callback. */
1222 if (cd->isCPPclass ())
1224 tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1225 Type::tvoid, 0);
1226 catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1227 catchbody, endcatch);
1230 add_stmt (build2 (CATCH_EXPR, void_type_node,
1231 catchtype, catchbody));
1235 tree catches = pop_stmt_list ();
1237 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1238 statement list, however pop_stmt_list may optimize away the list
1239 if there is only a single catch to push. */
1240 if (TREE_CODE (catches) != STATEMENT_LIST)
1242 tree stmt_list = alloc_stmt_list ();
1243 append_to_statement_list_force (catches, &stmt_list);
1244 catches = stmt_list;
1247 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1250 /* Build a try-finally statement, one of the building blocks for exception
1251 handling generated by the frontend. This is also used to implement
1252 `scope (exit)' statements. */
1254 void visit (TryFinallyStatement *s)
1256 this->start_scope (level_try);
1257 if (s->_body)
1258 this->build_stmt (s->_body);
1260 tree trybody = this->end_scope ();
1262 this->start_scope (level_finally);
1263 if (s->finalbody)
1264 this->build_stmt (s->finalbody);
1266 tree finally = this->end_scope ();
1268 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1271 /* The frontend lowers `synchronized (...)' statements as a call to
1272 monitor/critical enter and exit wrapped around try/finally.
1273 This visitor is not strictly required other than to enforce that
1274 these kinds of statements never reach here. */
1276 void visit (SynchronizedStatement *)
1278 gcc_unreachable ();
1281 /* D Inline Assembler is not implemented, as it would require writing
1282 an assembly parser for each supported target. Instead we leverage
1283 GCC extended assembler using the GccAsmStatement class. */
1285 void visit (AsmStatement *)
1287 sorry ("D inline assembler statements are not supported in GDC.");
1290 /* Build a GCC extended assembler expression, whose components are
1291 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1293 void visit (GccAsmStatement *s)
1295 StringExp *insn = (StringExp *)s->insn;
1296 tree outputs = NULL_TREE;
1297 tree inputs = NULL_TREE;
1298 tree clobbers = NULL_TREE;
1299 tree labels = NULL_TREE;
1301 /* Collect all arguments, which may be input or output operands. */
1302 if (s->args)
1304 for (size_t i = 0; i < s->args->dim; i++)
1306 Identifier *name = (*s->names)[i];
1307 const char *sname = name ? name->toChars () : NULL;
1308 tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1310 StringExp *constr = (StringExp *)(*s->constraints)[i];
1311 const char *cstring = (const char *)(constr->len
1312 ? constr->string : "");
1313 tree str = build_string (constr->len, cstring);
1315 Expression *earg = (*s->args)[i];
1316 tree val = build_expr (earg);
1318 if (i < s->outputargs)
1320 tree arg = build_tree_list (id, str);
1321 outputs = chainon (outputs, build_tree_list (arg, val));
1323 else
1325 tree arg = build_tree_list (id, str);
1326 inputs = chainon (inputs, build_tree_list (arg, val));
1331 /* Collect all clobber arguments. */
1332 if (s->clobbers)
1334 for (size_t i = 0; i < s->clobbers->dim; i++)
1336 StringExp *clobber = (StringExp *)(*s->clobbers)[i];
1337 const char *cstring = (const char *)(clobber->len
1338 ? clobber->string : "");
1340 tree val = build_string (clobber->len, cstring);
1341 clobbers = chainon (clobbers, build_tree_list (0, val));
1345 /* Collect all goto labels, these should have been already checked
1346 by the front-end, so pass down the label symbol to the back-end. */
1347 if (s->labels)
1349 for (size_t i = 0; i < s->labels->dim; i++)
1351 Identifier *ident = (*s->labels)[i];
1352 GotoStatement *gs = (*s->gotos)[i];
1354 gcc_assert (gs->label->statement != NULL);
1355 gcc_assert (gs->tf == gs->label->statement->tf);
1357 const char *sident = ident->toChars ();
1358 tree name = build_string (strlen (sident), sident);
1359 tree label = this->lookup_label (gs->label->statement,
1360 gs->label->ident);
1361 TREE_USED (label) = 1;
1363 labels = chainon (labels, build_tree_list (name, label));
1367 /* Do some extra validation on all input and output operands. */
1368 const char *insnstring = (const char *)(insn->len ? insn->string : "");
1369 tree string = build_string (insn->len, insnstring);
1370 string = resolve_asm_operand_names (string, outputs, inputs, labels);
1372 if (s->args)
1374 unsigned noutputs = s->outputargs;
1375 unsigned ninputs = (s->args->dim - noutputs);
1376 const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1377 bool allows_mem, allows_reg, is_inout;
1378 size_t i;
1379 tree t;
1381 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1383 tree output = TREE_VALUE (t);
1384 const char *constraint
1385 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1387 oconstraints[i] = constraint;
1389 if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1390 &allows_mem, &allows_reg, &is_inout))
1392 /* If the output argument is going to end up in memory. */
1393 if (!allows_reg)
1394 d_mark_addressable (output);
1396 else
1397 output = error_mark_node;
1399 TREE_VALUE (t) = output;
1402 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1404 tree input = TREE_VALUE (t);
1405 const char *constraint
1406 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1408 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1409 oconstraints, &allows_mem, &allows_reg))
1411 /* If the input argument is going to end up in memory. */
1412 if (!allows_reg && allows_mem)
1413 d_mark_addressable (input);
1415 else
1416 input = error_mark_node;
1418 TREE_VALUE (t) = input;
1422 tree exp = build5 (ASM_EXPR, void_type_node, string,
1423 outputs, inputs, clobbers, labels);
1424 SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1426 /* If the extended syntax was not used, mark the ASM_EXPR. */
1427 if (s->args == NULL && s->clobbers == NULL)
1428 ASM_INPUT_P (exp) = 1;
1430 /* Asm statements are treated as volatile unless 'pure'. */
1431 ASM_VOLATILE_P (exp) = !(s->stc & STCpure);
1433 add_stmt (exp);
1436 /* Import symbols from another module. */
1438 void visit (ImportStatement *s)
1440 if (s->imports == NULL)
1441 return;
1443 for (size_t i = 0; i < s->imports->dim; i++)
1445 Dsymbol *dsym = (*s->imports)[i];
1447 if (dsym != NULL)
1448 build_decl_tree (dsym);
1453 /* Main entry point for the IRVisitor interface to generate
1454 code for the body of function FD. */
1456 void
1457 build_function_body (FuncDeclaration *fd)
1459 IRVisitor v = IRVisitor (fd);
1460 location_t saved_location = input_location;
1461 input_location = make_location_t (fd->loc);
1462 v.build_stmt (fd->fbody);
1463 input_location = saved_location;