comparison dmd2/statement.c @ 758:f04dde6e882c

Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:38:48 +0100
parents
children f08e0ff8d28c
comparison
equal deleted inserted replaced
757:2c730d530c98 758:f04dde6e882c
1
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <assert.h>
14
15 #include "mem.h"
16
17 #include "statement.h"
18 #include "expression.h"
19 #include "cond.h"
20 #include "init.h"
21 #include "staticassert.h"
22 #include "mtype.h"
23 #include "scope.h"
24 #include "declaration.h"
25 #include "aggregate.h"
26 #include "id.h"
27 #include "hdrgen.h"
28 #include "parse.h"
29 #include "template.h"
30
31 /******************************** Statement ***************************/
32
33 Statement::Statement(Loc loc)
34 : loc(loc)
35 {
36 #ifdef _DH
37 // If this is an in{} contract scope statement (skip for determining
38 // inlineStatus of a function body for header content)
39 incontract = 0;
40 #endif
41 }
42
43 Statement *Statement::syntaxCopy()
44 {
45 assert(0);
46 return NULL;
47 }
48
49 void Statement::print()
50 {
51 fprintf(stdmsg, "%s\n", toChars());
52 fflush(stdmsg);
53 }
54
55 char *Statement::toChars()
56 { OutBuffer *buf;
57 HdrGenState hgs;
58
59 buf = new OutBuffer();
60 toCBuffer(buf, &hgs);
61 return buf->toChars();
62 }
63
64 void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
65 {
66 buf->printf("Statement::toCBuffer()");
67 buf->writenl();
68 }
69
70 Statement *Statement::semantic(Scope *sc)
71 {
72 return this;
73 }
74
75 // Same as semantic(), but do create a new scope
76
77 Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
78 { Scope *scd;
79 Statement *s;
80
81 scd = sc->push();
82 if (sbreak)
83 scd->sbreak = sbreak;
84 if (scontinue)
85 scd->scontinue = scontinue;
86 s = semantic(scd);
87 scd->pop();
88 return s;
89 }
90
91 void Statement::error(const char *format, ...)
92 {
93 va_list ap;
94 va_start(ap, format);
95 ::verror(loc, format, ap);
96 va_end( ap );
97 }
98
99 int Statement::hasBreak()
100 {
101 //printf("Statement::hasBreak()\n");
102 return FALSE;
103 }
104
105 int Statement::hasContinue()
106 {
107 return FALSE;
108 }
109
110 // TRUE if statement uses exception handling
111
112 int Statement::usesEH()
113 {
114 return FALSE;
115 }
116
117 /* Only valid after semantic analysis
118 */
119 int Statement::blockExit()
120 {
121 printf("Statement::blockExit(%p)\n", this);
122 printf("%s\n", toChars());
123 assert(0);
124 return BEany;
125 }
126
127 // TRUE if statement may fall off the end without a throw or return
128
129 int Statement::fallOffEnd()
130 {
131 return TRUE;
132 }
133
134 // TRUE if statement 'comes from' somewhere else, like a goto
135
136 int Statement::comeFrom()
137 {
138 //printf("Statement::comeFrom()\n");
139 return FALSE;
140 }
141
142 /****************************************
143 * If this statement has code that needs to run in a finally clause
144 * at the end of the current scope, return that code in the form of
145 * a Statement.
146 * Output:
147 * *sentry code executed upon entry to the scope
148 * *sexception code executed upon exit from the scope via exception
149 * *sfinally code executed in finally block
150 */
151
152 void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
153 {
154 //printf("Statement::scopeCode()\n");
155 //print();
156 *sentry = NULL;
157 *sexception = NULL;
158 *sfinally = NULL;
159 }
160
161 /*********************************
162 * Flatten out the scope by presenting the statement
163 * as an array of statements.
164 * Returns NULL if no flattening necessary.
165 */
166
167 Statements *Statement::flatten(Scope *sc)
168 {
169 return NULL;
170 }
171
172
173 /******************************** ExpStatement ***************************/
174
175 ExpStatement::ExpStatement(Loc loc, Expression *exp)
176 : Statement(loc)
177 {
178 this->exp = exp;
179 }
180
181 Statement *ExpStatement::syntaxCopy()
182 {
183 Expression *e = exp ? exp->syntaxCopy() : NULL;
184 ExpStatement *es = new ExpStatement(loc, e);
185 return es;
186 }
187
188 void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
189 {
190 if (exp)
191 exp->toCBuffer(buf, hgs);
192 buf->writeByte(';');
193 if (!hgs->FLinit.init)
194 buf->writenl();
195 }
196
197 Statement *ExpStatement::semantic(Scope *sc)
198 {
199 if (exp)
200 {
201 //printf("ExpStatement::semantic() %s\n", exp->toChars());
202 exp = exp->semantic(sc);
203 exp = resolveProperties(sc, exp);
204 exp->checkSideEffect(0);
205 exp = exp->optimize(0);
206 if (exp->op == TOKdeclaration && !isDeclarationStatement())
207 { Statement *s = new DeclarationStatement(loc, exp);
208 return s;
209 }
210 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
211 }
212 return this;
213 }
214
215 int ExpStatement::blockExit()
216 { int result = BEfallthru;
217
218 if (exp)
219 {
220 if (exp->op == TOKhalt)
221 return BEhalt;
222 if (exp->op == TOKassert)
223 { AssertExp *a = (AssertExp *)exp;
224
225 if (a->e1->isBool(FALSE)) // if it's an assert(0)
226 return BEhalt;
227 }
228 if (exp->canThrow())
229 result |= BEthrow;
230 }
231 return result;
232 }
233
234 int ExpStatement::fallOffEnd()
235 {
236 if (exp)
237 {
238 if (exp->op == TOKassert)
239 { AssertExp *a = (AssertExp *)exp;
240
241 if (a->e1->isBool(FALSE)) // if it's an assert(0)
242 return FALSE;
243 }
244 else if (exp->op == TOKhalt)
245 return FALSE;
246 }
247 return TRUE;
248 }
249
250 /******************************** CompileStatement ***************************/
251
252 CompileStatement::CompileStatement(Loc loc, Expression *exp)
253 : Statement(loc)
254 {
255 this->exp = exp;
256 }
257
258 Statement *CompileStatement::syntaxCopy()
259 {
260 Expression *e = exp->syntaxCopy();
261 CompileStatement *es = new CompileStatement(loc, e);
262 return es;
263 }
264
265 void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
266 {
267 buf->writestring("mixin(");
268 exp->toCBuffer(buf, hgs);
269 buf->writestring(");");
270 if (!hgs->FLinit.init)
271 buf->writenl();
272 }
273
274 Statements *CompileStatement::flatten(Scope *sc)
275 {
276 //printf("CompileStatement::flatten() %s\n", exp->toChars());
277 exp = exp->semantic(sc);
278 exp = resolveProperties(sc, exp);
279 exp = exp->optimize(WANTvalue | WANTinterpret);
280 if (exp->op != TOKstring)
281 { error("argument to mixin must be a string, not (%s)", exp->toChars());
282 return NULL;
283 }
284 StringExp *se = (StringExp *)exp;
285 se = se->toUTF8(sc);
286 Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
287 p.loc = loc;
288 p.nextToken();
289
290 Statements *a = new Statements();
291 while (p.token.value != TOKeof)
292 {
293 Statement *s = p.parseStatement(PSsemi | PScurlyscope);
294 a->push(s);
295 }
296 return a;
297 }
298
299 Statement *CompileStatement::semantic(Scope *sc)
300 {
301 //printf("CompileStatement::semantic() %s\n", exp->toChars());
302 Statements *a = flatten(sc);
303 if (!a)
304 return NULL;
305 Statement *s = new CompoundStatement(loc, a);
306 return s->semantic(sc);
307 }
308
309
310 /******************************** DeclarationStatement ***************************/
311
312 DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
313 : ExpStatement(loc, new DeclarationExp(loc, declaration))
314 {
315 }
316
317 DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
318 : ExpStatement(loc, exp)
319 {
320 }
321
322 Statement *DeclarationStatement::syntaxCopy()
323 {
324 DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
325 return ds;
326 }
327
328 void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
329 {
330 //printf("DeclarationStatement::scopeCode()\n");
331 //print();
332
333 *sentry = NULL;
334 *sexception = NULL;
335 *sfinally = NULL;
336
337 if (exp)
338 {
339 if (exp->op == TOKdeclaration)
340 {
341 DeclarationExp *de = (DeclarationExp *)(exp);
342 VarDeclaration *v = de->declaration->isVarDeclaration();
343 if (v)
344 { Expression *e;
345
346 e = v->callAutoDtor(sc);
347 if (e)
348 {
349 //printf("dtor is: "); e->print();
350 *sfinally = new ExpStatement(loc, e);
351 }
352 }
353 }
354 }
355 }
356
357 void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
358 {
359 exp->toCBuffer(buf, hgs);
360 }
361
362
363 /******************************** CompoundStatement ***************************/
364
365 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
366 : Statement(loc)
367 {
368 statements = s;
369 }
370
371 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
372 : Statement(loc)
373 {
374 statements = new Statements();
375 statements->reserve(2);
376 statements->push(s1);
377 statements->push(s2);
378 }
379
380 Statement *CompoundStatement::syntaxCopy()
381 {
382 Statements *a = new Statements();
383 a->setDim(statements->dim);
384 for (size_t i = 0; i < statements->dim; i++)
385 { Statement *s = (Statement *)statements->data[i];
386 if (s)
387 s = s->syntaxCopy();
388 a->data[i] = s;
389 }
390 CompoundStatement *cs = new CompoundStatement(loc, a);
391 return cs;
392 }
393
394
395 Statement *CompoundStatement::semantic(Scope *sc)
396 { Statement *s;
397
398 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
399
400 for (size_t i = 0; i < statements->dim; )
401 {
402 s = (Statement *) statements->data[i];
403 if (s)
404 { Statements *a = s->flatten(sc);
405
406 if (a)
407 {
408 statements->remove(i);
409 statements->insert(i, a);
410 continue;
411 }
412 s = s->semantic(sc);
413 statements->data[i] = s;
414 if (s)
415 {
416 Statement *sentry;
417 Statement *sexception;
418 Statement *sfinally;
419
420 s->scopeCode(sc, &sentry, &sexception, &sfinally);
421 if (sentry)
422 {
423 sentry = sentry->semantic(sc);
424 statements->data[i] = sentry;
425 }
426 if (sexception)
427 {
428 if (i + 1 == statements->dim && !sfinally)
429 {
430 #if 1
431 sexception = sexception->semantic(sc);
432 #else
433 statements->push(sexception);
434 if (sfinally)
435 // Assume sexception does not throw
436 statements->push(sfinally);
437 #endif
438 }
439 else
440 {
441 /* Rewrite:
442 * s; s1; s2;
443 * As:
444 * s;
445 * try { s1; s2; }
446 * catch (Object __o)
447 * { sexception; throw __o; }
448 */
449 Statement *body;
450 Statements *a = new Statements();
451
452 for (int j = i + 1; j < statements->dim; j++)
453 {
454 a->push(statements->data[j]);
455 }
456 body = new CompoundStatement(0, a);
457 body = new ScopeStatement(0, body);
458
459 Identifier *id = Lexer::uniqueId("__o");
460
461 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
462 handler = new CompoundStatement(0, sexception, handler);
463
464 Array *catches = new Array();
465 Catch *ctch = new Catch(0, NULL, id, handler);
466 catches->push(ctch);
467 s = new TryCatchStatement(0, body, catches);
468
469 if (sfinally)
470 s = new TryFinallyStatement(0, s, sfinally);
471 s = s->semantic(sc);
472 statements->setDim(i + 1);
473 statements->push(s);
474 break;
475 }
476 }
477 else if (sfinally)
478 {
479 if (0 && i + 1 == statements->dim)
480 {
481 statements->push(sfinally);
482 }
483 else
484 {
485 /* Rewrite:
486 * s; s1; s2;
487 * As:
488 * s; try { s1; s2; } finally { sfinally; }
489 */
490 Statement *body;
491 Statements *a = new Statements();
492
493 for (int j = i + 1; j < statements->dim; j++)
494 {
495 a->push(statements->data[j]);
496 }
497 body = new CompoundStatement(0, a);
498 s = new TryFinallyStatement(0, body, sfinally);
499 s = s->semantic(sc);
500 statements->setDim(i + 1);
501 statements->push(s);
502 break;
503 }
504 }
505 }
506 }
507 i++;
508 }
509 if (statements->dim == 1 && !isAsmBlockStatement())
510 {
511 return (Statement *)statements->data[0];
512 }
513 return this;
514 }
515
516 Statements *CompoundStatement::flatten(Scope *sc)
517 {
518 return statements;
519 }
520
521 ReturnStatement *CompoundStatement::isReturnStatement()
522 {
523 ReturnStatement *rs = NULL;
524
525 for (int i = 0; i < statements->dim; i++)
526 { Statement *s = (Statement *) statements->data[i];
527 if (s)
528 {
529 rs = s->isReturnStatement();
530 if (rs)
531 break;
532 }
533 }
534 return rs;
535 }
536
537 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
538 {
539 for (int i = 0; i < statements->dim; i++)
540 { Statement *s = (Statement *) statements->data[i];
541 if (s)
542 s->toCBuffer(buf, hgs);
543 }
544 }
545
546 int CompoundStatement::usesEH()
547 {
548 for (int i = 0; i < statements->dim; i++)
549 { Statement *s = (Statement *) statements->data[i];
550 if (s && s->usesEH())
551 return TRUE;
552 }
553 return FALSE;
554 }
555
556 int CompoundStatement::blockExit()
557 {
558 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
559 int result = BEfallthru;
560 for (size_t i = 0; i < statements->dim; i++)
561 { Statement *s = (Statement *) statements->data[i];
562 if (s)
563 {
564 //printf("result = x%x\n", result);
565 //printf("%s\n", s->toChars());
566 if (!(result & BEfallthru) && !s->comeFrom())
567 {
568 if (global.params.warnings)
569 { fprintf(stdmsg, "warning - ");
570 s->error("statement is not reachable");
571 }
572 }
573
574 result &= ~BEfallthru;
575 result |= s->blockExit();
576 }
577 }
578 return result;
579 }
580
581 int CompoundStatement::fallOffEnd()
582 { int falloff = TRUE;
583
584 //printf("CompoundStatement::fallOffEnd() %s\n", toChars());
585 for (int i = 0; i < statements->dim; i++)
586 { Statement *s = (Statement *)statements->data[i];
587
588 if (!s)
589 continue;
590
591 #if 0
592 if (!falloff && global.params.warnings && !s->comeFrom())
593 {
594 warning("%s: statement is not reachable", s->loc.toChars());
595 }
596 #endif
597 falloff = s->fallOffEnd();
598 }
599 return falloff;
600 }
601
602 int CompoundStatement::comeFrom()
603 { int comefrom = FALSE;
604
605 //printf("CompoundStatement::comeFrom()\n");
606 for (int i = 0; i < statements->dim; i++)
607 { Statement *s = (Statement *)statements->data[i];
608
609 if (!s)
610 continue;
611
612 comefrom |= s->comeFrom();
613 }
614 return comefrom;
615 }
616
617
618 /**************************** UnrolledLoopStatement ***************************/
619
620 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
621 : Statement(loc)
622 {
623 statements = s;
624 enclosinghandler = NULL;
625 }
626
627 Statement *UnrolledLoopStatement::syntaxCopy()
628 {
629 Statements *a = new Statements();
630 a->setDim(statements->dim);
631 for (size_t i = 0; i < statements->dim; i++)
632 { Statement *s = (Statement *)statements->data[i];
633 if (s)
634 s = s->syntaxCopy();
635 a->data[i] = s;
636 }
637 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
638 return cs;
639 }
640
641
642 Statement *UnrolledLoopStatement::semantic(Scope *sc)
643 {
644 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
645
646 enclosinghandler = sc->tfOfTry;
647
648 sc->noctor++;
649 Scope *scd = sc->push();
650 scd->sbreak = this;
651 scd->scontinue = this;
652
653 for (size_t i = 0; i < statements->dim; i++)
654 {
655 Statement *s = (Statement *) statements->data[i];
656 if (s)
657 {
658 s = s->semantic(scd);
659 statements->data[i] = s;
660 }
661 }
662
663 scd->pop();
664 sc->noctor--;
665 return this;
666 }
667
668 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
669 {
670 buf->writestring("unrolled {");
671 buf->writenl();
672
673 for (size_t i = 0; i < statements->dim; i++)
674 { Statement *s;
675
676 s = (Statement *) statements->data[i];
677 if (s)
678 s->toCBuffer(buf, hgs);
679 }
680
681 buf->writeByte('}');
682 buf->writenl();
683 }
684
685 int UnrolledLoopStatement::hasBreak()
686 {
687 return TRUE;
688 }
689
690 int UnrolledLoopStatement::hasContinue()
691 {
692 return TRUE;
693 }
694
695 int UnrolledLoopStatement::usesEH()
696 {
697 for (size_t i = 0; i < statements->dim; i++)
698 { Statement *s = (Statement *) statements->data[i];
699 if (s && s->usesEH())
700 return TRUE;
701 }
702 return FALSE;
703 }
704
705 int UnrolledLoopStatement::blockExit()
706 {
707 int result = BEfallthru;
708 for (size_t i = 0; i < statements->dim; i++)
709 { Statement *s = (Statement *) statements->data[i];
710 if (s)
711 {
712 int r = s->blockExit();
713 result |= r & ~(BEbreak | BEcontinue);
714 }
715 }
716 return result;
717 }
718
719 int UnrolledLoopStatement::fallOffEnd()
720 {
721 //printf("UnrolledLoopStatement::fallOffEnd()\n");
722 for (size_t i = 0; i < statements->dim; i++)
723 { Statement *s = (Statement *)statements->data[i];
724
725 if (s)
726 s->fallOffEnd();
727 }
728 return TRUE;
729 }
730
731 int UnrolledLoopStatement::comeFrom()
732 { int comefrom = FALSE;
733
734 //printf("UnrolledLoopStatement::comeFrom()\n");
735 for (size_t i = 0; i < statements->dim; i++)
736 { Statement *s = (Statement *)statements->data[i];
737
738 if (!s)
739 continue;
740
741 comefrom |= s->comeFrom();
742 }
743 return comefrom;
744 }
745
746
747 /******************************** ScopeStatement ***************************/
748
749 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
750 : Statement(loc)
751 {
752 this->statement = s;
753 }
754
755 Statement *ScopeStatement::syntaxCopy()
756 {
757 Statement *s;
758
759 s = statement ? statement->syntaxCopy() : NULL;
760 s = new ScopeStatement(loc, s);
761 return s;
762 }
763
764
765 Statement *ScopeStatement::semantic(Scope *sc)
766 { ScopeDsymbol *sym;
767
768 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
769 if (statement)
770 { Statements *a;
771
772 sym = new ScopeDsymbol();
773 sym->parent = sc->scopesym;
774 sc = sc->push(sym);
775
776 a = statement->flatten(sc);
777 if (a)
778 {
779 statement = new CompoundStatement(loc, a);
780 }
781
782 statement = statement->semantic(sc);
783 if (statement)
784 {
785 Statement *sentry;
786 Statement *sexception;
787 Statement *sfinally;
788
789 statement->scopeCode(sc, &sentry, &sexception, &sfinally);
790 if (sfinally)
791 {
792 //printf("adding sfinally\n");
793 statement = new CompoundStatement(loc, statement, sfinally);
794 }
795 }
796
797 sc->pop();
798 }
799 return this;
800 }
801
802 int ScopeStatement::hasBreak()
803 {
804 //printf("ScopeStatement::hasBreak() %s\n", toChars());
805 return statement ? statement->hasBreak() : FALSE;
806 }
807
808 int ScopeStatement::hasContinue()
809 {
810 return statement ? statement->hasContinue() : FALSE;
811 }
812
813 int ScopeStatement::usesEH()
814 {
815 return statement ? statement->usesEH() : FALSE;
816 }
817
818 int ScopeStatement::blockExit()
819 {
820 //printf("ScopeStatement::blockExit(%p)\n", statement);
821 return statement ? statement->blockExit() : BEfallthru;
822 }
823
824 int ScopeStatement::fallOffEnd()
825 {
826 return statement ? statement->fallOffEnd() : TRUE;
827 }
828
829 int ScopeStatement::comeFrom()
830 {
831 //printf("ScopeStatement::comeFrom()\n");
832 return statement ? statement->comeFrom() : FALSE;
833 }
834
835 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
836 {
837 buf->writeByte('{');
838 buf->writenl();
839
840 if (statement)
841 statement->toCBuffer(buf, hgs);
842
843 buf->writeByte('}');
844 buf->writenl();
845 }
846
847 /******************************** WhileStatement ***************************/
848
849 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
850 : Statement(loc)
851 {
852 condition = c;
853 body = b;
854 enclosinghandler = NULL;
855 }
856
857 Statement *WhileStatement::syntaxCopy()
858 {
859 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
860 return s;
861 }
862
863
864 Statement *WhileStatement::semantic(Scope *sc)
865 {
866 #if 0
867 if (condition->op == TOKmatch)
868 {
869 /* Rewrite while (condition) body as:
870 * if (condition)
871 * do
872 * body
873 * while ((_match = _match.opNext), _match);
874 */
875
876 Expression *ew = new IdentifierExp(0, Id::_match);
877 ew = new DotIdExp(0, ew, Id::next);
878 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
879 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
880 Expression *ev = new IdentifierExp(0, Id::_match);
881 //ev = new CastExp(0, ev, Type::tvoidptr);
882 ew = new CommaExp(0, ew, ev);
883 Statement *sw = new DoStatement(loc, body, ew);
884 Statement *si = new IfStatement(loc, condition, sw, NULL);
885 return si->semantic(sc);
886 }
887 #endif
888
889 enclosinghandler = sc->tfOfTry;
890
891 condition = condition->semantic(sc);
892 condition = resolveProperties(sc, condition);
893 condition = condition->optimize(WANTvalue);
894 condition = condition->checkToBoolean();
895
896 sc->noctor++;
897
898 Scope *scd = sc->push();
899 scd->sbreak = this;
900 scd->scontinue = this;
901 if (body)
902 body = body->semantic(scd);
903 scd->pop();
904
905 sc->noctor--;
906
907 return this;
908 }
909
910 int WhileStatement::hasBreak()
911 {
912 return TRUE;
913 }
914
915 int WhileStatement::hasContinue()
916 {
917 return TRUE;
918 }
919
920 int WhileStatement::usesEH()
921 {
922 return body ? body->usesEH() : 0;
923 }
924
925 int WhileStatement::blockExit()
926 {
927 //printf("WhileStatement::blockExit(%p)\n", this);
928
929 int result = BEnone;
930 if (condition->canThrow())
931 result |= BEthrow;
932 if (condition->isBool(TRUE))
933 {
934 if (body)
935 { result |= body->blockExit();
936 if (result & BEbreak)
937 result |= BEfallthru;
938 }
939 }
940 else if (condition->isBool(FALSE))
941 {
942 result |= BEfallthru;
943 }
944 else
945 {
946 if (body)
947 result |= body->blockExit();
948 result |= BEfallthru;
949 }
950 result &= ~(BEbreak | BEcontinue);
951 return result;
952 }
953
954 int WhileStatement::fallOffEnd()
955 {
956 if (body)
957 body->fallOffEnd();
958 return TRUE;
959 }
960
961 int WhileStatement::comeFrom()
962 {
963 if (body)
964 return body->comeFrom();
965 return FALSE;
966 }
967
968 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
969 {
970 buf->writestring("while (");
971 condition->toCBuffer(buf, hgs);
972 buf->writebyte(')');
973 buf->writenl();
974 if (body)
975 body->toCBuffer(buf, hgs);
976 }
977
978 /******************************** DoStatement ***************************/
979
980 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
981 : Statement(loc)
982 {
983 body = b;
984 condition = c;
985 enclosinghandler = NULL;
986 }
987
988 Statement *DoStatement::syntaxCopy()
989 {
990 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
991 return s;
992 }
993
994
995 Statement *DoStatement::semantic(Scope *sc)
996 {
997 enclosinghandler = sc->tfOfTry;
998
999 sc->noctor++;
1000 if (body)
1001 body = body->semanticScope(sc, this, this);
1002 sc->noctor--;
1003 condition = condition->semantic(sc);
1004 condition = resolveProperties(sc, condition);
1005 condition = condition->optimize(WANTvalue);
1006
1007 condition = condition->checkToBoolean();
1008
1009 return this;
1010 }
1011
1012 int DoStatement::hasBreak()
1013 {
1014 return TRUE;
1015 }
1016
1017 int DoStatement::hasContinue()
1018 {
1019 return TRUE;
1020 }
1021
1022 int DoStatement::usesEH()
1023 {
1024 return body ? body->usesEH() : 0;
1025 }
1026
1027 int DoStatement::blockExit()
1028 { int result;
1029
1030 if (body)
1031 { result = body->blockExit();
1032 if (result == BEbreak)
1033 return BEfallthru;
1034 if (result & BEcontinue)
1035 result |= BEfallthru;
1036 }
1037 else
1038 result = BEfallthru;
1039 if (result & BEfallthru)
1040 { if (condition->canThrow())
1041 result |= BEthrow;
1042 if (!(result & BEbreak) && condition->isBool(TRUE))
1043 result &= ~BEfallthru;
1044 }
1045 result &= ~(BEbreak | BEcontinue);
1046 return result;
1047 }
1048
1049 int DoStatement::fallOffEnd()
1050 {
1051 if (body)
1052 body->fallOffEnd();
1053 return TRUE;
1054 }
1055
1056 int DoStatement::comeFrom()
1057 {
1058 if (body)
1059 return body->comeFrom();
1060 return FALSE;
1061 }
1062
1063 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1064 {
1065 buf->writestring("do");
1066 buf->writenl();
1067 if (body)
1068 body->toCBuffer(buf, hgs);
1069 buf->writestring("while (");
1070 condition->toCBuffer(buf, hgs);
1071 buf->writebyte(')');
1072 }
1073
1074 /******************************** ForStatement ***************************/
1075
1076 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1077 : Statement(loc)
1078 {
1079 this->init = init;
1080 this->condition = condition;
1081 this->increment = increment;
1082 this->body = body;
1083 this->enclosinghandler = NULL;
1084 }
1085
1086 Statement *ForStatement::syntaxCopy()
1087 {
1088 Statement *i = NULL;
1089 if (init)
1090 i = init->syntaxCopy();
1091 Expression *c = NULL;
1092 if (condition)
1093 c = condition->syntaxCopy();
1094 Expression *inc = NULL;
1095 if (increment)
1096 inc = increment->syntaxCopy();
1097 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1098 return s;
1099 }
1100
1101 Statement *ForStatement::semantic(Scope *sc)
1102 {
1103 enclosinghandler = sc->tfOfTry;
1104
1105 ScopeDsymbol *sym = new ScopeDsymbol();
1106 sym->parent = sc->scopesym;
1107 sc = sc->push(sym);
1108 if (init)
1109 init = init->semantic(sc);
1110 sc->noctor++;
1111 if (condition)
1112 {
1113 condition = condition->semantic(sc);
1114 condition = resolveProperties(sc, condition);
1115 condition = condition->optimize(WANTvalue);
1116 condition = condition->checkToBoolean();
1117 }
1118 if (increment)
1119 increment = increment->semantic(sc);
1120
1121 sc->sbreak = this;
1122 sc->scontinue = this;
1123 body = body->semantic(sc);
1124 sc->noctor--;
1125
1126 sc->pop();
1127 return this;
1128 }
1129
1130 void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
1131 {
1132 //printf("ForStatement::scopeCode()\n");
1133 //print();
1134 if (init)
1135 init->scopeCode(sc, sentry, sexception, sfinally);
1136 else
1137 Statement::scopeCode(sc, sentry, sexception, sfinally);
1138 }
1139
1140 int ForStatement::hasBreak()
1141 {
1142 //printf("ForStatement::hasBreak()\n");
1143 return TRUE;
1144 }
1145
1146 int ForStatement::hasContinue()
1147 {
1148 return TRUE;
1149 }
1150
1151 int ForStatement::usesEH()
1152 {
1153 return (init && init->usesEH()) || body->usesEH();
1154 }
1155
1156 int ForStatement::blockExit()
1157 { int result = BEfallthru;
1158
1159 if (init)
1160 { result = init->blockExit();
1161 if (!(result & BEfallthru))
1162 return result;
1163 }
1164 if (condition)
1165 { if (condition->canThrow())
1166 result |= BEthrow;
1167 }
1168 else
1169 result &= ~BEfallthru; // the body must do the exiting
1170 if (body)
1171 { int r = body->blockExit();
1172 if (r & BEbreak)
1173 result |= BEfallthru;
1174 result |= r & ~(BEbreak | BEcontinue);
1175 }
1176 if (increment && increment->canThrow())
1177 result |= BEthrow;
1178 return result;
1179 }
1180
1181 int ForStatement::fallOffEnd()
1182 {
1183 if (body)
1184 body->fallOffEnd();
1185 return TRUE;
1186 }
1187
1188 int ForStatement::comeFrom()
1189 {
1190 //printf("ForStatement::comeFrom()\n");
1191 if (body)
1192 { int result = body->comeFrom();
1193 //printf("result = %d\n", result);
1194 return result;
1195 }
1196 return FALSE;
1197 }
1198
1199 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1200 {
1201 buf->writestring("for (");
1202 if (init)
1203 {
1204 hgs->FLinit.init++;
1205 hgs->FLinit.decl = 0;
1206 init->toCBuffer(buf, hgs);
1207 if (hgs->FLinit.decl > 0)
1208 buf->writebyte(';');
1209 hgs->FLinit.decl = 0;
1210 hgs->FLinit.init--;
1211 }
1212 else
1213 buf->writebyte(';');
1214 if (condition)
1215 { buf->writebyte(' ');
1216 condition->toCBuffer(buf, hgs);
1217 }
1218 buf->writebyte(';');
1219 if (increment)
1220 { buf->writebyte(' ');
1221 increment->toCBuffer(buf, hgs);
1222 }
1223 buf->writebyte(')');
1224 buf->writenl();
1225 buf->writebyte('{');
1226 buf->writenl();
1227 body->toCBuffer(buf, hgs);
1228 buf->writebyte('}');
1229 buf->writenl();
1230 }
1231
1232 /******************************** ForeachStatement ***************************/
1233
1234 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1235 Expression *aggr, Statement *body)
1236 : Statement(loc)
1237 {
1238 this->op = op;
1239 this->arguments = arguments;
1240 this->aggr = aggr;
1241 this->body = body;
1242 this->enclosinghandler = NULL;
1243
1244 this->key = NULL;
1245 this->value = NULL;
1246
1247 this->func = NULL;
1248 }
1249
1250 Statement *ForeachStatement::syntaxCopy()
1251 {
1252 Arguments *args = Argument::arraySyntaxCopy(arguments);
1253 Expression *exp = aggr->syntaxCopy();
1254 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1255 body ? body->syntaxCopy() : NULL);
1256 return s;
1257 }
1258
1259 Statement *ForeachStatement::semantic(Scope *sc)
1260 {
1261 //printf("ForeachStatement::semantic() %p\n", this);
1262 ScopeDsymbol *sym;
1263 Statement *s = this;
1264 int dim = arguments->dim;
1265 int i;
1266 TypeAArray *taa = NULL;
1267
1268 Type *tn = NULL;
1269 Type *tnv = NULL;
1270
1271 enclosinghandler = sc->tfOfTry;
1272
1273 func = sc->func;
1274 if (func->fes)
1275 func = func->fes->func;
1276
1277 aggr = aggr->semantic(sc);
1278 aggr = resolveProperties(sc, aggr);
1279 aggr = aggr->optimize(WANTvalue);
1280 if (!aggr->type)
1281 {
1282 error("invalid foreach aggregate %s", aggr->toChars());
1283 return this;
1284 }
1285
1286 inferApplyArgTypes(op, arguments, aggr);
1287
1288 /* Check for inference errors
1289 */
1290 if (dim != arguments->dim)
1291 {
1292 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1293 error("cannot uniquely infer foreach argument types");
1294 return this;
1295 }
1296
1297 Type *tab = aggr->type->toBasetype();
1298
1299 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1300 {
1301 if (dim < 1 || dim > 2)
1302 {
1303 error("only one (value) or two (key,value) arguments for tuple foreach");
1304 return s;
1305 }
1306
1307 TypeTuple *tuple = (TypeTuple *)tab;
1308 Statements *statements = new Statements();
1309 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1310 size_t n;
1311 TupleExp *te = NULL;
1312 if (aggr->op == TOKtuple) // expression tuple
1313 { te = (TupleExp *)aggr;
1314 n = te->exps->dim;
1315 }
1316 else if (aggr->op == TOKtype) // type tuple
1317 {
1318 n = Argument::dim(tuple->arguments);
1319 }
1320 else
1321 assert(0);
1322 for (size_t j = 0; j < n; j++)
1323 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1324 Expression *e;
1325 Type *t;
1326 if (te)
1327 e = (Expression *)te->exps->data[k];
1328 else
1329 t = Argument::getNth(tuple->arguments, k)->type;
1330 Argument *arg = (Argument *)arguments->data[0];
1331 Statements *st = new Statements();
1332
1333 if (dim == 2)
1334 { // Declare key
1335 if (arg->storageClass & (STCout | STCref | STClazy))
1336 error("no storage class for key %s", arg->ident->toChars());
1337 TY keyty = arg->type->ty;
1338 if (global.params.is64bit)
1339 {
1340 if (keyty != Tint32 && keyty != Tuns32 && keyty != Tint64 && keyty != Tuns64)
1341 {
1342 error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars());
1343 }
1344 }
1345 else if (keyty != Tint32 && keyty != Tuns32)
1346 {
1347 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1348 }
1349 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1350 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1351 var->storage_class |= STCmanifest;
1352 DeclarationExp *de = new DeclarationExp(loc, var);
1353 st->push(new ExpStatement(loc, de));
1354 arg = (Argument *)arguments->data[1]; // value
1355 }
1356 // Declare value
1357 if (arg->storageClass & (STCout | STCref | STClazy))
1358 error("no storage class for value %s", arg->ident->toChars());
1359 Dsymbol *var;
1360 if (te)
1361 { Type *tb = e->type->toBasetype();
1362 if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
1363 { VarExp *ve = (VarExp *)e;
1364 var = new AliasDeclaration(loc, arg->ident, ve->var);
1365 }
1366 else
1367 {
1368 arg->type = e->type;
1369 Initializer *ie = new ExpInitializer(0, e);
1370 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1371 if (e->isConst())
1372 v->storage_class |= STCconst;
1373 var = v;
1374 }
1375 }
1376 else
1377 {
1378 var = new AliasDeclaration(loc, arg->ident, t);
1379 }
1380 DeclarationExp *de = new DeclarationExp(loc, var);
1381 st->push(new ExpStatement(loc, de));
1382
1383 st->push(body->syntaxCopy());
1384 s = new CompoundStatement(loc, st);
1385 s = new ScopeStatement(loc, s);
1386 statements->push(s);
1387 }
1388
1389 s = new UnrolledLoopStatement(loc, statements);
1390 s = s->semantic(sc);
1391 return s;
1392 }
1393
1394 for (i = 0; i < dim; i++)
1395 { Argument *arg = (Argument *)arguments->data[i];
1396 if (!arg->type)
1397 {
1398 error("cannot infer type for %s", arg->ident->toChars());
1399 return this;
1400 }
1401 }
1402
1403 sym = new ScopeDsymbol();
1404 sym->parent = sc->scopesym;
1405 sc = sc->push(sym);
1406
1407 sc->noctor++;
1408
1409 switch (tab->ty)
1410 {
1411 case Tarray:
1412 case Tsarray:
1413 if (dim < 1 || dim > 2)
1414 {
1415 error("only one or two arguments for array foreach");
1416 break;
1417 }
1418
1419 /* Look for special case of parsing char types out of char type
1420 * array.
1421 */
1422 tn = tab->nextOf()->toBasetype();
1423 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1424 { Argument *arg;
1425
1426 i = (dim == 1) ? 0 : 1; // index of value
1427 arg = (Argument *)arguments->data[i];
1428 arg->type = arg->type->semantic(loc, sc);
1429 tnv = arg->type->toBasetype();
1430 if (tnv->ty != tn->ty &&
1431 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1432 {
1433 if (arg->storageClass & STCref)
1434 error("foreach: value of UTF conversion cannot be ref");
1435 if (dim == 2)
1436 { arg = (Argument *)arguments->data[0];
1437 if (arg->storageClass & STCref)
1438 error("foreach: key cannot be ref");
1439 }
1440 goto Lapply;
1441 }
1442 }
1443
1444 for (i = 0; i < dim; i++)
1445 { // Declare args
1446 Argument *arg = (Argument *)arguments->data[i];
1447 VarDeclaration *var;
1448
1449 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1450 var->storage_class |= STCforeach;
1451 var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant);
1452 if (dim == 2 && i == 0)
1453 { key = var;
1454 //var->storage_class |= STCfinal;
1455 }
1456 else
1457 {
1458 value = var;
1459 /* Reference to immutable data should be marked as const
1460 */
1461 if (var->storage_class & STCref && !tn->isMutable())
1462 {
1463 var->storage_class |= STCconst;
1464 }
1465 }
1466 #if 1
1467 DeclarationExp *de = new DeclarationExp(loc, var);
1468 de->semantic(sc);
1469 #else
1470 var->semantic(sc);
1471 if (!sc->insert(var))
1472 error("%s already defined", var->ident->toChars());
1473 #endif
1474 }
1475
1476 sc->sbreak = this;
1477 sc->scontinue = this;
1478 body = body->semantic(sc);
1479
1480 if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst)
1481 {
1482 if (aggr->op == TOKstring)
1483 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1484 else
1485 error("foreach: %s is not an array of %s",
1486 tab->toChars(), value->type->toChars());
1487 }
1488
1489 if (key)
1490 {
1491 if (global.params.is64bit)
1492 {
1493 if (key->type->ty != Tint32 && key->type->ty != Tuns32 && key->type->ty != Tint64 && key->type->ty != Tuns64)
1494 {
1495 error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars());
1496 }
1497 }
1498 else if (key->type->ty != Tint32 && key->type->ty != Tuns32)
1499 {
1500 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1501 }
1502 }
1503
1504 if (key && key->storage_class & (STCout | STCref))
1505 error("foreach: key cannot be out or ref");
1506 break;
1507
1508 case Taarray:
1509 taa = (TypeAArray *)tab;
1510 if (dim < 1 || dim > 2)
1511 {
1512 error("only one or two arguments for associative array foreach");
1513 break;
1514 }
1515 if (op == TOKforeach_reverse)
1516 {
1517 error("no reverse iteration on associative arrays");
1518 }
1519 goto Lapply;
1520
1521 case Tclass:
1522 case Tstruct:
1523 case Tdelegate:
1524 Lapply:
1525 { FuncDeclaration *fdapply;
1526 Arguments *args;
1527 Expression *ec;
1528 Expression *e;
1529 FuncLiteralDeclaration *fld;
1530 Argument *a;
1531 Type *t;
1532 Expression *flde;
1533 Identifier *id;
1534 Type *tret;
1535 TypeDelegate* dgty;
1536 TypeDelegate* dgty2;
1537 TypeDelegate* fldeTy;
1538
1539 tret = func->type->nextOf();
1540
1541 // Need a variable to hold value from any return statements in body.
1542 if (!sc->func->vresult && tret && tret != Type::tvoid)
1543 { VarDeclaration *v;
1544
1545 v = new VarDeclaration(loc, tret, Id::result, NULL);
1546 v->noauto = 1;
1547 v->semantic(sc);
1548 if (!sc->insert(v))
1549 assert(0);
1550 v->parent = sc->func;
1551 sc->func->vresult = v;
1552 }
1553
1554 /* Turn body into the function literal:
1555 * int delegate(ref T arg) { body }
1556 */
1557 args = new Arguments();
1558 for (i = 0; i < dim; i++)
1559 { Argument *arg = (Argument *)arguments->data[i];
1560
1561 arg->type = arg->type->semantic(loc, sc);
1562 if (arg->storageClass & STCref)
1563 id = arg->ident;
1564 else
1565 { // Make a copy of the ref argument so it isn't
1566 // a reference.
1567 VarDeclaration *v;
1568 Initializer *ie;
1569
1570 id = Lexer::uniqueId("__applyArg", i);
1571
1572 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1573 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1574 s = new DeclarationStatement(0, v);
1575 body = new CompoundStatement(loc, s, body);
1576 }
1577 a = new Argument(STCref, arg->type, id, NULL);
1578 args->push(a);
1579 }
1580 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1581 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1582 fld->fbody = body;
1583 flde = new FuncExp(loc, fld);
1584 flde = flde->semantic(sc);
1585 fld->tookAddressOf = 0;
1586
1587 // Resolve any forward referenced goto's
1588 for (int i = 0; i < gotos.dim; i++)
1589 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1590 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1591
1592 if (!gs->label->statement)
1593 { // 'Promote' it to this scope, and replace with a return
1594 cases.push(gs);
1595 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1596 cs->statements->data[0] = (void *)s;
1597 }
1598 }
1599
1600 if (tab->ty == Taarray)
1601 {
1602 // Check types
1603 Argument *arg = (Argument *)arguments->data[0];
1604 if (dim == 2)
1605 {
1606 if (arg->storageClass & STCref)
1607 error("foreach: index cannot be ref");
1608 if (!arg->type->equals(taa->index))
1609 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1610 arg = (Argument *)arguments->data[1];
1611 }
1612 if (!arg->type->equals(taa->nextOf()))
1613 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1614
1615 /* Call:
1616 * _aaApply(aggr, keysize, flde)
1617 */
1618 //LDC: Build arguments.
1619 static FuncDeclaration *aaApply2_fd = NULL;
1620 static TypeDelegate* aaApply2_dg;
1621 if(!aaApply2_fd) {
1622 Arguments* args = new Arguments;
1623 args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
1624 args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
1625 Arguments* dgargs = new Arguments;
1626 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1627 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1628 aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
1629 args->push(new Argument(STCin, aaApply2_dg, NULL, NULL));
1630 aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2");
1631 }
1632 static FuncDeclaration *aaApply_fd = NULL;
1633 static TypeDelegate* aaApply_dg;
1634 if(!aaApply_fd) {
1635 Arguments* args = new Arguments;
1636 args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
1637 args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
1638 Arguments* dgargs = new Arguments;
1639 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1640 aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
1641 args->push(new Argument(STCin, aaApply_dg, NULL, NULL));
1642 aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply");
1643 }
1644 if (dim == 2) {
1645 fdapply = aaApply2_fd;
1646 fldeTy = aaApply2_dg;
1647 } else {
1648 fdapply = aaApply_fd;
1649 fldeTy = aaApply_dg;
1650 }
1651 ec = new VarExp(0, fdapply);
1652 Expressions *exps = new Expressions();
1653 exps->push(aggr);
1654 size_t keysize = taa->index->size();
1655 keysize = (keysize + 3) & ~3;
1656 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1657
1658 // LDC paint delegate argument to the type runtime expects
1659 if (!fldeTy->equals(flde->type))
1660 {
1661 flde = new CastExp(loc, flde, flde->type);
1662 flde->type = fldeTy;
1663 }
1664 exps->push(flde);
1665
1666 e = new CallExp(loc, ec, exps);
1667 e->type = Type::tindex; // don't run semantic() on e
1668 }
1669 else if (tab->ty == Tarray || tab->ty == Tsarray)
1670 {
1671 /* Call:
1672 * _aApply(aggr, flde)
1673 */
1674 static char fntab[9][3] =
1675 { "cc","cw","cd",
1676 "wc","cc","wd",
1677 "dc","dw","dd"
1678 };
1679 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1680 int flag;
1681
1682 switch (tn->ty)
1683 {
1684 case Tchar: flag = 0; break;
1685 case Twchar: flag = 3; break;
1686 case Tdchar: flag = 6; break;
1687 default: assert(0);
1688 }
1689 switch (tnv->ty)
1690 {
1691 case Tchar: flag += 0; break;
1692 case Twchar: flag += 1; break;
1693 case Tdchar: flag += 2; break;
1694 default: assert(0);
1695 }
1696 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1697 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1698 assert(j < sizeof(fdname));
1699 //LDC: Build arguments.
1700 Arguments* args = new Arguments;
1701 args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL));
1702 if (dim == 2) {
1703 Arguments* dgargs = new Arguments;
1704 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1705 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1706 dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
1707 args->push(new Argument(STCin, dgty, NULL, NULL));
1708 fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
1709 } else {
1710 Arguments* dgargs = new Arguments;
1711 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
1712 dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
1713 args->push(new Argument(STCin, dgty, NULL, NULL));
1714 fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
1715 }
1716
1717 ec = new VarExp(0, fdapply);
1718 Expressions *exps = new Expressions();
1719 if (tab->ty == Tsarray)
1720 aggr = aggr->castTo(sc, tn->arrayOf());
1721 exps->push(aggr);
1722
1723 // LDC paint delegate argument to the type runtime expects
1724 if (!dgty->equals(flde->type))
1725 {
1726 flde = new CastExp(loc, flde, flde->type);
1727 flde->type = dgty;
1728 }
1729 exps->push(flde);
1730
1731 e = new CallExp(loc, ec, exps);
1732 e->type = Type::tindex; // don't run semantic() on e
1733 }
1734 else if (tab->ty == Tdelegate)
1735 {
1736 /* Call:
1737 * aggr(flde)
1738 */
1739 Expressions *exps = new Expressions();
1740 exps->push(flde);
1741 e = new CallExp(loc, aggr, exps);
1742 e = e->semantic(sc);
1743 if (e->type != Type::tint32)
1744 error("opApply() function for %s must return an int", tab->toChars());
1745 }
1746 else
1747 {
1748 assert(tab->ty == Tstruct || tab->ty == Tclass);
1749 Identifier *idapply = (op == TOKforeach_reverse)
1750 ? Id::applyReverse : Id::apply;
1751 Dsymbol *sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply);
1752 Expressions *exps = new Expressions();
1753 #if 0
1754 TemplateDeclaration *td;
1755 if (sapply &&
1756 (td = sapply->isTemplateDeclaration()) != NULL)
1757 { /* Call:
1758 * aggr.apply!(fld)()
1759 */
1760 TemplateInstance *ti = new TemplateInstance(loc, idapply);
1761 Objects *tiargs = new Objects();
1762 tiargs->push(fld);
1763 ti->tiargs = tiargs;
1764 ec = new DotTemplateInstanceExp(loc, aggr, ti);
1765 }
1766 else
1767 #endif
1768 {
1769 /* Call:
1770 * aggr.apply(flde)
1771 */
1772 ec = new DotIdExp(loc, aggr, idapply);
1773 exps->push(flde);
1774 }
1775 e = new CallExp(loc, ec, exps);
1776 e = e->semantic(sc);
1777 if (e->type != Type::tint32)
1778 error("opApply() function for %s must return an int", tab->toChars());
1779 }
1780
1781 if (!cases.dim)
1782 // Easy case, a clean exit from the loop
1783 s = new ExpStatement(loc, e);
1784 else
1785 { // Construct a switch statement around the return value
1786 // of the apply function.
1787 Statements *a = new Statements();
1788
1789 // default: break; takes care of cases 0 and 1
1790 s = new BreakStatement(0, NULL);
1791 s = new DefaultStatement(0, s);
1792 a->push(s);
1793
1794 // cases 2...
1795 for (int i = 0; i < cases.dim; i++)
1796 {
1797 s = (Statement *)cases.data[i];
1798 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1799 a->push(s);
1800 }
1801
1802 s = new CompoundStatement(loc, a);
1803 s = new SwitchStatement(loc, e, s);
1804 s = s->semantic(sc);
1805 }
1806 break;
1807 }
1808
1809 default:
1810 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1811 break;
1812 }
1813 sc->noctor--;
1814 sc->pop();
1815 return s;
1816 }
1817
1818 int ForeachStatement::hasBreak()
1819 {
1820 return TRUE;
1821 }
1822
1823 int ForeachStatement::hasContinue()
1824 {
1825 return TRUE;
1826 }
1827
1828 int ForeachStatement::usesEH()
1829 {
1830 return body->usesEH();
1831 }
1832
1833 int ForeachStatement::blockExit()
1834 { int result = BEfallthru;
1835
1836 if (aggr->canThrow())
1837 result |= BEthrow;
1838
1839 if (body)
1840 {
1841 result |= body->blockExit() & ~(BEbreak | BEcontinue);
1842 }
1843 return result;
1844 }
1845
1846 int ForeachStatement::fallOffEnd()
1847 {
1848 if (body)
1849 body->fallOffEnd();
1850 return TRUE;
1851 }
1852
1853 int ForeachStatement::comeFrom()
1854 {
1855 if (body)
1856 return body->comeFrom();
1857 return FALSE;
1858 }
1859
1860 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1861 {
1862 buf->writestring(Token::toChars(op));
1863 buf->writestring(" (");
1864 for (int i = 0; i < arguments->dim; i++)
1865 {
1866 Argument *a = (Argument *)arguments->data[i];
1867 if (i)
1868 buf->writestring(", ");
1869 if (a->storageClass & STCref)
1870 buf->writestring((global.params.Dversion == 1)
1871 ? (char*)"inout " : (char*)"ref ");
1872 if (a->type)
1873 a->type->toCBuffer(buf, a->ident, hgs);
1874 else
1875 buf->writestring(a->ident->toChars());
1876 }
1877 buf->writestring("; ");
1878 aggr->toCBuffer(buf, hgs);
1879 buf->writebyte(')');
1880 buf->writenl();
1881 buf->writebyte('{');
1882 buf->writenl();
1883 if (body)
1884 body->toCBuffer(buf, hgs);
1885 buf->writebyte('}');
1886 buf->writenl();
1887 }
1888
1889 /**************************** ForeachRangeStatement ***************************/
1890
1891 ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg,
1892 Expression *lwr, Expression *upr, Statement *body)
1893 : Statement(loc)
1894 {
1895 this->op = op;
1896 this->arg = arg;
1897 this->lwr = lwr;
1898 this->upr = upr;
1899 this->body = body;
1900
1901 this->enclosinghandler = NULL;
1902
1903 this->key = NULL;
1904 }
1905
1906 Statement *ForeachRangeStatement::syntaxCopy()
1907 {
1908 ForeachRangeStatement *s = new ForeachRangeStatement(loc, op,
1909 arg->syntaxCopy(),
1910 lwr->syntaxCopy(),
1911 upr->syntaxCopy(),
1912 body ? body->syntaxCopy() : NULL);
1913 return s;
1914 }
1915
1916 Statement *ForeachRangeStatement::semantic(Scope *sc)
1917 {
1918 //printf("ForeachRangeStatement::semantic() %p\n", this);
1919 ScopeDsymbol *sym;
1920 Statement *s = this;
1921
1922 enclosinghandler = sc->tfOfTry;
1923
1924 lwr = lwr->semantic(sc);
1925 lwr = resolveProperties(sc, lwr);
1926 lwr = lwr->optimize(WANTvalue);
1927 if (!lwr->type)
1928 {
1929 error("invalid range lower bound %s", lwr->toChars());
1930 return this;
1931 }
1932
1933 upr = upr->semantic(sc);
1934 upr = resolveProperties(sc, upr);
1935 upr = upr->optimize(WANTvalue);
1936 if (!upr->type)
1937 {
1938 error("invalid range upper bound %s", upr->toChars());
1939 return this;
1940 }
1941
1942 if (arg->type)
1943 {
1944 lwr = lwr->implicitCastTo(sc, arg->type);
1945 upr = upr->implicitCastTo(sc, arg->type);
1946 }
1947 else
1948 {
1949 /* Must infer types from lwr and upr
1950 */
1951 AddExp ea(loc, lwr, upr);
1952 ea.typeCombine(sc);
1953 arg->type = ea.type->mutableOf();
1954 lwr = ea.e1;
1955 upr = ea.e2;
1956 }
1957 if (!arg->type->isscalar())
1958 error("%s is not a scalar type", arg->type->toChars());
1959
1960 sym = new ScopeDsymbol();
1961 sym->parent = sc->scopesym;
1962 sc = sc->push(sym);
1963
1964 sc->noctor++;
1965
1966 key = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1967 DeclarationExp *de = new DeclarationExp(loc, key);
1968 de->semantic(sc);
1969
1970 if (key->storage_class)
1971 error("foreach range: key cannot have storage class");
1972
1973 sc->sbreak = this;
1974 sc->scontinue = this;
1975 body = body->semantic(sc);
1976
1977 sc->noctor--;
1978 sc->pop();
1979 return s;
1980 }
1981
1982 int ForeachRangeStatement::hasBreak()
1983 {
1984 return TRUE;
1985 }
1986
1987 int ForeachRangeStatement::hasContinue()
1988 {
1989 return TRUE;
1990 }
1991
1992 int ForeachRangeStatement::usesEH()
1993 {
1994 return body->usesEH();
1995 }
1996
1997 int ForeachRangeStatement::blockExit()
1998 { int result = BEfallthru;
1999
2000 if (lwr && lwr->canThrow())
2001 result |= BEthrow;
2002 else if (upr && upr->canThrow())
2003 result |= BEthrow;
2004
2005 if (body)
2006 {
2007 result |= body->blockExit() & ~(BEbreak | BEcontinue);
2008 }
2009 return result;
2010 }
2011
2012 int ForeachRangeStatement::fallOffEnd()
2013 {
2014 if (body)
2015 body->fallOffEnd();
2016 return TRUE;
2017 }
2018
2019 int ForeachRangeStatement::comeFrom()
2020 {
2021 if (body)
2022 return body->comeFrom();
2023 return FALSE;
2024 }
2025
2026 void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2027 {
2028 buf->writestring(Token::toChars(op));
2029 buf->writestring(" (");
2030
2031 if (arg->type)
2032 arg->type->toCBuffer(buf, arg->ident, hgs);
2033 else
2034 buf->writestring(arg->ident->toChars());
2035
2036 buf->writestring("; ");
2037 lwr->toCBuffer(buf, hgs);
2038 buf->writestring(" .. ");
2039 upr->toCBuffer(buf, hgs);
2040 buf->writebyte(')');
2041 buf->writenl();
2042 buf->writebyte('{');
2043 buf->writenl();
2044 if (body)
2045 body->toCBuffer(buf, hgs);
2046 buf->writebyte('}');
2047 buf->writenl();
2048 }
2049
2050 /******************************** IfStatement ***************************/
2051
2052 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
2053 : Statement(loc)
2054 {
2055 this->arg = arg;
2056 this->condition = condition;
2057 this->ifbody = ifbody;
2058 this->elsebody = elsebody;
2059 this->match = NULL;
2060 }
2061
2062 Statement *IfStatement::syntaxCopy()
2063 {
2064 Statement *i = NULL;
2065 if (ifbody)
2066 i = ifbody->syntaxCopy();
2067
2068 Statement *e = NULL;
2069 if (elsebody)
2070 e = elsebody->syntaxCopy();
2071
2072 Argument *a = arg ? arg->syntaxCopy() : NULL;
2073 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
2074 return s;
2075 }
2076
2077 Statement *IfStatement::semantic(Scope *sc)
2078 {
2079 condition = condition->semantic(sc);
2080 condition = resolveProperties(sc, condition);
2081 condition = condition->checkToBoolean();
2082
2083 // If we can short-circuit evaluate the if statement, don't do the
2084 // semantic analysis of the skipped code.
2085 // This feature allows a limited form of conditional compilation.
2086 condition = condition->optimize(WANTflags);
2087
2088 // Evaluate at runtime
2089 unsigned cs0 = sc->callSuper;
2090 unsigned cs1;
2091
2092 Scope *scd;
2093 if (arg)
2094 { /* Declare arg, which we will set to be the
2095 * result of condition.
2096 */
2097 ScopeDsymbol *sym = new ScopeDsymbol();
2098 sym->parent = sc->scopesym;
2099 scd = sc->push(sym);
2100
2101 Type *t = arg->type ? arg->type : condition->type;
2102 match = new VarDeclaration(loc, t, arg->ident, NULL);
2103 match->noauto = 1;
2104 match->semantic(scd);
2105 if (!scd->insert(match))
2106 assert(0);
2107 match->parent = sc->func;
2108
2109 /* Generate:
2110 * (arg = condition)
2111 */
2112 VarExp *v = new VarExp(0, match);
2113 condition = new AssignExp(loc, v, condition);
2114 condition = condition->semantic(scd);
2115 }
2116 else
2117 scd = sc->push();
2118 ifbody = ifbody->semantic(scd);
2119 scd->pop();
2120
2121 cs1 = sc->callSuper;
2122 sc->callSuper = cs0;
2123 if (elsebody)
2124 elsebody = elsebody->semanticScope(sc, NULL, NULL);
2125 sc->mergeCallSuper(loc, cs1);
2126
2127 return this;
2128 }
2129
2130 int IfStatement::usesEH()
2131 {
2132 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2133 }
2134
2135 int IfStatement::blockExit()
2136 {
2137 //printf("IfStatement::blockExit(%p)\n", this);
2138
2139 int result = BEnone;
2140 if (condition->canThrow())
2141 result |= BEthrow;
2142 if (condition->isBool(TRUE))
2143 {
2144 if (ifbody)
2145 result |= ifbody->blockExit();
2146 else
2147 result |= BEfallthru;
2148 }
2149 else if (condition->isBool(FALSE))
2150 {
2151 if (elsebody)
2152 result |= elsebody->blockExit();
2153 else
2154 result |= BEfallthru;
2155 }
2156 else
2157 {
2158 if (ifbody)
2159 result |= ifbody->blockExit();
2160 else
2161 result |= BEfallthru;
2162 if (elsebody)
2163 result |= elsebody->blockExit();
2164 else
2165 result |= BEfallthru;
2166 }
2167 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2168 return result;
2169 }
2170
2171 int IfStatement::fallOffEnd()
2172 {
2173 if (!ifbody || ifbody->fallOffEnd() ||
2174 !elsebody || elsebody->fallOffEnd())
2175 return TRUE;
2176 return FALSE;
2177 }
2178
2179
2180 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2181 {
2182 buf->writestring("if (");
2183 if (arg)
2184 {
2185 if (arg->type)
2186 arg->type->toCBuffer(buf, arg->ident, hgs);
2187 else
2188 { buf->writestring("auto ");
2189 buf->writestring(arg->ident->toChars());
2190 }
2191 buf->writestring(" = ");
2192 }
2193 condition->toCBuffer(buf, hgs);
2194 buf->writebyte(')');
2195 buf->writenl();
2196 ifbody->toCBuffer(buf, hgs);
2197 if (elsebody)
2198 { buf->writestring("else");
2199 buf->writenl();
2200 elsebody->toCBuffer(buf, hgs);
2201 }
2202 }
2203
2204 /******************************** ConditionalStatement ***************************/
2205
2206 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
2207 : Statement(loc)
2208 {
2209 this->condition = condition;
2210 this->ifbody = ifbody;
2211 this->elsebody = elsebody;
2212 }
2213
2214 Statement *ConditionalStatement::syntaxCopy()
2215 {
2216 Statement *e = NULL;
2217 if (elsebody)
2218 e = elsebody->syntaxCopy();
2219 ConditionalStatement *s = new ConditionalStatement(loc,
2220 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
2221 return s;
2222 }
2223
2224 Statement *ConditionalStatement::semantic(Scope *sc)
2225 {
2226 //printf("ConditionalStatement::semantic()\n");
2227
2228 // If we can short-circuit evaluate the if statement, don't do the
2229 // semantic analysis of the skipped code.
2230 // This feature allows a limited form of conditional compilation.
2231 if (condition->include(sc, NULL))
2232 {
2233 ifbody = ifbody->semantic(sc);
2234 return ifbody;
2235 }
2236 else
2237 {
2238 if (elsebody)
2239 elsebody = elsebody->semantic(sc);
2240 return elsebody;
2241 }
2242 }
2243
2244 Statements *ConditionalStatement::flatten(Scope *sc)
2245 {
2246 Statement *s;
2247
2248 if (condition->include(sc, NULL))
2249 s = ifbody;
2250 else
2251 s = elsebody;
2252
2253 Statements *a = new Statements();
2254 a->push(s);
2255 return a;
2256 }
2257
2258 int ConditionalStatement::usesEH()
2259 {
2260 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2261 }
2262
2263 int ConditionalStatement::blockExit()
2264 {
2265 int result = ifbody->blockExit();
2266 if (elsebody)
2267 result |= elsebody->blockExit();
2268 return result;
2269 }
2270
2271 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2272 {
2273 condition->toCBuffer(buf, hgs);
2274 buf->writenl();
2275 buf->writeByte('{');
2276 buf->writenl();
2277 if (ifbody)
2278 ifbody->toCBuffer(buf, hgs);
2279 buf->writeByte('}');
2280 buf->writenl();
2281 if (elsebody)
2282 {
2283 buf->writestring("else");
2284 buf->writenl();
2285 buf->writeByte('{');
2286 buf->writenl();
2287 elsebody->toCBuffer(buf, hgs);
2288 buf->writeByte('}');
2289 buf->writenl();
2290 }
2291 buf->writenl();
2292 }
2293
2294
2295 /******************************** PragmaStatement ***************************/
2296
2297 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
2298 : Statement(loc)
2299 {
2300 this->ident = ident;
2301 this->args = args;
2302 this->body = body;
2303 }
2304
2305 Statement *PragmaStatement::syntaxCopy()
2306 {
2307 Statement *b = NULL;
2308 if (body)
2309 b = body->syntaxCopy();
2310 PragmaStatement *s = new PragmaStatement(loc,
2311 ident, Expression::arraySyntaxCopy(args), b);
2312 return s;
2313 }
2314
2315 Statement *PragmaStatement::semantic(Scope *sc)
2316 { // Should be merged with PragmaDeclaration
2317 //printf("PragmaStatement::semantic() %s\n", toChars());
2318 //printf("body = %p\n", body);
2319 if (ident == Id::msg)
2320 {
2321 if (args)
2322 {
2323 for (size_t i = 0; i < args->dim; i++)
2324 {
2325 Expression *e = (Expression *)args->data[i];
2326
2327 e = e->semantic(sc);
2328 e = e->optimize(WANTvalue | WANTinterpret);
2329 if (e->op == TOKstring)
2330 {
2331 StringExp *se = (StringExp *)e;
2332 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
2333 }
2334 else
2335 error("string expected for message, not '%s'", e->toChars());
2336 }
2337 fprintf(stdmsg, "\n");
2338 }
2339 }
2340 else if (ident == Id::lib)
2341 {
2342 if (!args || args->dim != 1)
2343 error("string expected for library name");
2344 else
2345 {
2346 Expression *e = (Expression *)args->data[0];
2347
2348 e = e->semantic(sc);
2349 e = e->optimize(WANTvalue | WANTinterpret);
2350 args->data[0] = (void *)e;
2351 if (e->op != TOKstring)
2352 error("string expected for library name, not '%s'", e->toChars());
2353 else if (global.params.verbose)
2354 {
2355 StringExp *se = (StringExp *)e;
2356 char *name = (char *)mem.malloc(se->len + 1);
2357 memcpy(name, se->string, se->len);
2358 name[se->len] = 0;
2359 printf("library %s\n", name);
2360 mem.free(name);
2361 }
2362 }
2363 }
2364 else if (ident == Id::startaddress)
2365 {
2366 if (!args || args->dim != 1)
2367 error("function name expected for start address");
2368 else
2369 {
2370 Expression *e = (Expression *)args->data[0];
2371 e = e->semantic(sc);
2372 e = e->optimize(WANTvalue | WANTinterpret);
2373 args->data[0] = (void *)e;
2374 Dsymbol *sa = getDsymbol(e);
2375 if (!sa || !sa->isFuncDeclaration())
2376 error("function name expected for start address, not '%s'", e->toChars());
2377 if (body)
2378 {
2379 body = body->semantic(sc);
2380 }
2381 return this;
2382 }
2383 }
2384 else
2385 error("unrecognized pragma(%s)", ident->toChars());
2386
2387 if (body)
2388 {
2389 body = body->semantic(sc);
2390 }
2391 return body;
2392 }
2393
2394 int PragmaStatement::usesEH()
2395 {
2396 return body && body->usesEH();
2397 }
2398
2399 int PragmaStatement::blockExit()
2400 {
2401 int result = BEfallthru;
2402 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2403 if (arrayExpressionCanThrow(args))
2404 result |= BEthrow;
2405 if (body)
2406 result |= body->blockExit();
2407 #endif
2408 return result;
2409 }
2410
2411 int PragmaStatement::fallOffEnd()
2412 {
2413 if (body)
2414 return body->fallOffEnd();
2415 return TRUE;
2416 }
2417
2418 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2419 {
2420 buf->writestring("pragma (");
2421 buf->writestring(ident->toChars());
2422 if (args && args->dim)
2423 {
2424 buf->writestring(", ");
2425 argsToCBuffer(buf, args, hgs);
2426 }
2427 buf->writeByte(')');
2428 if (body)
2429 {
2430 buf->writenl();
2431 buf->writeByte('{');
2432 buf->writenl();
2433
2434 body->toCBuffer(buf, hgs);
2435
2436 buf->writeByte('}');
2437 buf->writenl();
2438 }
2439 else
2440 {
2441 buf->writeByte(';');
2442 buf->writenl();
2443 }
2444 }
2445
2446
2447 /******************************** StaticAssertStatement ***************************/
2448
2449 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2450 : Statement(sa->loc)
2451 {
2452 this->sa = sa;
2453 }
2454
2455 Statement *StaticAssertStatement::syntaxCopy()
2456 {
2457 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2458 return s;
2459 }
2460
2461 Statement *StaticAssertStatement::semantic(Scope *sc)
2462 {
2463 sa->semantic2(sc);
2464 return NULL;
2465 }
2466
2467 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2468 {
2469 sa->toCBuffer(buf, hgs);
2470 }
2471
2472
2473 /******************************** SwitchStatement ***************************/
2474
2475 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2476 : Statement(loc)
2477 {
2478 condition = c;
2479 body = b;
2480 sdefault = NULL;
2481 tf = NULL;
2482 cases = NULL;
2483 hasNoDefault = 0;
2484 hasVars = 0;
2485 // LDC
2486 enclosinghandler = NULL;
2487 }
2488
2489 Statement *SwitchStatement::syntaxCopy()
2490 {
2491 SwitchStatement *s = new SwitchStatement(loc,
2492 condition->syntaxCopy(), body->syntaxCopy());
2493 return s;
2494 }
2495
2496 Statement *SwitchStatement::semantic(Scope *sc)
2497 {
2498 //printf("SwitchStatement::semantic(%p)\n", this);
2499 tf = sc->tf;
2500 assert(!cases); // ensure semantic() is only run once
2501
2502 enclosinghandler = sc->tfOfTry;
2503
2504 condition = condition->semantic(sc);
2505 condition = resolveProperties(sc, condition);
2506 if (condition->type->isString())
2507 {
2508 // If it's not an array, cast it to one
2509 if (condition->type->ty != Tarray)
2510 {
2511 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2512 }
2513 condition->type = condition->type->constOf();
2514 }
2515 else
2516 { condition = condition->integralPromotions(sc);
2517 condition->checkIntegral();
2518 }
2519 condition = condition->optimize(WANTvalue);
2520
2521 sc = sc->push();
2522 sc->sbreak = this;
2523 sc->sw = this;
2524
2525 cases = new Array();
2526 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2527 body = body->semantic(sc);
2528 sc->noctor--;
2529
2530 // Resolve any goto case's with exp
2531 for (int i = 0; i < gotoCases.dim; i++)
2532 {
2533 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2534
2535 if (!gcs->exp)
2536 {
2537 gcs->error("no case statement following goto case;");
2538 break;
2539 }
2540
2541 for (Scope *scx = sc; scx; scx = scx->enclosing)
2542 {
2543 if (!scx->sw)
2544 continue;
2545 for (int j = 0; j < scx->sw->cases->dim; j++)
2546 {
2547 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2548
2549 if (cs->exp->equals(gcs->exp))
2550 {
2551 gcs->cs = cs;
2552 goto Lfoundcase;
2553 }
2554 }
2555 }
2556 gcs->error("case %s not found", gcs->exp->toChars());
2557
2558 Lfoundcase:
2559 ;
2560 }
2561
2562 if (!sc->sw->sdefault)
2563 { hasNoDefault = 1;
2564
2565 if (global.params.warnings)
2566 { warning("%s: switch statement has no default", loc.toChars());
2567 }
2568
2569 // Generate runtime error if the default is hit
2570 Statements *a = new Statements();
2571 CompoundStatement *cs;
2572 Statement *s;
2573
2574 if (global.params.useSwitchError)
2575 s = new SwitchErrorStatement(loc);
2576 else
2577 { Expression *e = new HaltExp(loc);
2578 s = new ExpStatement(loc, e);
2579 }
2580
2581 a->reserve(4);
2582 a->push(body);
2583 a->push(new BreakStatement(loc, NULL));
2584 sc->sw->sdefault = new DefaultStatement(loc, s);
2585 a->push(sc->sw->sdefault);
2586 cs = new CompoundStatement(loc, a);
2587 body = cs;
2588 }
2589
2590 sc->pop();
2591 return this;
2592 }
2593
2594 int SwitchStatement::hasBreak()
2595 {
2596 return TRUE;
2597 }
2598
2599 int SwitchStatement::usesEH()
2600 {
2601 return body ? body->usesEH() : 0;
2602 }
2603
2604 int SwitchStatement::blockExit()
2605 { int result = BEnone;
2606 if (condition->canThrow())
2607 result |= BEthrow;
2608
2609 if (body)
2610 { result |= body->blockExit();
2611 if (result & BEbreak)
2612 { result |= BEfallthru;
2613 result &= ~BEbreak;
2614 }
2615 }
2616 else
2617 result |= BEfallthru;
2618
2619 return result;
2620 }
2621
2622 int SwitchStatement::fallOffEnd()
2623 {
2624 if (body)
2625 body->fallOffEnd();
2626 return TRUE; // need to do this better
2627 }
2628
2629 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2630 {
2631 buf->writestring("switch (");
2632 condition->toCBuffer(buf, hgs);
2633 buf->writebyte(')');
2634 buf->writenl();
2635 if (body)
2636 {
2637 if (!body->isScopeStatement())
2638 { buf->writebyte('{');
2639 buf->writenl();
2640 body->toCBuffer(buf, hgs);
2641 buf->writebyte('}');
2642 buf->writenl();
2643 }
2644 else
2645 {
2646 body->toCBuffer(buf, hgs);
2647 }
2648 }
2649 }
2650
2651 /******************************** CaseStatement ***************************/
2652
2653 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2654 : Statement(loc)
2655 {
2656 this->exp = exp;
2657 this->statement = s;
2658 index = 0;
2659 cblock = NULL;
2660 bodyBB = NULL;
2661 llvmIdx = NULL;
2662 }
2663
2664 Statement *CaseStatement::syntaxCopy()
2665 {
2666 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2667 return s;
2668 }
2669
2670 Statement *CaseStatement::semantic(Scope *sc)
2671 { SwitchStatement *sw = sc->sw;
2672
2673 //printf("CaseStatement::semantic() %s\n", toChars());
2674 exp = exp->semantic(sc);
2675 if (sw)
2676 {
2677 exp = exp->implicitCastTo(sc, sw->condition->type);
2678 exp = exp->optimize(WANTvalue | WANTinterpret);
2679
2680 /* This is where variables are allowed as case expressions.
2681 */
2682 if (exp->op == TOKvar)
2683 { VarExp *ve = (VarExp *)exp;
2684 VarDeclaration *v = ve->var->isVarDeclaration();
2685 Type *t = exp->type->toBasetype();
2686 if (v && (t->isintegral() || t->ty == Tclass))
2687 { /* Flag that we need to do special code generation
2688 * for this, i.e. generate a sequence of if-then-else
2689 */
2690 sw->hasVars = 1;
2691 goto L1;
2692 }
2693 }
2694
2695 if (exp->op != TOKstring && exp->op != TOKint64)
2696 {
2697 error("case must be a string or an integral constant, not %s", exp->toChars());
2698 exp = new IntegerExp(0);
2699 }
2700
2701 L1:
2702 for (int i = 0; i < sw->cases->dim; i++)
2703 {
2704 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2705
2706 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2707 if (cs->exp->equals(exp))
2708 { error("duplicate case %s in switch statement", exp->toChars());
2709 break;
2710 }
2711 }
2712
2713 sw->cases->push(this);
2714
2715 // Resolve any goto case's with no exp to this case statement
2716 for (int i = 0; i < sw->gotoCases.dim; i++)
2717 {
2718 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2719
2720 if (!gcs->exp)
2721 {
2722 gcs->cs = this;
2723 sw->gotoCases.remove(i); // remove from array
2724 }
2725 }
2726
2727 if (sc->sw->tf != sc->tf)
2728 error("switch and case are in different finally blocks");
2729 }
2730 else
2731 error("case not in switch statement");
2732 statement = statement->semantic(sc);
2733 return this;
2734 }
2735
2736 int CaseStatement::compare(Object *obj)
2737 {
2738 // Sort cases so we can do an efficient lookup
2739 CaseStatement *cs2 = (CaseStatement *)(obj);
2740
2741 return exp->compare(cs2->exp);
2742 }
2743
2744 int CaseStatement::usesEH()
2745 {
2746 return statement->usesEH();
2747 }
2748
2749 int CaseStatement::blockExit()
2750 {
2751 return statement->blockExit();
2752 }
2753
2754 int CaseStatement::fallOffEnd()
2755 {
2756 return statement->fallOffEnd();
2757 }
2758
2759 int CaseStatement::comeFrom()
2760 {
2761 return TRUE;
2762 }
2763
2764 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2765 {
2766 buf->writestring("case ");
2767 exp->toCBuffer(buf, hgs);
2768 buf->writebyte(':');
2769 buf->writenl();
2770 statement->toCBuffer(buf, hgs);
2771 }
2772
2773 /******************************** DefaultStatement ***************************/
2774
2775 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2776 : Statement(loc)
2777 {
2778 this->statement = s;
2779 #if IN_GCC
2780 + cblock = NULL;
2781 #endif
2782 bodyBB = NULL;
2783 }
2784
2785 Statement *DefaultStatement::syntaxCopy()
2786 {
2787 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2788 return s;
2789 }
2790
2791 Statement *DefaultStatement::semantic(Scope *sc)
2792 {
2793 //printf("DefaultStatement::semantic()\n");
2794 if (sc->sw)
2795 {
2796 if (sc->sw->sdefault)
2797 {
2798 error("switch statement already has a default");
2799 }
2800 sc->sw->sdefault = this;
2801
2802 if (sc->sw->tf != sc->tf)
2803 error("switch and default are in different finally blocks");
2804 }
2805 else
2806 error("default not in switch statement");
2807 statement = statement->semantic(sc);
2808 return this;
2809 }
2810
2811 int DefaultStatement::usesEH()
2812 {
2813 return statement->usesEH();
2814 }
2815
2816 int DefaultStatement::blockExit()
2817 {
2818 return statement->blockExit();
2819 }
2820
2821 int DefaultStatement::fallOffEnd()
2822 {
2823 return statement->fallOffEnd();
2824 }
2825
2826 int DefaultStatement::comeFrom()
2827 {
2828 return TRUE;
2829 }
2830
2831 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2832 {
2833 buf->writestring("default:\n");
2834 statement->toCBuffer(buf, hgs);
2835 }
2836
2837 /******************************** GotoDefaultStatement ***************************/
2838
2839 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2840 : Statement(loc)
2841 {
2842 sw = NULL;
2843 enclosinghandler = NULL;
2844 }
2845
2846 Statement *GotoDefaultStatement::syntaxCopy()
2847 {
2848 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2849 return s;
2850 }
2851
2852 Statement *GotoDefaultStatement::semantic(Scope *sc)
2853 {
2854 enclosinghandler = sc->tfOfTry;
2855 sw = sc->sw;
2856 if (!sw)
2857 error("goto default not in switch statement");
2858 return this;
2859 }
2860
2861 int GotoDefaultStatement::blockExit()
2862 {
2863 return BEgoto;
2864 }
2865
2866 int GotoDefaultStatement::fallOffEnd()
2867 {
2868 return FALSE;
2869 }
2870
2871 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2872 {
2873 buf->writestring("goto default;\n");
2874 }
2875
2876 /******************************** GotoCaseStatement ***************************/
2877
2878 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2879 : Statement(loc)
2880 {
2881 cs = NULL;
2882 this->exp = exp;
2883 enclosinghandler = NULL;
2884 sw = NULL;
2885 }
2886
2887 Statement *GotoCaseStatement::syntaxCopy()
2888 {
2889 Expression *e = exp ? exp->syntaxCopy() : NULL;
2890 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2891 return s;
2892 }
2893
2894 Statement *GotoCaseStatement::semantic(Scope *sc)
2895 {
2896 enclosinghandler = sc->tfOfTry;
2897 if (exp)
2898 exp = exp->semantic(sc);
2899
2900 if (!sc->sw)
2901 error("goto case not in switch statement");
2902 else
2903 {
2904 sw = sc->sw;
2905 sc->sw->gotoCases.push(this);
2906 if (exp)
2907 {
2908 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2909 exp = exp->optimize(WANTvalue);
2910 }
2911 }
2912 return this;
2913 }
2914
2915 int GotoCaseStatement::blockExit()
2916 {
2917 return BEgoto;
2918 }
2919
2920 int GotoCaseStatement::fallOffEnd()
2921 {
2922 return FALSE;
2923 }
2924
2925 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2926 {
2927 buf->writestring("goto case");
2928 if (exp)
2929 { buf->writebyte(' ');
2930 exp->toCBuffer(buf, hgs);
2931 }
2932 buf->writebyte(';');
2933 buf->writenl();
2934 }
2935
2936 /******************************** SwitchErrorStatement ***************************/
2937
2938 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2939 : Statement(loc)
2940 {
2941 }
2942
2943 int SwitchErrorStatement::blockExit()
2944 {
2945 return BEthrow;
2946 }
2947
2948 int SwitchErrorStatement::fallOffEnd()
2949 {
2950 return FALSE;
2951 }
2952
2953 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2954 {
2955 buf->writestring("SwitchErrorStatement::toCBuffer()");
2956 buf->writenl();
2957 }
2958
2959 /******************************** ReturnStatement ***************************/
2960
2961 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2962 : Statement(loc)
2963 {
2964 this->exp = exp;
2965 this->enclosinghandler = NULL;
2966 }
2967
2968 Statement *ReturnStatement::syntaxCopy()
2969 {
2970 Expression *e = NULL;
2971 if (exp)
2972 e = exp->syntaxCopy();
2973 ReturnStatement *s = new ReturnStatement(loc, e);
2974 return s;
2975 }
2976
2977 Statement *ReturnStatement::semantic(Scope *sc)
2978 {
2979 //printf("ReturnStatement::semantic() %s\n", toChars());
2980 this->enclosinghandler = sc->tfOfTry;
2981
2982 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2983 Scope *scx = sc;
2984 int implicit0 = 0;
2985
2986 if (sc->fes)
2987 {
2988 // Find scope of function foreach is in
2989 for (; 1; scx = scx->enclosing)
2990 {
2991 assert(scx);
2992 if (scx->func != fd)
2993 { fd = scx->func; // fd is now function enclosing foreach
2994 break;
2995 }
2996 }
2997 }
2998
2999 Type *tret = fd->type->nextOf();
3000 if (fd->tintro)
3001 /* We'll be implicitly casting the return expression to tintro
3002 */
3003 tret = fd->tintro->nextOf();
3004 Type *tbret = NULL;
3005
3006 if (tret)
3007 tbret = tret->toBasetype();
3008
3009 // main() returns 0, even if it returns void
3010 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
3011 { implicit0 = 1;
3012 exp = new IntegerExp(0);
3013 }
3014
3015 if (sc->incontract || scx->incontract)
3016 error("return statements cannot be in contracts");
3017 if (sc->tf || scx->tf)
3018 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
3019
3020 if (fd->isCtorDeclaration())
3021 {
3022 // Constructors implicitly do:
3023 // return this;
3024 if (exp && exp->op != TOKthis)
3025 error("cannot return expression from constructor");
3026 exp = new ThisExp(0);
3027 }
3028
3029 if (!exp)
3030 fd->nrvo_can = 0;
3031
3032 if (exp)
3033 {
3034 fd->hasReturnExp |= 1;
3035
3036 exp = exp->semantic(sc);
3037 exp = resolveProperties(sc, exp);
3038 exp = exp->optimize(WANTvalue);
3039
3040 if (fd->nrvo_can && exp->op == TOKvar)
3041 { VarExp *ve = (VarExp *)exp;
3042 VarDeclaration *v = ve->var->isVarDeclaration();
3043
3044 if (((TypeFunction *)fd->type)->isref)
3045 // Function returns a reference
3046 fd->nrvo_can = 0;
3047 else if (!v || v->isOut() || v->isRef())
3048 fd->nrvo_can = 0;
3049 else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor)
3050 // Struct being returned has destructors
3051 fd->nrvo_can = 0;
3052 else if (fd->nrvo_var == NULL)
3053 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
3054 { //printf("Setting nrvo to %s\n", v->toChars());
3055 fd->nrvo_var = v;
3056 }
3057 else
3058 fd->nrvo_can = 0;
3059 }
3060 else if (fd->nrvo_var != v)
3061 fd->nrvo_can = 0;
3062 }
3063 else
3064 fd->nrvo_can = 0;
3065
3066 if (fd->returnLabel && tbret->ty != Tvoid)
3067 {
3068 }
3069 else if (fd->inferRetType)
3070 {
3071 if (fd->type->nextOf())
3072 {
3073 if (!exp->type->equals(fd->type->nextOf()))
3074 error("mismatched function return type inference of %s and %s",
3075 exp->type->toChars(), fd->type->nextOf()->toChars());
3076 }
3077 else
3078 {
3079 ((TypeFunction *)fd->type)->next = exp->type;
3080 fd->type = fd->type->semantic(loc, sc);
3081 if (!fd->tintro)
3082 { tret = fd->type->nextOf();
3083 tbret = tret->toBasetype();
3084 }
3085 }
3086 }
3087 else if (tbret->ty != Tvoid)
3088 {
3089 exp = exp->implicitCastTo(sc, tret);
3090 }
3091 }
3092 else if (fd->inferRetType)
3093 {
3094 if (fd->type->nextOf())
3095 {
3096 if (fd->type->nextOf()->ty != Tvoid)
3097 error("mismatched function return type inference of void and %s",
3098 fd->type->nextOf()->toChars());
3099 }
3100 else
3101 {
3102 ((TypeFunction *)fd->type)->next = Type::tvoid;
3103 fd->type = fd->type->semantic(loc, sc);
3104 if (!fd->tintro)
3105 { tret = Type::tvoid;
3106 tbret = tret;
3107 }
3108 }
3109 }
3110 else if (tbret->ty != Tvoid) // if non-void return
3111 error("return expression expected");
3112
3113 if (sc->fes)
3114 {
3115 Statement *s;
3116
3117 if (exp && !implicit0)
3118 {
3119 exp = exp->implicitCastTo(sc, tret);
3120 }
3121 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
3122 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
3123 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
3124 exp->op == TOKstring)
3125 {
3126 sc->fes->cases.push(this);
3127 // Construct: return cases.dim+1;
3128 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3129 }
3130 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
3131 {
3132 s = new ReturnStatement(0, NULL);
3133 sc->fes->cases.push(s);
3134
3135 // Construct: { exp; return cases.dim + 1; }
3136 Statement *s1 = new ExpStatement(loc, exp);
3137 Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3138 s = new CompoundStatement(loc, s1, s2);
3139 }
3140 else
3141 {
3142 // Construct: return vresult;
3143 if (!fd->vresult)
3144 { // Declare vresult
3145 VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL);
3146 v->noauto = 1;
3147 v->semantic(scx);
3148 if (!scx->insert(v))
3149 assert(0);
3150 v->parent = fd;
3151 fd->vresult = v;
3152 }
3153
3154 s = new ReturnStatement(0, new VarExp(0, fd->vresult));
3155 sc->fes->cases.push(s);
3156
3157 // Construct: { vresult = exp; return cases.dim + 1; }
3158 exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp);
3159 exp = exp->semantic(sc);
3160 Statement *s1 = new ExpStatement(loc, exp);
3161 Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3162 s = new CompoundStatement(loc, s1, s2);
3163 }
3164 return s;
3165 }
3166
3167 if (exp)
3168 {
3169 if (fd->returnLabel && tbret->ty != Tvoid)
3170 {
3171 assert(fd->vresult);
3172 VarExp *v = new VarExp(0, fd->vresult);
3173
3174 exp = new AssignExp(loc, v, exp);
3175 exp = exp->semantic(sc);
3176 }
3177
3178 if (((TypeFunction *)fd->type)->isref)
3179 { // Function returns a reference
3180 if (tbret->isMutable())
3181 exp = exp->modifiableLvalue(sc, exp);
3182 else
3183 exp = exp->toLvalue(sc, exp);
3184
3185 if (exp->op == TOKvar)
3186 { VarExp *ve = (VarExp *)exp;
3187 VarDeclaration *v = ve->var->isVarDeclaration();
3188 if (v && !v->isDataseg() && !(v->storage_class & (STCref | STCout)))
3189 error("escaping reference to local variable %s", v->toChars());
3190 }
3191 }
3192
3193 //exp->dump(0);
3194 //exp->print();
3195 exp->checkEscape();
3196 }
3197
3198 /* BUG: need to issue an error on:
3199 * this
3200 * { if (x) return;
3201 * super();
3202 * }
3203 */
3204
3205 if (sc->callSuper & CSXany_ctor &&
3206 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
3207 error("return without calling constructor");
3208
3209 sc->callSuper |= CSXreturn;
3210
3211 // See if all returns are instead to be replaced with a goto returnLabel;
3212 if (fd->returnLabel)
3213 {
3214 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
3215
3216 gs->label = fd->returnLabel;
3217 if (exp)
3218 { /* Replace: return exp;
3219 * with: exp; goto returnLabel;
3220 */
3221 Statement *s = new ExpStatement(0, exp);
3222 return new CompoundStatement(loc, s, gs);
3223 }
3224 return gs;
3225 }
3226
3227 if (exp && tbret->ty == Tvoid && !fd->isMain())
3228 {
3229 /* Replace:
3230 * return exp;
3231 * with:
3232 * exp; return;
3233 */
3234 Statement *s = new ExpStatement(loc, exp);
3235 loc = 0;
3236 exp = NULL;
3237 return new CompoundStatement(loc, s, this);
3238 }
3239
3240 return this;
3241 }
3242
3243 int ReturnStatement::blockExit()
3244 { int result = BEreturn;
3245
3246 if (exp && exp->canThrow())
3247 result |= BEthrow;
3248 return result;
3249 }
3250
3251 int ReturnStatement::fallOffEnd()
3252 {
3253 return FALSE;
3254 }
3255
3256 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3257 {
3258 buf->printf("return ");
3259 if (exp)
3260 exp->toCBuffer(buf, hgs);
3261 buf->writeByte(';');
3262 buf->writenl();
3263 }
3264
3265 /******************************** BreakStatement ***************************/
3266
3267 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
3268 : Statement(loc)
3269 {
3270 this->ident = ident;
3271 this->enclosinghandler = NULL;
3272 }
3273
3274 Statement *BreakStatement::syntaxCopy()
3275 {
3276 BreakStatement *s = new BreakStatement(loc, ident);
3277 return s;
3278 }
3279
3280 Statement *BreakStatement::semantic(Scope *sc)
3281 {
3282 //printf("BreakStatement::semantic()\n");
3283 enclosinghandler = sc->tfOfTry;
3284 // If:
3285 // break Identifier;
3286 if (ident)
3287 {
3288 Scope *scx;
3289 FuncDeclaration *thisfunc = sc->func;
3290
3291 for (scx = sc; scx; scx = scx->enclosing)
3292 {
3293 LabelStatement *ls;
3294
3295 if (scx->func != thisfunc) // if in enclosing function
3296 {
3297 if (sc->fes) // if this is the body of a foreach
3298 {
3299 /* Post this statement to the fes, and replace
3300 * it with a return value that caller will put into
3301 * a switch. Caller will figure out where the break
3302 * label actually is.
3303 * Case numbers start with 2, not 0, as 0 is continue
3304 * and 1 is break.
3305 */
3306 Statement *s;
3307 sc->fes->cases.push(this);
3308 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3309 return s;
3310 }
3311 break; // can't break to it
3312 }
3313
3314 ls = scx->slabel;
3315 if (ls && ls->ident == ident)
3316 {
3317 Statement *s = ls->statement;
3318
3319 if (!s->hasBreak())
3320 error("label '%s' has no break", ident->toChars());
3321 if (ls->tf != sc->tf)
3322 error("cannot break out of finally block");
3323
3324 this->target = ls;
3325 return this;
3326 }
3327 }
3328 error("enclosing label '%s' for break not found", ident->toChars());
3329 }
3330 else if (!sc->sbreak)
3331 {
3332 if (sc->fes)
3333 { Statement *s;
3334
3335 // Replace break; with return 1;
3336 s = new ReturnStatement(0, new IntegerExp(1));
3337 return s;
3338 }
3339 error("break is not inside a loop or switch");
3340 }
3341 return this;
3342 }
3343
3344 int BreakStatement::blockExit()
3345 {
3346 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3347 return ident ? BEgoto : BEbreak;
3348 }
3349
3350 int BreakStatement::fallOffEnd()
3351 {
3352 return FALSE;
3353 }
3354
3355 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3356 {
3357 buf->writestring("break");
3358 if (ident)
3359 { buf->writebyte(' ');
3360 buf->writestring(ident->toChars());
3361 }
3362 buf->writebyte(';');
3363 buf->writenl();
3364 }
3365
3366 /******************************** ContinueStatement ***************************/
3367
3368 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
3369 : Statement(loc)
3370 {
3371 this->ident = ident;
3372 this->enclosinghandler = NULL;
3373 }
3374
3375 Statement *ContinueStatement::syntaxCopy()
3376 {
3377 ContinueStatement *s = new ContinueStatement(loc, ident);
3378 return s;
3379 }
3380
3381 Statement *ContinueStatement::semantic(Scope *sc)
3382 {
3383 enclosinghandler = sc->tfOfTry;
3384 //printf("ContinueStatement::semantic() %p\n", this);
3385 if (ident)
3386 {
3387 Scope *scx;
3388 FuncDeclaration *thisfunc = sc->func;
3389
3390 for (scx = sc; scx; scx = scx->enclosing)
3391 {
3392 LabelStatement *ls;
3393
3394 if (scx->func != thisfunc) // if in enclosing function
3395 {
3396 if (sc->fes) // if this is the body of a foreach
3397 {
3398 for (; scx; scx = scx->enclosing)
3399 {
3400 ls = scx->slabel;
3401 if (ls && ls->ident == ident && ls->statement == sc->fes)
3402 {
3403 // Replace continue ident; with return 0;
3404 return new ReturnStatement(0, new IntegerExp(0));
3405 }
3406 }
3407
3408 /* Post this statement to the fes, and replace
3409 * it with a return value that caller will put into
3410 * a switch. Caller will figure out where the break
3411 * label actually is.
3412 * Case numbers start with 2, not 0, as 0 is continue
3413 * and 1 is break.
3414 */
3415 Statement *s;
3416 sc->fes->cases.push(this);
3417 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3418 return s;
3419 }
3420 break; // can't continue to it
3421 }
3422
3423 ls = scx->slabel;
3424 if (ls && ls->ident == ident)
3425 {
3426 Statement *s = ls->statement;
3427
3428 if (!s->hasContinue())
3429 error("label '%s' has no continue", ident->toChars());
3430 if (ls->tf != sc->tf)
3431 error("cannot continue out of finally block");
3432
3433 this->target = ls;
3434 return this;
3435 }
3436 }
3437 error("enclosing label '%s' for continue not found", ident->toChars());
3438 }
3439 else if (!sc->scontinue)
3440 {
3441 if (sc->fes)
3442 { Statement *s;
3443
3444 // Replace continue; with return 0;
3445 s = new ReturnStatement(0, new IntegerExp(0));
3446 return s;
3447 }
3448 error("continue is not inside a loop");
3449 }
3450 return this;
3451 }
3452
3453 int ContinueStatement::blockExit()
3454 {
3455 return ident ? BEgoto : BEcontinue;
3456 }
3457
3458 int ContinueStatement::fallOffEnd()
3459 {
3460 return FALSE;
3461 }
3462
3463 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3464 {
3465 buf->writestring("continue");
3466 if (ident)
3467 { buf->writebyte(' ');
3468 buf->writestring(ident->toChars());
3469 }
3470 buf->writebyte(';');
3471 buf->writenl();
3472 }
3473
3474 /******************************** SynchronizedStatement ***************************/
3475
3476 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
3477 : Statement(loc)
3478 {
3479 this->exp = exp;
3480 this->body = body;
3481 this->esync = NULL;
3482 this->enclosinghandler = NULL;
3483 // LDC
3484 this->llsync = NULL;
3485 }
3486
3487 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
3488 : Statement(loc)
3489 {
3490 this->exp = NULL;
3491 this->body = body;
3492 this->esync = esync;
3493 this->enclosinghandler = NULL;
3494 // LDC
3495 this->llsync = NULL;
3496 }
3497
3498 Statement *SynchronizedStatement::syntaxCopy()
3499 {
3500 Expression *e = exp ? exp->syntaxCopy() : NULL;
3501 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
3502 return s;
3503 }
3504
3505 Statement *SynchronizedStatement::semantic(Scope *sc)
3506 {
3507 if (exp)
3508 { ClassDeclaration *cd;
3509
3510 exp = exp->semantic(sc);
3511 exp = resolveProperties(sc, exp);
3512 cd = exp->type->isClassHandle();
3513 if (!cd)
3514 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
3515 else if (cd->isInterfaceDeclaration())
3516 { Type *t = new TypeIdentifier(0, Id::Object);
3517
3518 t = t->semantic(0, sc);
3519 exp = new CastExp(loc, exp, t);
3520 exp = exp->semantic(sc);
3521 }
3522 }
3523 if (body)
3524 {
3525 enclosinghandler = sc->tfOfTry;
3526 sc->tfOfTry = new EnclosingSynchro(this);
3527 body = body->semantic(sc);
3528 sc->tfOfTry = enclosinghandler;
3529 }
3530 return this;
3531 }
3532
3533 int SynchronizedStatement::hasBreak()
3534 {
3535 return FALSE; //TRUE;
3536 }
3537
3538 int SynchronizedStatement::hasContinue()
3539 {
3540 return FALSE; //TRUE;
3541 }
3542
3543 int SynchronizedStatement::usesEH()
3544 {
3545 return TRUE;
3546 }
3547
3548 int SynchronizedStatement::blockExit()
3549 {
3550 return body ? body->blockExit() : BEfallthru;
3551 }
3552
3553 int SynchronizedStatement::fallOffEnd()
3554 {
3555 return body ? body->fallOffEnd() : TRUE;
3556 }
3557
3558 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3559 {
3560 buf->writestring("synchronized");
3561 if (exp)
3562 { buf->writebyte('(');
3563 exp->toCBuffer(buf, hgs);
3564 buf->writebyte(')');
3565 }
3566 if (body)
3567 {
3568 buf->writebyte(' ');
3569 body->toCBuffer(buf, hgs);
3570 }
3571 }
3572
3573 /******************************** WithStatement ***************************/
3574
3575 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3576 : Statement(loc)
3577 {
3578 this->exp = exp;
3579 this->body = body;
3580 wthis = NULL;
3581 }
3582
3583 Statement *WithStatement::syntaxCopy()
3584 {
3585 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3586 return s;
3587 }
3588
3589 Statement *WithStatement::semantic(Scope *sc)
3590 { ScopeDsymbol *sym;
3591 Initializer *init;
3592
3593 //printf("WithStatement::semantic()\n");
3594 exp = exp->semantic(sc);
3595 exp = resolveProperties(sc, exp);
3596 if (exp->op == TOKimport)
3597 { ScopeExp *es = (ScopeExp *)exp;
3598
3599 sym = es->sds;
3600 }
3601 else if (exp->op == TOKtype)
3602 { TypeExp *es = (TypeExp *)exp;
3603
3604 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3605 if (!sym)
3606 { error("%s has no members", es->toChars());
3607 body = body->semantic(sc);
3608 return this;
3609 }
3610 }
3611 else
3612 { Type *t = exp->type;
3613
3614 assert(t);
3615 t = t->toBasetype();
3616 if (t->isClassHandle())
3617 {
3618 init = new ExpInitializer(loc, exp);
3619 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3620 wthis->semantic(sc);
3621
3622 sym = new WithScopeSymbol(this);
3623 sym->parent = sc->scopesym;
3624 }
3625 else if (t->ty == Tstruct)
3626 {
3627 Expression *e = exp->addressOf(sc);
3628 init = new ExpInitializer(loc, e);
3629 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3630 wthis->semantic(sc);
3631 sym = new WithScopeSymbol(this);
3632 sym->parent = sc->scopesym;
3633 }
3634 else
3635 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3636 return NULL;
3637 }
3638 }
3639 sc = sc->push(sym);
3640
3641 if (body)
3642 body = body->semantic(sc);
3643
3644 sc->pop();
3645
3646 return this;
3647 }
3648
3649 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3650 {
3651 buf->writestring("with (");
3652 exp->toCBuffer(buf, hgs);
3653 buf->writestring(")\n");
3654 if (body)
3655 body->toCBuffer(buf, hgs);
3656 }
3657
3658 int WithStatement::usesEH()
3659 {
3660 return body ? body->usesEH() : 0;
3661 }
3662
3663 int WithStatement::blockExit()
3664 {
3665 int result = BEnone;
3666 if (exp->canThrow())
3667 result = BEthrow;
3668 if (body)
3669 result |= body->blockExit();
3670 else
3671 result |= BEfallthru;
3672 return result;
3673 }
3674
3675 int WithStatement::fallOffEnd()
3676 {
3677 return body ? body->fallOffEnd() : TRUE;
3678 }
3679
3680 /******************************** TryCatchStatement ***************************/
3681
3682 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3683 : Statement(loc)
3684 {
3685 this->body = body;
3686 this->catches = catches;
3687 }
3688
3689 Statement *TryCatchStatement::syntaxCopy()
3690 {
3691 Array *a = new Array();
3692 a->setDim(catches->dim);
3693 for (int i = 0; i < a->dim; i++)
3694 { Catch *c;
3695
3696 c = (Catch *)catches->data[i];
3697 c = c->syntaxCopy();
3698 a->data[i] = c;
3699 }
3700 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3701 return s;
3702 }
3703
3704 Statement *TryCatchStatement::semantic(Scope *sc)
3705 {
3706 body = body->semanticScope(sc, NULL /*this*/, NULL);
3707
3708 /* Even if body is NULL, still do semantic analysis on catches
3709 */
3710 for (size_t i = 0; i < catches->dim; i++)
3711 { Catch *c = (Catch *)catches->data[i];
3712 c->semantic(sc);
3713
3714 // Determine if current catch 'hides' any previous catches
3715 for (size_t j = 0; j < i; j++)
3716 { Catch *cj = (Catch *)catches->data[j];
3717 char *si = c->loc.toChars();
3718 char *sj = cj->loc.toChars();
3719
3720 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3721 error("catch at %s hides catch at %s", sj, si);
3722 }
3723 }
3724
3725 if (!body)
3726 return NULL;
3727
3728 return this;
3729 }
3730
3731 int TryCatchStatement::hasBreak()
3732 {
3733 return FALSE; //TRUE;
3734 }
3735
3736 int TryCatchStatement::usesEH()
3737 {
3738 return TRUE;
3739 }
3740
3741 int TryCatchStatement::blockExit()
3742 { int result;
3743
3744 assert(body);
3745 result = body->blockExit();
3746
3747 for (size_t i = 0; i < catches->dim; i++)
3748 {
3749 Catch *c = (Catch *)catches->data[i];
3750 result |= c->blockExit();
3751 }
3752 return result;
3753 }
3754
3755 int TryCatchStatement::fallOffEnd()
3756 {
3757 int result = FALSE;
3758
3759 if (body)
3760 result = body->fallOffEnd();
3761 for (int i = 0; i < catches->dim; i++)
3762 { Catch *c;
3763
3764 c = (Catch *)catches->data[i];
3765 if (c->handler)
3766 result |= c->handler->fallOffEnd();
3767 }
3768 return result;
3769 }
3770
3771 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3772 {
3773 buf->writestring("try");
3774 buf->writenl();
3775 if (body)
3776 body->toCBuffer(buf, hgs);
3777 for (size_t i = 0; i < catches->dim; i++)
3778 {
3779 Catch *c = (Catch *)catches->data[i];
3780 c->toCBuffer(buf, hgs);
3781 }
3782 }
3783
3784 /******************************** Catch ***************************/
3785
3786 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3787 {
3788 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3789 this->loc = loc;
3790 this->type = t;
3791 this->ident = id;
3792 this->handler = handler;
3793 var = NULL;
3794 }
3795
3796 Catch *Catch::syntaxCopy()
3797 {
3798 Catch *c = new Catch(loc,
3799 (type ? type->syntaxCopy() : NULL),
3800 ident,
3801 (handler ? handler->syntaxCopy() : NULL));
3802 return c;
3803 }
3804
3805 void Catch::semantic(Scope *sc)
3806 { ScopeDsymbol *sym;
3807
3808 //printf("Catch::semantic(%s)\n", ident->toChars());
3809
3810 #ifndef IN_GCC
3811 if (sc->tf)
3812 {
3813 /* This is because the _d_local_unwind() gets the stack munged
3814 * up on this. The workaround is to place any try-catches into
3815 * a separate function, and call that.
3816 * To fix, have the compiler automatically convert the finally
3817 * body into a nested function.
3818 */
3819 error(loc, "cannot put catch statement inside finally block");
3820 }
3821 #endif
3822
3823 sym = new ScopeDsymbol();
3824 sym->parent = sc->scopesym;
3825 sc = sc->push(sym);
3826
3827 if (!type)
3828 type = new TypeIdentifier(0, Id::Object);
3829 type = type->semantic(loc, sc);
3830 if (!type->toBasetype()->isClassHandle())
3831 error("can only catch class objects, not '%s'", type->toChars());
3832 else if (ident)
3833 {
3834 var = new VarDeclaration(loc, type, ident, NULL);
3835 var->parent = sc->parent;
3836 sc->insert(var);
3837 }
3838 handler = handler->semantic(sc);
3839
3840 sc->pop();
3841 }
3842
3843 int Catch::blockExit()
3844 {
3845 return handler ? handler->blockExit() : BEfallthru;
3846 }
3847
3848 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3849 {
3850 buf->writestring("catch");
3851 if (type)
3852 { buf->writebyte('(');
3853 type->toCBuffer(buf, ident, hgs);
3854 buf->writebyte(')');
3855 }
3856 buf->writenl();
3857 buf->writebyte('{');
3858 buf->writenl();
3859 if (handler)
3860 handler->toCBuffer(buf, hgs);
3861 buf->writebyte('}');
3862 buf->writenl();
3863 }
3864
3865 /****************************** TryFinallyStatement ***************************/
3866
3867 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3868 : Statement(loc)
3869 {
3870 this->body = body;
3871 this->finalbody = finalbody;
3872 this->enclosinghandler = NULL;
3873 }
3874
3875 Statement *TryFinallyStatement::syntaxCopy()
3876 {
3877 TryFinallyStatement *s = new TryFinallyStatement(loc,
3878 body->syntaxCopy(), finalbody->syntaxCopy());
3879 return s;
3880 }
3881
3882 Statement *TryFinallyStatement::semantic(Scope *sc)
3883 {
3884 //printf("TryFinallyStatement::semantic()\n");
3885
3886 enclosinghandler = sc->tfOfTry;
3887 sc->tfOfTry = new EnclosingTryFinally(this);
3888 body = body->semantic(sc);
3889 sc->tfOfTry = enclosinghandler;
3890
3891 sc = sc->push();
3892 sc->tf = this;
3893 sc->sbreak = NULL;
3894 sc->scontinue = NULL; // no break or continue out of finally block
3895 finalbody = finalbody->semantic(sc);
3896 sc->pop();
3897 if (!body)
3898 return finalbody;
3899 if (!finalbody)
3900 return body;
3901 if (body->blockExit() == BEfallthru)
3902 { Statement *s = new CompoundStatement(loc, body, finalbody);
3903 return s;
3904 }
3905 return this;
3906 }
3907
3908 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3909 {
3910 buf->printf("try\n{\n");
3911 body->toCBuffer(buf, hgs);
3912 buf->printf("}\nfinally\n{\n");
3913 finalbody->toCBuffer(buf, hgs);
3914 buf->writeByte('}');
3915 buf->writenl();
3916 }
3917
3918 int TryFinallyStatement::hasBreak()
3919 {
3920 return FALSE; //TRUE;
3921 }
3922
3923 int TryFinallyStatement::hasContinue()
3924 {
3925 return FALSE; //TRUE;
3926 }
3927
3928 int TryFinallyStatement::usesEH()
3929 {
3930 return TRUE;
3931 }
3932
3933 int TryFinallyStatement::blockExit()
3934 {
3935 int result = body->blockExit();
3936 return result;
3937 }
3938
3939 int TryFinallyStatement::fallOffEnd()
3940 { int result;
3941
3942 result = body->fallOffEnd();
3943 // if (finalbody)
3944 // result = finalbody->fallOffEnd();
3945 return result;
3946 }
3947
3948 /****************************** OnScopeStatement ***************************/
3949
3950 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3951 : Statement(loc)
3952 {
3953 this->tok = tok;
3954 this->statement = statement;
3955 }
3956
3957 Statement *OnScopeStatement::syntaxCopy()
3958 {
3959 OnScopeStatement *s = new OnScopeStatement(loc,
3960 tok, statement->syntaxCopy());
3961 return s;
3962 }
3963
3964 Statement *OnScopeStatement::semantic(Scope *sc)
3965 {
3966 /* semantic is called on results of scopeCode() */
3967 return this;
3968 }
3969
3970 int OnScopeStatement::blockExit()
3971 { // At this point, this statement is just an empty placeholder
3972 return BEfallthru;
3973 }
3974
3975 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3976 {
3977 buf->writestring(Token::toChars(tok));
3978 buf->writebyte(' ');
3979 statement->toCBuffer(buf, hgs);
3980 }
3981
3982 int OnScopeStatement::usesEH()
3983 {
3984 return 1;
3985 }
3986
3987 void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
3988 {
3989 //printf("OnScopeStatement::scopeCode()\n");
3990 //print();
3991 *sentry = NULL;
3992 *sexception = NULL;
3993 *sfinally = NULL;
3994 switch (tok)
3995 {
3996 case TOKon_scope_exit:
3997 *sfinally = statement;
3998 break;
3999
4000 case TOKon_scope_failure:
4001 *sexception = statement;
4002 break;
4003
4004 case TOKon_scope_success:
4005 {
4006 /* Create:
4007 * sentry: int x = 0;
4008 * sexception: x = 1;
4009 * sfinally: if (!x) statement;
4010 */
4011 Identifier *id = Lexer::uniqueId("__os");
4012
4013 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
4014 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
4015 *sentry = new DeclarationStatement(loc, v);
4016
4017 Expression *e = new IntegerExp(1);
4018 e = new AssignExp(0, new VarExp(0, v), e);
4019 *sexception = new ExpStatement(0, e);
4020
4021 e = new VarExp(0, v);
4022 e = new NotExp(0, e);
4023 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
4024
4025 break;
4026 }
4027
4028 default:
4029 assert(0);
4030 }
4031 }
4032
4033 /******************************** ThrowStatement ***************************/
4034
4035 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
4036 : Statement(loc)
4037 {
4038 this->exp = exp;
4039 }
4040
4041 Statement *ThrowStatement::syntaxCopy()
4042 {
4043 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
4044 return s;
4045 }
4046
4047 Statement *ThrowStatement::semantic(Scope *sc)
4048 {
4049 //printf("ThrowStatement::semantic()\n");
4050
4051 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4052 fd->hasReturnExp |= 2;
4053
4054 if (sc->incontract)
4055 error("Throw statements cannot be in contracts");
4056 exp = exp->semantic(sc);
4057 exp = resolveProperties(sc, exp);
4058 if (!exp->type->toBasetype()->isClassHandle())
4059 error("can only throw class objects, not type %s", exp->type->toChars());
4060 return this;
4061 }
4062
4063 int ThrowStatement::blockExit()
4064 {
4065 return BEthrow; // obviously
4066 }
4067
4068 int ThrowStatement::fallOffEnd()
4069 {
4070 return FALSE;
4071 }
4072
4073 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4074 {
4075 buf->printf("throw ");
4076 exp->toCBuffer(buf, hgs);
4077 buf->writeByte(';');
4078 buf->writenl();
4079 }
4080
4081 /******************************** VolatileStatement **************************/
4082
4083 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
4084 : Statement(loc)
4085 {
4086 this->statement = statement;
4087 this->enclosinghandler = NULL;
4088 }
4089
4090 Statement *VolatileStatement::syntaxCopy()
4091 {
4092 VolatileStatement *s = new VolatileStatement(loc,
4093 statement ? statement->syntaxCopy() : NULL);
4094 return s;
4095 }
4096
4097 Statement *VolatileStatement::semantic(Scope *sc)
4098 {
4099 if (statement)
4100 {
4101 enclosinghandler = sc->tfOfTry;
4102 sc->tfOfTry = new EnclosingVolatile(this);
4103 statement = statement->semantic(sc);
4104 sc->tfOfTry = enclosinghandler;
4105 }
4106 return this;
4107 }
4108
4109 Statements *VolatileStatement::flatten(Scope *sc)
4110 {
4111 Statements *a;
4112
4113 a = statement ? statement->flatten(sc) : NULL;
4114 if (a)
4115 { for (int i = 0; i < a->dim; i++)
4116 { Statement *s = (Statement *)a->data[i];
4117
4118 s = new VolatileStatement(loc, s);
4119 a->data[i] = s;
4120 }
4121 }
4122
4123 return a;
4124 }
4125
4126 int VolatileStatement::blockExit()
4127 {
4128 return statement ? statement->blockExit() : BEfallthru;
4129 }
4130
4131 int VolatileStatement::fallOffEnd()
4132 {
4133 return statement ? statement->fallOffEnd() : TRUE;
4134 }
4135
4136 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4137 {
4138 buf->writestring("volatile");
4139 if (statement)
4140 { if (statement->isScopeStatement())
4141 buf->writenl();
4142 else
4143 buf->writebyte(' ');
4144 statement->toCBuffer(buf, hgs);
4145 }
4146 }
4147
4148
4149 /******************************** GotoStatement ***************************/
4150
4151 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
4152 : Statement(loc)
4153 {
4154 this->ident = ident;
4155 this->label = NULL;
4156 this->tf = NULL;
4157 this->enclosinghandler = NULL;
4158 }
4159
4160 Statement *GotoStatement::syntaxCopy()
4161 {
4162 GotoStatement *s = new GotoStatement(loc, ident);
4163 return s;
4164 }
4165
4166 Statement *GotoStatement::semantic(Scope *sc)
4167 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4168
4169 //printf("GotoStatement::semantic()\n");
4170 tf = sc->tf;
4171 enclosinghandler = sc->tfOfTry;
4172 label = fd->searchLabel(ident);
4173 if (!label->statement && sc->fes)
4174 {
4175 /* Either the goto label is forward referenced or it
4176 * is in the function that the enclosing foreach is in.
4177 * Can't know yet, so wrap the goto in a compound statement
4178 * so we can patch it later, and add it to a 'look at this later'
4179 * list.
4180 */
4181 Statements *a = new Statements();
4182 Statement *s;
4183
4184 a->push(this);
4185 s = new CompoundStatement(loc, a);
4186 sc->fes->gotos.push(s); // 'look at this later' list
4187 return s;
4188 }
4189 if (label->statement && label->statement->tf != sc->tf)
4190 error("cannot goto in or out of finally block");
4191 return this;
4192 }
4193
4194 int GotoStatement::blockExit()
4195 {
4196 //printf("GotoStatement::blockExit(%p)\n", this);
4197 return BEgoto;
4198 }
4199
4200 int GotoStatement::fallOffEnd()
4201 {
4202 return FALSE;
4203 }
4204
4205 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4206 {
4207 buf->writestring("goto ");
4208 buf->writestring(ident->toChars());
4209 buf->writebyte(';');
4210 buf->writenl();
4211 }
4212
4213 /******************************** LabelStatement ***************************/
4214
4215 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
4216 : Statement(loc)
4217 {
4218 this->ident = ident;
4219 this->statement = statement;
4220 this->tf = NULL;
4221 this->enclosinghandler = NULL;
4222 this->lblock = NULL;
4223 this->isReturnLabel = 0;
4224 this->asmLabel = false;
4225 }
4226
4227 Statement *LabelStatement::syntaxCopy()
4228 {
4229 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
4230 return s;
4231 }
4232
4233 Statement *LabelStatement::semantic(Scope *sc)
4234 { LabelDsymbol *ls;
4235 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4236
4237 //printf("LabelStatement::semantic()\n");
4238 ls = fd->searchLabel(ident);
4239 if (ls->statement)
4240 error("Label '%s' already defined", ls->toChars());
4241 else
4242 ls->statement = this;
4243 tf = sc->tf;
4244 enclosinghandler = sc->tfOfTry;
4245 sc = sc->push();
4246 sc->scopesym = sc->enclosing->scopesym;
4247 sc->callSuper |= CSXlabel;
4248 sc->slabel = this;
4249 if (statement)
4250 statement = statement->semantic(sc);
4251 sc->pop();
4252
4253 // LDC put in labmap
4254 fd->labmap[ident->toChars()] = this;
4255
4256 return this;
4257 }
4258
4259 Statements *LabelStatement::flatten(Scope *sc)
4260 {
4261 Statements *a = NULL;
4262
4263 if (statement)
4264 {
4265 a = statement->flatten(sc);
4266 if (a)
4267 {
4268 if (!a->dim)
4269 {
4270 a->push(new ExpStatement(loc, NULL));
4271 }
4272 Statement *s = (Statement *)a->data[0];
4273
4274 s = new LabelStatement(loc, ident, s);
4275 a->data[0] = s;
4276 }
4277 }
4278
4279 return a;
4280 }
4281
4282
4283 int LabelStatement::usesEH()
4284 {
4285 return statement ? statement->usesEH() : FALSE;
4286 }
4287
4288 int LabelStatement::blockExit()
4289 {
4290 //printf("LabelStatement::blockExit(%p)\n", this);
4291 return statement ? statement->blockExit() : BEfallthru;
4292 }
4293
4294 int LabelStatement::fallOffEnd()
4295 {
4296 return statement ? statement->fallOffEnd() : TRUE;
4297 }
4298
4299 int LabelStatement::comeFrom()
4300 {
4301 //printf("LabelStatement::comeFrom()\n");
4302 return TRUE;
4303 }
4304
4305 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4306 {
4307 buf->writestring(ident->toChars());
4308 buf->writebyte(':');
4309 buf->writenl();
4310 if (statement)
4311 statement->toCBuffer(buf, hgs);
4312 }
4313
4314
4315 /******************************** LabelDsymbol ***************************/
4316
4317 LabelDsymbol::LabelDsymbol(Identifier *ident)
4318 : Dsymbol(ident)
4319 {
4320 statement = NULL;
4321 }
4322
4323 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
4324 {
4325 return this;
4326 }
4327
4328