6aaf10bf4e4b599539b10befa174dcaf771d5ea4
[gcc.git] / gcc / d / toir.cc
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2 Copyright (C) 2006-2020 Free Software Foundation, Inc.
3
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3. If not see
16 <http://www.gnu.org/licenses/>. */
17
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
21
22 #include "dmd/aggregate.h"
23 #include "dmd/declaration.h"
24 #include "dmd/expression.h"
25 #include "dmd/identifier.h"
26 #include "dmd/init.h"
27 #include "dmd/statement.h"
28
29 #include "tree.h"
30 #include "tree-iterator.h"
31 #include "options.h"
32 #include "stmt.h"
33 #include "fold-const.h"
34 #include "diagnostic.h"
35 #include "stringpool.h"
36 #include "function.h"
37 #include "toplev.h"
38
39 #include "d-tree.h"
40
41
42 /* Update data for defined and undefined labels when leaving a scope. */
43
44 bool
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> &, &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
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
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
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:
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
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
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
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
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
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
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
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
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
368 void check_goto (Statement *from, Statement *to)
369 {
370 d_label_entry *ent = d_function_chain->labels->get (to);
371 gcc_assert (ent != NULL);
372
373 /* If the label hasn't been defined yet, defer checking. */
374 if (! DECL_INITIAL (ent->label))
375 {
376 d_label_use_entry *fwdref = ggc_alloc<d_label_use_entry> ();
377 fwdref->level = current_binding_level;
378 fwdref->statement = from;
379 fwdref->next = ent->fwdrefs;
380 ent->fwdrefs = fwdref;
381 return;
382 }
383
384 if (ent->in_try_scope)
385 error_at (make_location_t (from->loc),
386 "cannot %<goto%> into %<try%> block");
387 else if (ent->in_catch_scope)
388 error_at (make_location_t (from->loc),
389 "cannot %<goto%> into %<catch%> block");
390 }
391
392 /* Check that a previously seen jump to a newly defined label is valid.
393 S is the label statement; FWDREF is the jump context. This is called
394 for both user-defined and case labels. */
395
396 void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
397 {
398 for (binding_level *b = current_binding_level; b ; b = b->level_chain)
399 {
400 if (b == fwdref->level)
401 break;
402
403 if (b->kind == level_try || b->kind == level_catch)
404 {
405 location_t location;
406
407 if (s->isLabelStatement ())
408 {
409 location = make_location_t (fwdref->statement->loc);
410 if (b->kind == level_try)
411 error_at (location, "cannot %<goto%> into %<try%> block");
412 else
413 error_at (location, "cannot %<goto%> into %<catch%> block");
414 }
415 else if (s->isCaseStatement ())
416 {
417 location = make_location_t (s->loc);
418 error_at (location, "case cannot be in different "
419 "%<try%> block level from %<switch%>");
420 }
421 else if (s->isDefaultStatement ())
422 {
423 location = make_location_t (s->loc);
424 error_at (location, "default cannot be in different "
425 "%<try%> block level from %<switch%>");
426 }
427 else
428 gcc_unreachable ();
429 }
430 }
431 }
432
433 /* Get or build LABEL_DECL using the IDENT and statement block S given. */
434
435 tree lookup_label (Statement *s, Identifier *ident = NULL)
436 {
437 /* You can't use labels at global scope. */
438 if (d_function_chain == NULL)
439 {
440 error ("label %s referenced outside of any function",
441 ident ? ident->toChars () : "(unnamed)");
442 return NULL_TREE;
443 }
444
445 /* Create the label htab for the function on demand. */
446 if (!d_function_chain->labels)
447 {
448 d_function_chain->labels
449 = hash_map<Statement *, d_label_entry>::create_ggc (13);
450 }
451
452 d_label_entry *ent = d_function_chain->labels->get (s);
453 if (ent != NULL)
454 return ent->label;
455 else
456 {
457 tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
458 tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
459 name, void_type_node);
460 DECL_CONTEXT (decl) = current_function_decl;
461 DECL_MODE (decl) = VOIDmode;
462
463 /* Create new empty slot. */
464 ent = ggc_cleared_alloc<d_label_entry> ();
465 ent->statement = s;
466 ent->label = decl;
467
468 bool existed = d_function_chain->labels->put (s, *ent);
469 gcc_assert (!existed);
470
471 return decl;
472 }
473 }
474
475 /* Get the LABEL_DECL to represent a break or continue for the
476 statement S given. BC indicates which. */
477
478 tree lookup_bc_label (Statement *s, bc_kind bc)
479 {
480 tree vec = this->lookup_label (s);
481
482 /* The break and continue labels are put into a TREE_VEC. */
483 if (TREE_CODE (vec) == LABEL_DECL)
484 {
485 d_label_entry *ent = d_function_chain->labels->get (s);
486 gcc_assert (ent != NULL);
487
488 vec = make_tree_vec (2);
489 TREE_VEC_ELT (vec, bc_break) = ent->label;
490
491 /* Build the continue label. */
492 tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
493 NULL_TREE, void_type_node);
494 DECL_CONTEXT (label) = current_function_decl;
495 DECL_MODE (label) = VOIDmode;
496 TREE_VEC_ELT (vec, bc_continue) = label;
497
498 ent->label = vec;
499 ent->bc_label = true;
500 }
501
502 return TREE_VEC_ELT (vec, bc);
503 }
504
505 /* Set and return the current break label for the current block. */
506
507 tree push_break_label (Statement *s)
508 {
509 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
510 DECL_CHAIN (label) = this->break_label_;
511 this->break_label_ = label;
512 return label;
513 }
514
515 /* Finish with the current break label. */
516
517 void pop_break_label (tree label)
518 {
519 gcc_assert (this->break_label_ == label);
520 this->break_label_ = DECL_CHAIN (this->break_label_);
521 this->do_label (label);
522 }
523
524 /* Set and return the continue label for the current block. */
525
526 tree push_continue_label (Statement *s)
527 {
528 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
529 DECL_CHAIN (label) = this->continue_label_;
530 this->continue_label_ = label;
531 return label;
532 }
533
534 /* Finish with the current continue label. */
535
536 void pop_continue_label (tree label)
537 {
538 gcc_assert (this->continue_label_ == label);
539 this->continue_label_ = DECL_CHAIN (this->continue_label_);
540 this->do_label (label);
541 }
542
543 /* Visitor interfaces. */
544
545
546 /* This should be overridden by each statement class. */
547
548 void visit (Statement *)
549 {
550 gcc_unreachable ();
551 }
552
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. */
556
557 void visit (OnScopeStatement *)
558 {
559 }
560
561 /* If statements provide simple conditional execution of statements. */
562
563 void visit (IfStatement *s)
564 {
565 this->start_scope (level_cond);
566
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;
573
574 /* Build the 'then' branch. */
575 if (s->ifbody)
576 {
577 push_stmt_list ();
578 this->build_stmt (s->ifbody);
579 ifbody = pop_stmt_list ();
580 }
581
582 /* Now build the 'else' branch, which may have nested 'else if' parts. */
583 if (s->elsebody)
584 {
585 push_stmt_list ();
586 this->build_stmt (s->elsebody);
587 elsebody = pop_stmt_list ();
588 }
589
590 /* Wrap up our constructed if condition into a COND_EXPR. */
591 tree cond = build_vcondition (ifcond, ifbody, elsebody);
592 add_stmt (cond);
593
594 /* Finish the if-then scope. */
595 this->finish_scope ();
596 }
597
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. */
601
602 void visit (PragmaStatement *)
603 {
604 }
605
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. */
609
610 void visit (WhileStatement *)
611 {
612 gcc_unreachable ();
613 }
614
615 /* Do while statments implement simple loops. The body is executed, then
616 the condition is evaluated. */
617
618 void visit (DoStatement *s)
619 {
620 tree lbreak = this->push_break_label (s);
621
622 this->start_scope (level_loop);
623 if (s->_body)
624 {
625 tree lcontinue = this->push_continue_label (s);
626 this->build_stmt (s->_body);
627 this->pop_continue_label (lcontinue);
628 }
629
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;
637
638 tree body = this->end_scope ();
639 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
640
641 this->pop_break_label (lbreak);
642 }
643
644 /* For statements implement loops with initialization, test, and
645 increment clauses. */
646
647 void visit (ForStatement *s)
648 {
649 tree lbreak = this->push_break_label (s);
650 this->start_scope (level_loop);
651
652 if (s->_init)
653 this->build_stmt (s->_init);
654
655 if (s->condition)
656 {
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;
663 }
664
665 if (s->_body)
666 {
667 tree lcontinue = this->push_continue_label (s);
668 this->build_stmt (s->_body);
669 this->pop_continue_label (lcontinue);
670 }
671
672 if (s->increment)
673 {
674 /* Force side effects? */
675 add_stmt (build_expr_dtor (s->increment));
676 }
677
678 tree body = this->end_scope ();
679 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
680
681 this->pop_break_label (lbreak);
682 }
683
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. */
687
688 void visit (ForeachStatement *)
689 {
690 gcc_unreachable ();
691 }
692
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. */
696
697 void visit (ForeachRangeStatement *)
698 {
699 gcc_unreachable ();
700 }
701
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. */
704
705 void visit (BreakStatement *s)
706 {
707 if (s->ident)
708 {
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));
715 }
716 else
717 this->do_jump (this->break_label_);
718 }
719
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. */
722
723 void visit (ContinueStatement *s)
724 {
725 if (s->ident)
726 {
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));
731 }
732 else
733 this->do_jump (this->continue_label_);
734 }
735
736 /* A goto statement jumps to the statement identified by the given label. */
737
738 void visit (GotoStatement *s)
739 {
740 gcc_assert (s->label->statement != NULL);
741 gcc_assert (s->tf == s->label->statement->tf);
742
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);
746
747 /* Need to error if the goto is jumping into a try or catch block. */
748 this->check_goto (s, s->label->statement);
749 }
750
751 /* Statements can be labeled. A label is an identifier that precedes
752 a statement. */
753
754 void visit (LabelStatement *s)
755 {
756 LabelDsymbol *sym;
757
758 if (this->is_return_label (s->ident))
759 sym = this->func_->returnLabel;
760 else
761 sym = this->func_->searchLabel (s->ident);
762
763 /* If no label found, there was an error. */
764 tree label = this->define_label (sym->statement, sym->ident);
765 TREE_USED (label) = 1;
766
767 this->do_label (label);
768
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);
773 }
774
775 /* A switch statement goes to one of a collection of case statements
776 depending on the value of the switch expression. */
777
778 void visit (SwitchStatement *s)
779 {
780 this->start_scope (level_switch);
781 tree lbreak = this->push_break_label (s);
782
783 tree condition = build_expr_dtor (s->condition);
784 Type *condtype = s->condition->type->toBasetype ();
785
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 ())
789 {
790 Type *etype = condtype->nextOf ()->toBasetype ();
791 libcall_fn libcall;
792
793 switch (etype->ty)
794 {
795 case Tchar:
796 libcall = LIBCALL_SWITCH_STRING;
797 break;
798
799 case Twchar:
800 libcall = LIBCALL_SWITCH_USTRING;
801 break;
802
803 case Tdchar:
804 libcall = LIBCALL_SWITCH_DSTRING;
805 break;
806
807 default:
808 ::error ("switch statement value must be an array of "
809 "some character type, not %s", etype->toChars ());
810 gcc_unreachable ();
811 }
812
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;
817
818 s->cases->sort ();
819
820 for (size_t i = 0; i < s->cases->dim; i++)
821 {
822 CaseStatement *cs = (*s->cases)[i];
823 cs->index = i;
824
825 if (cs->exp->op != TOKstring)
826 s->error ("case '%s' is not a string", cs->exp->toChars ());
827 else
828 {
829 tree exp = build_expr (cs->exp, true);
830 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
831 }
832 }
833
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);
840
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));
845
846 condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
847 }
848 else if (!condtype->isscalar ())
849 {
850 error ("cannot handle switch condition of type %s",
851 condtype->toChars ());
852 gcc_unreachable ();
853 }
854
855 condition = fold (condition);
856
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)
860 {
861 for (size_t i = 0; i < s->cases->dim; i++)
862 {
863 CaseStatement *cs = (*s->cases)[i];
864 tree caselabel = this->lookup_label (cs);
865
866 /* Write cases as a series of if-then-else blocks.
867 if (condition == case)
868 goto caselabel; */
869 if (s->hasVars)
870 {
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);
879 }
880
881 this->check_goto (s, cs);
882 }
883
884 if (s->sdefault)
885 {
886 tree defaultlabel = this->lookup_label (s->sdefault);
887
888 /* The default label is the last 'else' block. */
889 if (s->hasVars)
890 {
891 this->do_jump (defaultlabel);
892 LABEL_VARIABLE_CASE (defaultlabel) = 1;
893 }
894
895 this->check_goto (s, s->sdefault);
896 }
897 }
898
899 /* Switch body goes in its own statement list. */
900 push_stmt_list ();
901 if (s->_body)
902 this->build_stmt (s->_body);
903
904 tree casebody = pop_stmt_list ();
905
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
911 {
912 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
913 condition, casebody);
914 add_stmt (switchexpr);
915 SWITCH_ALL_CASES_P (switchexpr) = 1;
916 }
917
918 SWITCH_BREAK_LABEL_P (lbreak) = 1;
919
920 /* If the switch had any 'break' statements, emit the label now. */
921 this->pop_break_label (lbreak);
922 this->finish_scope ();
923 }
924
925 /* Declare the case label associated with the current SwitchStatement. */
926
927 void visit (CaseStatement *s)
928 {
929 /* Emit the case label. */
930 tree label = this->define_label (s);
931
932 if (LABEL_VARIABLE_CASE (label))
933 this->do_label (label);
934 else
935 {
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));
941
942 tree caselabel = build_case_label (casevalue, NULL_TREE, label);
943 add_stmt (caselabel);
944 }
945
946 /* Now do the body. */
947 if (s->statement)
948 this->build_stmt (s->statement);
949 }
950
951 /* Declare the default label associated with the current SwitchStatement. */
952
953 void visit (DefaultStatement *s)
954 {
955 /* Emit the default case label. */
956 tree label = this->define_label (s);
957
958 if (LABEL_VARIABLE_CASE (label))
959 this->do_label (label);
960 else
961 {
962 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
963 add_stmt (caselabel);
964 }
965
966 /* Now do the body. */
967 if (s->statement)
968 this->build_stmt (s->statement);
969 }
970
971 /* Implements 'goto default' by jumping to the label associated with
972 the DefaultStatement in a switch block. */
973
974 void visit (GotoDefaultStatement *s)
975 {
976 tree label = this->lookup_label (s->sw->sdefault);
977 this->do_jump (label);
978 }
979
980 /* Implements 'goto case' by jumping to the label associated with the
981 CaseStatement in a switch block. */
982
983 void visit (GotoCaseStatement *s)
984 {
985 tree label = this->lookup_label (s->cs);
986 this->do_jump (label);
987 }
988
989 /* Throw a SwitchError exception, called when a switch statement has
990 no DefaultStatement, yet none of the cases match. */
991
992 void visit (SwitchErrorStatement *s)
993 {
994 add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
995 }
996
997 /* A return statement exits the current function and supplies its return
998 value, if the return type is not void. */
999
1000 void visit (ReturnStatement *s)
1001 {
1002 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
1003 {
1004 /* Return has no value. */
1005 add_stmt (return_expr (NULL_TREE));
1006 return;
1007 }
1008
1009 TypeFunction *tf = (TypeFunction *)this->func_->type;
1010 Type *type = this->func_->tintro != NULL
1011 ? this->func_->tintro->nextOf () : tf->nextOf ();
1012
1013 if ((this->func_->isMain () || this->func_->isCMain ())
1014 && type->toBasetype ()->ty == Tvoid)
1015 type = Type::tint32;
1016
1017 if (this->func_->nrvo_can && this->func_->nrvo_var)
1018 {
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));
1024 }
1025 else
1026 {
1027 /* Convert for initializing the DECL_RESULT. */
1028 tree expr = build_return_dtor (s->exp, type, tf);
1029 add_stmt (expr);
1030 }
1031 }
1032
1033 /* Evaluate the enclosed expression, and add it to the statement list. */
1034
1035 void visit (ExpStatement *s)
1036 {
1037 if (s->exp)
1038 {
1039 /* Expression may produce temporaries requiring scope destruction. */
1040 tree exp = build_expr_dtor (s->exp);
1041 add_stmt (exp);
1042 }
1043 }
1044
1045 /* Evaluate all enclosed statements. */
1046
1047 void visit (CompoundStatement *s)
1048 {
1049 if (s->statements == NULL)
1050 return;
1051
1052 for (size_t i = 0; i < s->statements->dim; i++)
1053 {
1054 Statement *statement = (*s->statements)[i];
1055
1056 if (statement != NULL)
1057 this->build_stmt (statement);
1058 }
1059 }
1060
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. */
1064
1065 void visit (UnrolledLoopStatement *s)
1066 {
1067 if (s->statements == NULL)
1068 return;
1069
1070 tree lbreak = this->push_break_label (s);
1071 this->start_scope (level_loop);
1072
1073 for (size_t i = 0; i < s->statements->dim; i++)
1074 {
1075 Statement *statement = (*s->statements)[i];
1076
1077 if (statement != NULL)
1078 {
1079 tree lcontinue = this->push_continue_label (statement);
1080 this->build_stmt (statement);
1081 this->pop_continue_label (lcontinue);
1082 }
1083 }
1084
1085 this->do_jump (this->break_label_);
1086
1087 tree body = this->end_scope ();
1088 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1089
1090 this->pop_break_label (lbreak);
1091 }
1092
1093 /* Start a new scope and visit all nested statements, wrapping
1094 them up into a BIND_EXPR at the end of the scope. */
1095
1096 void visit (ScopeStatement *s)
1097 {
1098 if (s->statement == NULL)
1099 return;
1100
1101 this->start_scope (level_block);
1102 this->build_stmt (s->statement);
1103 this->finish_scope ();
1104 }
1105
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. */
1108
1109 void visit (WithStatement *s)
1110 {
1111 this->start_scope (level_with);
1112
1113 if (s->wthis)
1114 {
1115 /* Perform initialisation of the 'with' handle. */
1116 ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1117 gcc_assert (ie != NULL);
1118
1119 declare_local_var (s->wthis);
1120 tree init = build_expr_dtor (ie->exp);
1121 add_stmt (init);
1122 }
1123
1124 if (s->_body)
1125 this->build_stmt (s->_body);
1126
1127 this->finish_scope ();
1128 }
1129
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. */
1133
1134 void visit (ThrowStatement *s)
1135 {
1136 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1137 InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1138 tree arg = build_expr_dtor (s->exp);
1139
1140 if (!global.params.useExceptions)
1141 {
1142 static int warned = 0;
1143 if (!warned)
1144 {
1145 error_at (make_location_t (s->loc), "exception handling disabled; "
1146 "use %<-fexceptions%> to enable");
1147 warned = 1;
1148 }
1149 }
1150
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);
1157
1158 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1159 }
1160
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. */
1164
1165 void visit (TryCatchStatement *s)
1166 {
1167 this->start_scope (level_try);
1168 if (s->_body)
1169 this->build_stmt (s->_body);
1170
1171 tree trybody = this->end_scope ();
1172
1173 /* Try handlers go in their own statement list. */
1174 push_stmt_list ();
1175
1176 if (s->catches)
1177 {
1178 for (size_t i = 0; i < s->catches->dim; i++)
1179 {
1180 Catch *vcatch = (*s->catches)[i];
1181
1182 this->start_scope (level_catch);
1183
1184 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1185 tree catchtype = build_ctype (vcatch->type);
1186 tree object = NULL_TREE;
1187
1188 ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1189
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 ();
1195
1196 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1197 : LIBCALL_BEGIN_CATCH;
1198 object = build_libcall (libcall, vcatch->type, 1, ehptr);
1199
1200 if (vcatch->var)
1201 {
1202 tree var = get_symbol_decl (vcatch->var);
1203 tree init = build_assign (INIT_EXPR, var, object);
1204
1205 declare_local_var (vcatch->var);
1206 add_stmt (init);
1207 }
1208 else
1209 {
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);
1213 }
1214
1215 if (vcatch->handler)
1216 this->build_stmt (vcatch->handler);
1217
1218 tree catchbody = this->end_scope ();
1219
1220 /* Need to wrap C++ handlers in a try/finally block to signal
1221 the end catch callback. */
1222 if (cd->isCPPclass ())
1223 {
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);
1228 }
1229
1230 add_stmt (build2 (CATCH_EXPR, void_type_node,
1231 catchtype, catchbody));
1232 }
1233 }
1234
1235 tree catches = pop_stmt_list ();
1236
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)
1241 {
1242 tree stmt_list = alloc_stmt_list ();
1243 append_to_statement_list_force (catches, &stmt_list);
1244 catches = stmt_list;
1245 }
1246
1247 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1248 }
1249
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. */
1253
1254 void visit (TryFinallyStatement *s)
1255 {
1256 this->start_scope (level_try);
1257 if (s->_body)
1258 this->build_stmt (s->_body);
1259
1260 tree trybody = this->end_scope ();
1261
1262 this->start_scope (level_finally);
1263 if (s->finalbody)
1264 this->build_stmt (s->finalbody);
1265
1266 tree finally = this->end_scope ();
1267
1268 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1269 }
1270
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. */
1275
1276 void visit (SynchronizedStatement *)
1277 {
1278 gcc_unreachable ();
1279 }
1280
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. */
1284
1285 void visit (AsmStatement *)
1286 {
1287 sorry ("D inline assembler statements are not supported in GDC.");
1288 }
1289
1290 /* Build a GCC extended assembler expression, whose components are
1291 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1292
1293 void visit (GccAsmStatement *s)
1294 {
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;
1300
1301 /* Collect all arguments, which may be input or output operands. */
1302 if (s->args)
1303 {
1304 for (size_t i = 0; i < s->args->dim; i++)
1305 {
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;
1309
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);
1314
1315 Expression *earg = (*s->args)[i];
1316 tree val = build_expr (earg);
1317
1318 if (i < s->outputargs)
1319 {
1320 tree arg = build_tree_list (id, str);
1321 outputs = chainon (outputs, build_tree_list (arg, val));
1322 }
1323 else
1324 {
1325 tree arg = build_tree_list (id, str);
1326 inputs = chainon (inputs, build_tree_list (arg, val));
1327 }
1328 }
1329 }
1330
1331 /* Collect all clobber arguments. */
1332 if (s->clobbers)
1333 {
1334 for (size_t i = 0; i < s->clobbers->dim; i++)
1335 {
1336 StringExp *clobber = (StringExp *)(*s->clobbers)[i];
1337 const char *cstring = (const char *)(clobber->len
1338 ? clobber->string : "");
1339
1340 tree val = build_string (clobber->len, cstring);
1341 clobbers = chainon (clobbers, build_tree_list (0, val));
1342 }
1343 }
1344
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)
1348 {
1349 for (size_t i = 0; i < s->labels->dim; i++)
1350 {
1351 Identifier *ident = (*s->labels)[i];
1352 GotoStatement *gs = (*s->gotos)[i];
1353
1354 gcc_assert (gs->label->statement != NULL);
1355 gcc_assert (gs->tf == gs->label->statement->tf);
1356
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;
1362
1363 labels = chainon (labels, build_tree_list (name, label));
1364 }
1365 }
1366
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);
1371
1372 if (s->args)
1373 {
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;
1380
1381 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1382 {
1383 tree output = TREE_VALUE (t);
1384 const char *constraint
1385 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1386
1387 oconstraints[i] = constraint;
1388
1389 if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1390 &allows_mem, &allows_reg, &is_inout))
1391 {
1392 /* If the output argument is going to end up in memory. */
1393 if (!allows_reg)
1394 d_mark_addressable (output);
1395 }
1396 else
1397 output = error_mark_node;
1398
1399 TREE_VALUE (t) = output;
1400 }
1401
1402 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1403 {
1404 tree input = TREE_VALUE (t);
1405 const char *constraint
1406 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1407
1408 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1409 oconstraints, &allows_mem, &allows_reg))
1410 {
1411 /* If the input argument is going to end up in memory. */
1412 if (!allows_reg && allows_mem)
1413 d_mark_addressable (input);
1414 }
1415 else
1416 input = error_mark_node;
1417
1418 TREE_VALUE (t) = input;
1419 }
1420 }
1421
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));
1425
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;
1429
1430 /* All asm statements are assumed to have a side effect. As a future
1431 optimization, this could be unset when building in release mode. */
1432 ASM_VOLATILE_P (exp) = 1;
1433
1434 add_stmt (exp);
1435 }
1436
1437 /* Import symbols from another module. */
1438
1439 void visit (ImportStatement *s)
1440 {
1441 if (s->imports == NULL)
1442 return;
1443
1444 for (size_t i = 0; i < s->imports->dim; i++)
1445 {
1446 Dsymbol *dsym = (*s->imports)[i];
1447
1448 if (dsym != NULL)
1449 build_decl_tree (dsym);
1450 }
1451 }
1452 };
1453
1454 /* Main entry point for the IRVisitor interface to generate
1455 code for the body of function FD. */
1456
1457 void
1458 build_function_body (FuncDeclaration *fd)
1459 {
1460 IRVisitor v = IRVisitor (fd);
1461 location_t saved_location = input_location;
1462 input_location = make_location_t (fd->loc);
1463 v.build_stmt (fd->fbody);
1464 input_location = saved_location;
1465 }