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