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