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