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