root/trunk/src/statement.c

Revision 879, 127.6 kB (checked in by walter, 1 year ago)

64 bit alignment fix

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