]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/statementsem.c
PR d/90650
[thirdparty/gcc.git] / gcc / d / dmd / statementsem.c
1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 */
9
10 #include "root/dsystem.h"
11 #include "root/rmem.h"
12 #include "root/checkedint.h"
13
14 #include "errors.h"
15 #include "statement.h"
16 #include "expression.h"
17 #include "cond.h"
18 #include "init.h"
19 #include "staticassert.h"
20 #include "module.h"
21 #include "scope.h"
22 #include "declaration.h"
23 #include "aggregate.h"
24 #include "id.h"
25 #include "enum.h"
26 #include "template.h"
27 #include "import.h"
28 #include "target.h"
29 #include "visitor.h"
30
31 StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
32 bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
33 bool checkThrowEscape(Scope *sc, Expression *e, bool gag);
34 LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement);
35 Identifier *fixupLabelName(Scope *sc, Identifier *ident);
36 FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
37 VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
38 Expression *checkAssignmentAsCondition(Expression *e);
39 TypeIdentifier *getThrowable();
40
41 Expression *semantic(Expression *e, Scope *sc);
42 Statement *semantic(Statement *s, Scope *sc);
43 void semantic(Catch *c, Scope *sc);
44 Statement *semanticNoScope(Statement *s, Scope *sc);
45 Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
46 int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
47
48 class StatementSemanticVisitor : public Visitor
49 {
50 public:
51 Statement *result;
52 Scope *sc;
53
54 StatementSemanticVisitor(Scope *sc)
55 {
56 this->result = NULL;
57 this->sc = sc;
58 }
59
60 private:
61 void setError()
62 {
63 result = new ErrorStatement();
64 }
65
66 public:
67 void visit(Statement *s)
68 {
69 result = s;
70 }
71
72 void visit(ErrorStatement *s)
73 {
74 result = s;
75 }
76
77 void visit(PeelStatement *s)
78 {
79 /* "peel" off this wrapper, and don't run semantic()
80 * on the result.
81 */
82 result = s->s;
83 }
84
85 void visit(ExpStatement *s)
86 {
87 if (s->exp)
88 {
89 //printf("ExpStatement::semantic() %s\n", s->exp->toChars());
90
91 // Allow CommaExp in ExpStatement because return isn't used
92 if (s->exp->op == TOKcomma)
93 ((CommaExp *)s->exp)->allowCommaExp = true;
94
95 s->exp = semantic(s->exp, sc);
96 s->exp = resolveProperties(sc, s->exp);
97 s->exp = s->exp->addDtorHook(sc);
98 if (checkNonAssignmentArrayOp(s->exp))
99 s->exp = new ErrorExp();
100 if (FuncDeclaration *f = isFuncAddress(s->exp))
101 {
102 if (f->checkForwardRef(s->exp->loc))
103 s->exp = new ErrorExp();
104 }
105 if (discardValue(s->exp))
106 s->exp = new ErrorExp();
107
108 s->exp = s->exp->optimize(WANTvalue);
109 s->exp = checkGC(sc, s->exp);
110 if (s->exp->op == TOKerror)
111 return setError();
112 }
113 result = s;
114 }
115
116 void visit(CompileStatement *cs)
117 {
118 //printf("CompileStatement::semantic() %s\n", cs->exp->toChars());
119 Statements *a = cs->flatten(sc);
120 if (!a)
121 return;
122 Statement *s = new CompoundStatement(cs->loc, a);
123 result = semantic(s, sc);
124 }
125
126 void visit(CompoundStatement *cs)
127 {
128 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
129 for (size_t i = 0; i < cs->statements->dim; )
130 {
131 Statement *s = (*cs->statements)[i];
132 if (s)
133 {
134 Statements *flt = s->flatten(sc);
135 if (flt)
136 {
137 cs->statements->remove(i);
138 cs->statements->insert(i, flt);
139 continue;
140 }
141 s = semantic(s, sc);
142 (*cs->statements)[i] = s;
143 if (s)
144 {
145 Statement *sentry;
146 Statement *sexception;
147 Statement *sfinally;
148
149 (*cs->statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally);
150 if (sentry)
151 {
152 sentry = semantic(sentry, sc);
153 cs->statements->insert(i, sentry);
154 i++;
155 }
156 if (sexception)
157 sexception = semantic(sexception, sc);
158 if (sexception)
159 {
160 if (i + 1 == cs->statements->dim && !sfinally)
161 {
162 }
163 else
164 {
165 /* Rewrite:
166 * s; s1; s2;
167 * As:
168 * s;
169 * try { s1; s2; }
170 * catch (Throwable __o)
171 * { sexception; throw __o; }
172 */
173 Statements *a = new Statements();
174 for (size_t j = i + 1; j < cs->statements->dim; j++)
175 {
176 a->push((*cs->statements)[j]);
177 }
178 Statement *body = new CompoundStatement(Loc(), a);
179 body = new ScopeStatement(Loc(), body, Loc());
180
181 Identifier *id = Identifier::generateId("__o");
182
183 Statement *handler = new PeelStatement(sexception);
184 if (blockExit(sexception, sc->func, false) & BEfallthru)
185 {
186 ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
187 ts->internalThrow = true;
188 handler = new CompoundStatement(Loc(), handler, ts);
189 }
190
191 Catches *catches = new Catches();
192 Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
193 ctch->internalCatch = true;
194 catches->push(ctch);
195
196 s = new TryCatchStatement(Loc(), body, catches);
197 if (sfinally)
198 s = new TryFinallyStatement(Loc(), s, sfinally);
199 s = semantic(s, sc);
200
201 cs->statements->setDim(i + 1);
202 cs->statements->push(s);
203 break;
204 }
205 }
206 else if (sfinally)
207 {
208 if (0 && i + 1 == cs->statements->dim)
209 {
210 cs->statements->push(sfinally);
211 }
212 else
213 {
214 /* Rewrite:
215 * s; s1; s2;
216 * As:
217 * s; try { s1; s2; } finally { sfinally; }
218 */
219 Statements *a = new Statements();
220 for (size_t j = i + 1; j < cs->statements->dim; j++)
221 {
222 a->push((*cs->statements)[j]);
223 }
224 Statement *body = new CompoundStatement(Loc(), a);
225 s = new TryFinallyStatement(Loc(), body, sfinally);
226 s = semantic(s, sc);
227 cs->statements->setDim(i + 1);
228 cs->statements->push(s);
229 break;
230 }
231 }
232 }
233 else
234 {
235 /* Remove NULL statements from the list.
236 */
237 cs->statements->remove(i);
238 continue;
239 }
240 }
241 i++;
242 }
243 for (size_t i = 0; i < cs->statements->dim; ++i)
244 {
245 Lagain:
246 Statement *s = (*cs->statements)[i];
247 if (!s)
248 continue;
249
250 Statement *se = s->isErrorStatement();
251 if (se)
252 {
253 result = se;
254 return;
255 }
256
257 /* Bugzilla 11653: 'semantic' may return another CompoundStatement
258 * (eg. CaseRangeStatement), so flatten it here.
259 */
260 Statements *flt = s->flatten(sc);
261 if (flt)
262 {
263 cs->statements->remove(i);
264 cs->statements->insert(i, flt);
265 if (cs->statements->dim <= i)
266 break;
267 goto Lagain;
268 }
269 }
270 if (cs->statements->dim == 1)
271 {
272 result = (*cs->statements)[0];
273 return;
274 }
275 result = cs;
276 }
277
278 void visit(UnrolledLoopStatement *uls)
279 {
280 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
281 Scope *scd = sc->push();
282 scd->sbreak = uls;
283 scd->scontinue = uls;
284
285 Statement *serror = NULL;
286 for (size_t i = 0; i < uls->statements->dim; i++)
287 {
288 Statement *s = (*uls->statements)[i];
289 if (s)
290 {
291 //printf("[%d]: %s\n", i, s->toChars());
292 s = semantic(s, scd);
293 (*uls->statements)[i] = s;
294
295 if (s && !serror)
296 serror = s->isErrorStatement();
297 }
298 }
299
300 scd->pop();
301 result = serror ? serror : uls;
302 }
303
304 void visit(ScopeStatement *ss)
305 {
306 ScopeDsymbol *sym;
307 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
308 if (ss->statement)
309 {
310 sym = new ScopeDsymbol();
311 sym->parent = sc->scopesym;
312 sym->endlinnum = ss->endloc.linnum;
313 sc = sc->push(sym);
314
315 Statements *a = ss->statement->flatten(sc);
316 if (a)
317 {
318 ss->statement = new CompoundStatement(ss->loc, a);
319 }
320
321 ss->statement = semantic(ss->statement, sc);
322 if (ss->statement)
323 {
324 if (ss->statement->isErrorStatement())
325 {
326 sc->pop();
327 result = ss->statement;
328 return;
329 }
330
331 Statement *sentry;
332 Statement *sexception;
333 Statement *sfinally;
334
335 ss->statement = ss->statement->scopeCode(sc, &sentry, &sexception, &sfinally);
336 assert(!sentry);
337 assert(!sexception);
338 if (sfinally)
339 {
340 //printf("adding sfinally\n");
341 sfinally = semantic(sfinally, sc);
342 ss->statement = new CompoundStatement(ss->loc, ss->statement, sfinally);
343 }
344 }
345
346 sc->pop();
347 }
348 result = ss;
349 }
350
351 void visit(WhileStatement *ws)
352 {
353 /* Rewrite as a for(;condition;) loop
354 */
355 Statement *s = new ForStatement(ws->loc, NULL, ws->condition, NULL, ws->_body, ws->endloc);
356 s = semantic(s, sc);
357 result = s;
358 }
359
360 void visit(DoStatement *ds)
361 {
362 sc->noctor++;
363 if (ds->_body)
364 ds->_body = semanticScope(ds->_body, sc, ds, ds);
365 sc->noctor--;
366
367 if (ds->condition->op == TOKdotid)
368 ((DotIdExp *)ds->condition)->noderef = true;
369
370 // check in syntax level
371 ds->condition = checkAssignmentAsCondition(ds->condition);
372
373 ds->condition = semantic(ds->condition, sc);
374 ds->condition = resolveProperties(sc, ds->condition);
375 if (checkNonAssignmentArrayOp(ds->condition))
376 ds->condition = new ErrorExp();
377 ds->condition = ds->condition->optimize(WANTvalue);
378 ds->condition = checkGC(sc, ds->condition);
379
380 ds->condition = ds->condition->toBoolean(sc);
381
382 if (ds->condition->op == TOKerror)
383 return setError();
384
385 if (ds->_body && ds->_body->isErrorStatement())
386 {
387 result = ds->_body;
388 return;
389 }
390
391 result = ds;
392 }
393
394 void visit(ForStatement *fs)
395 {
396 //printf("ForStatement::semantic %s\n", toChars());
397
398 if (fs->_init)
399 {
400 /* Rewrite:
401 * for (auto v1 = i1, v2 = i2; condition; increment) { ... }
402 * to:
403 * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
404 * then lowered to:
405 * auto v1 = i1;
406 * try {
407 * auto v2 = i2;
408 * try {
409 * for (; condition; increment) { ... }
410 * } finally { v2.~this(); }
411 * } finally { v1.~this(); }
412 */
413 Statements *ainit = new Statements();
414 ainit->push(fs->_init);
415 fs->_init = NULL;
416 ainit->push(fs);
417 Statement *s = new CompoundStatement(fs->loc, ainit);
418 s = new ScopeStatement(fs->loc, s, fs->endloc);
419 s = semantic(s, sc);
420 if (!s->isErrorStatement())
421 {
422 if (LabelStatement *ls = checkLabeledLoop(sc, fs))
423 ls->gotoTarget = fs;
424 fs->relatedLabeled = s;
425 }
426 result = s;
427 return;
428 }
429 assert(fs->_init == NULL);
430
431 ScopeDsymbol *sym = new ScopeDsymbol();
432 sym->parent = sc->scopesym;
433 sym->endlinnum = fs->endloc.linnum;
434 sc = sc->push(sym);
435
436 sc->noctor++;
437 if (fs->condition)
438 {
439 if (fs->condition->op == TOKdotid)
440 ((DotIdExp *)fs->condition)->noderef = true;
441
442 // check in syntax level
443 fs->condition = checkAssignmentAsCondition(fs->condition);
444
445 fs->condition = semantic(fs->condition, sc);
446 fs->condition = resolveProperties(sc, fs->condition);
447 if (checkNonAssignmentArrayOp(fs->condition))
448 fs->condition = new ErrorExp();
449 fs->condition = fs->condition->optimize(WANTvalue);
450 fs->condition = checkGC(sc, fs->condition);
451 fs->condition = fs->condition->toBoolean(sc);
452 }
453 if (fs->increment)
454 {
455 if (fs->increment->op == TOKcomma)
456 ((CommaExp *)fs->increment)->allowCommaExp = true;
457 fs->increment = semantic(fs->increment, sc);
458 fs->increment = resolveProperties(sc, fs->increment);
459 if (checkNonAssignmentArrayOp(fs->increment))
460 fs->increment = new ErrorExp();
461 fs->increment = fs->increment->optimize(WANTvalue);
462 fs->increment = checkGC(sc, fs->increment);
463 }
464
465 sc->sbreak = fs;
466 sc->scontinue = fs;
467 if (fs->_body)
468 fs->_body = semanticNoScope(fs->_body, sc);
469 sc->noctor--;
470
471 sc->pop();
472
473 if ((fs->condition && fs->condition->op == TOKerror) ||
474 (fs->increment && fs->increment->op == TOKerror) ||
475 (fs->_body && fs->_body->isErrorStatement()))
476 return setError();
477
478 result = fs;
479 }
480
481 void visit(ForeachStatement *fs)
482 {
483 //printf("ForeachStatement::semantic() %p\n", fs);
484 ScopeDsymbol *sym;
485 Statement *s = fs;
486 Loc loc = fs->loc;
487 size_t dim = fs->parameters->dim;
488 TypeAArray *taa = NULL;
489 Dsymbol *sapply = NULL;
490
491 Type *tn = NULL;
492 Type *tnv = NULL;
493
494 fs->func = sc->func;
495 if (fs->func->fes)
496 fs->func = fs->func->fes->func;
497
498 VarDeclaration *vinit = NULL;
499 fs->aggr = semantic(fs->aggr, sc);
500 fs->aggr = resolveProperties(sc, fs->aggr);
501 fs->aggr = fs->aggr->optimize(WANTvalue);
502 if (fs->aggr->op == TOKerror)
503 return setError();
504
505 Expression *oaggr = fs->aggr;
506 if (fs->aggr->type && fs->aggr->type->toBasetype()->ty == Tstruct &&
507 ((TypeStruct *)(fs->aggr->type->toBasetype()))->sym->dtor &&
508 fs->aggr->op != TOKtype && !fs->aggr->isLvalue())
509 {
510 // Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
511 vinit = copyToTemp(STCrvalue, "__aggr", fs->aggr);
512 vinit->semantic(sc);
513 fs->aggr = new VarExp(fs->aggr->loc, vinit);
514 }
515
516 if (!inferAggregate(fs, sc, sapply))
517 {
518 const char *msg = "";
519 if (fs->aggr->type && isAggregate(fs->aggr->type))
520 {
521 msg = ", define opApply(), range primitives, or use .tupleof";
522 }
523 fs->error("invalid foreach aggregate %s%s", oaggr->toChars(), msg);
524 return setError();
525 }
526
527 Dsymbol* sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
528
529 /* Check for inference errors
530 */
531 if (!inferApplyArgTypes(fs, sc, sapply))
532 {
533 /**
534 Try and extract the parameter count of the opApply callback function, e.g.:
535 int opApply(int delegate(int, float)) => 2 args
536 */
537 bool foundMismatch = false;
538 size_t foreachParamCount = 0;
539 if (sapplyOld)
540 {
541 if (FuncDeclaration *fd = sapplyOld->isFuncDeclaration())
542 {
543 int fvarargs; // ignored (opApply shouldn't take variadics)
544 Parameters *fparameters = fd->getParameters(&fvarargs);
545
546 if (Parameter::dim(fparameters) == 1)
547 {
548 // first param should be the callback function
549 Parameter *fparam = Parameter::getNth(fparameters, 0);
550 if ((fparam->type->ty == Tpointer || fparam->type->ty == Tdelegate) &&
551 fparam->type->nextOf()->ty == Tfunction)
552 {
553 TypeFunction *tf = (TypeFunction *)fparam->type->nextOf();
554 foreachParamCount = Parameter::dim(tf->parameters);
555 foundMismatch = true;
556 }
557 }
558 }
559 }
560
561 //printf("dim = %d, parameters->dim = %d\n", dim, fs->parameters->dim);
562 if (foundMismatch && dim != foreachParamCount)
563 {
564 const char *plural = foreachParamCount > 1 ? "s" : "";
565 fs->error("cannot infer argument types, expected %d argument%s, not %d",
566 foreachParamCount, plural, dim);
567 }
568 else
569 fs->error("cannot uniquely infer foreach argument types");
570
571 return setError();
572 }
573
574 Type *tab = fs->aggr->type->toBasetype();
575
576 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
577 {
578 if (dim < 1 || dim > 2)
579 {
580 fs->error("only one (value) or two (key,value) arguments for tuple foreach");
581 return setError();
582 }
583
584 Type *paramtype = (*fs->parameters)[dim-1]->type;
585 if (paramtype)
586 {
587 paramtype = paramtype->semantic(loc, sc);
588 if (paramtype->ty == Terror)
589 return setError();
590 }
591
592 TypeTuple *tuple = (TypeTuple *)tab;
593 Statements *statements = new Statements();
594 //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
595 size_t n;
596 TupleExp *te = NULL;
597 if (fs->aggr->op == TOKtuple) // expression tuple
598 {
599 te = (TupleExp *)fs->aggr;
600 n = te->exps->dim;
601 }
602 else if (fs->aggr->op == TOKtype) // type tuple
603 {
604 n = Parameter::dim(tuple->arguments);
605 }
606 else
607 assert(0);
608 for (size_t j = 0; j < n; j++)
609 {
610 size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
611 Expression *e = NULL;
612 Type *t = NULL;
613 if (te)
614 e = (*te->exps)[k];
615 else
616 t = Parameter::getNth(tuple->arguments, k)->type;
617 Parameter *p = (*fs->parameters)[0];
618 Statements *st = new Statements();
619
620 if (dim == 2)
621 {
622 // Declare key
623 if (p->storageClass & (STCout | STCref | STClazy))
624 {
625 fs->error("no storage class for key %s", p->ident->toChars());
626 return setError();
627 }
628 p->type = p->type->semantic(loc, sc);
629 TY keyty = p->type->ty;
630 if (keyty != Tint32 && keyty != Tuns32)
631 {
632 if (global.params.isLP64)
633 {
634 if (keyty != Tint64 && keyty != Tuns64)
635 {
636 fs->error("foreach: key type must be int or uint, long or ulong, not %s", p->type->toChars());
637 return setError();
638 }
639 }
640 else
641 {
642 fs->error("foreach: key type must be int or uint, not %s", p->type->toChars());
643 return setError();
644 }
645 }
646 Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
647 VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
648 var->storage_class |= STCmanifest;
649 st->push(new ExpStatement(loc, var));
650 p = (*fs->parameters)[1]; // value
651 }
652 // Declare value
653 if (p->storageClass & (STCout | STClazy) ||
654 (p->storageClass & STCref && !te))
655 {
656 fs->error("no storage class for value %s", p->ident->toChars());
657 return setError();
658 }
659 Dsymbol *var;
660 if (te)
661 {
662 Type *tb = e->type->toBasetype();
663 Dsymbol *ds = NULL;
664 if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
665 ds = ((VarExp *)e)->var;
666 else if (e->op == TOKtemplate)
667 ds = ((TemplateExp *)e)->td;
668 else if (e->op == TOKscope)
669 ds = ((ScopeExp *)e)->sds;
670 else if (e->op == TOKfunction)
671 {
672 FuncExp *fe = (FuncExp *)e;
673 ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
674 }
675
676 if (ds)
677 {
678 var = new AliasDeclaration(loc, p->ident, ds);
679 if (p->storageClass & STCref)
680 {
681 fs->error("symbol %s cannot be ref", s->toChars());
682 return setError();
683 }
684 if (paramtype)
685 {
686 fs->error("cannot specify element type for symbol %s", ds->toChars());
687 return setError();
688 }
689 }
690 else if (e->op == TOKtype)
691 {
692 var = new AliasDeclaration(loc, p->ident, e->type);
693 if (paramtype)
694 {
695 fs->error("cannot specify element type for type %s", e->type->toChars());
696 return setError();
697 }
698 }
699 else
700 {
701 p->type = e->type;
702 if (paramtype)
703 p->type = paramtype;
704 Initializer *ie = new ExpInitializer(Loc(), e);
705 VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ie);
706 if (p->storageClass & STCref)
707 v->storage_class |= STCref | STCforeach;
708 if (e->isConst() || e->op == TOKstring ||
709 e->op == TOKstructliteral || e->op == TOKarrayliteral)
710 {
711 if (v->storage_class & STCref)
712 {
713 fs->error("constant value %s cannot be ref", ie->toChars());
714 return setError();
715 }
716 else
717 v->storage_class |= STCmanifest;
718 }
719 var = v;
720 }
721 }
722 else
723 {
724 var = new AliasDeclaration(loc, p->ident, t);
725 if (paramtype)
726 {
727 fs->error("cannot specify element type for symbol %s", s->toChars());
728 return setError();
729 }
730 }
731 st->push(new ExpStatement(loc, var));
732
733 if (fs->_body)
734 st->push(fs->_body->syntaxCopy());
735 s = new CompoundStatement(loc, st);
736 s = new ScopeStatement(loc, s, fs->endloc);
737 statements->push(s);
738 }
739
740 s = new UnrolledLoopStatement(loc, statements);
741 if (LabelStatement *ls = checkLabeledLoop(sc, fs))
742 ls->gotoTarget = s;
743 if (te && te->e0)
744 s = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), s);
745 if (vinit)
746 s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
747 s = semantic(s, sc);
748 result = s;
749 return;
750 }
751
752 sym = new ScopeDsymbol();
753 sym->parent = sc->scopesym;
754 sym->endlinnum = fs->endloc.linnum;
755 Scope *sc2 = sc->push(sym);
756
757 sc2->noctor++;
758
759 switch (tab->ty)
760 {
761 case Tarray:
762 case Tsarray:
763 {
764 if (fs->checkForArgTypes())
765 {
766 result = fs;
767 return;
768 }
769
770 if (dim < 1 || dim > 2)
771 {
772 fs->error("only one or two arguments for array foreach");
773 goto Lerror2;
774 }
775
776 /* Look for special case of parsing char types out of char type
777 * array.
778 */
779 tn = tab->nextOf()->toBasetype();
780 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
781 {
782 int i = (dim == 1) ? 0 : 1; // index of value
783 Parameter *p = (*fs->parameters)[i];
784 p->type = p->type->semantic(loc, sc2);
785 p->type = p->type->addStorageClass(p->storageClass);
786 tnv = p->type->toBasetype();
787 if (tnv->ty != tn->ty &&
788 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
789 {
790 if (p->storageClass & STCref)
791 {
792 fs->error("foreach: value of UTF conversion cannot be ref");
793 goto Lerror2;
794 }
795 if (dim == 2)
796 {
797 p = (*fs->parameters)[0];
798 if (p->storageClass & STCref)
799 {
800 fs->error("foreach: key cannot be ref");
801 goto Lerror2;
802 }
803 }
804 goto Lapply;
805 }
806 }
807
808 for (size_t i = 0; i < dim; i++)
809 {
810 // Declare parameterss
811 Parameter *p = (*fs->parameters)[i];
812 p->type = p->type->semantic(loc, sc2);
813 p->type = p->type->addStorageClass(p->storageClass);
814 VarDeclaration *var;
815
816 if (dim == 2 && i == 0)
817 {
818 var = new VarDeclaration(loc, p->type->mutableOf(), Identifier::generateId("__key"), NULL);
819 var->storage_class |= STCtemp | STCforeach;
820 if (var->storage_class & (STCref | STCout))
821 var->storage_class |= STCnodtor;
822
823 fs->key = var;
824 if (p->storageClass & STCref)
825 {
826 if (var->type->constConv(p->type) <= MATCHnomatch)
827 {
828 fs->error("key type mismatch, %s to ref %s",
829 var->type->toChars(), p->type->toChars());
830 goto Lerror2;
831 }
832 }
833 if (tab->ty == Tsarray)
834 {
835 TypeSArray *ta = (TypeSArray *)tab;
836 IntRange dimrange = getIntRange(ta->dim);
837 if (!IntRange::fromType(var->type).contains(dimrange))
838 {
839 fs->error("index type '%s' cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
840 goto Lerror2;
841 }
842 fs->key->range = new IntRange(SignExtendedNumber(0), dimrange.imax);
843 }
844 }
845 else
846 {
847 var = new VarDeclaration(loc, p->type, p->ident, NULL);
848 var->storage_class |= STCforeach;
849 var->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
850 if (var->storage_class & (STCref | STCout))
851 var->storage_class |= STCnodtor;
852
853 fs->value = var;
854 if (var->storage_class & STCref)
855 {
856 if (fs->aggr->checkModifiable(sc2, 1) == 2)
857 var->storage_class |= STCctorinit;
858
859 Type *t = tab->nextOf();
860 if (t->constConv(p->type) <= MATCHnomatch)
861 {
862 fs->error("argument type mismatch, %s to ref %s",
863 t->toChars(), p->type->toChars());
864 goto Lerror2;
865 }
866 }
867 }
868 }
869
870 /* Convert to a ForStatement
871 * foreach (key, value; a) body =>
872 * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
873 * { T value = tmp[k]; body }
874 *
875 * foreach_reverse (key, value; a) body =>
876 * for (T[] tmp = a[], size_t key = tmp.length; key--; )
877 * { T value = tmp[k]; body }
878 */
879 Identifier *id = Identifier::generateId("__r");
880 ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, fs->aggr, NULL, NULL));
881 VarDeclaration *tmp;
882 if (fs->aggr->op == TOKarrayliteral &&
883 !((*fs->parameters)[dim - 1]->storageClass & STCref))
884 {
885 ArrayLiteralExp *ale = (ArrayLiteralExp *)fs->aggr;
886 size_t edim = ale->elements ? ale->elements->dim : 0;
887 Type *telem = (*fs->parameters)[dim - 1]->type;
888
889 // Bugzilla 12936: if telem has been specified explicitly,
890 // converting array literal elements to telem might make it @nogc.
891 fs->aggr = fs->aggr->implicitCastTo(sc, telem->sarrayOf(edim));
892 if (fs->aggr->op == TOKerror)
893 goto Lerror2;
894
895 // for (T[edim] tmp = a, ...)
896 tmp = new VarDeclaration(loc, fs->aggr->type, id, ie);
897 }
898 else
899 tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie);
900 tmp->storage_class |= STCtemp;
901 tmp->endlinnum = fs->endloc.linnum;
902
903 Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
904
905 if (!fs->key)
906 {
907 Identifier *idkey = Identifier::generateId("__key");
908 fs->key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL);
909 fs->key->storage_class |= STCtemp;
910 }
911 if (fs->op == TOKforeach_reverse)
912 fs->key->_init = new ExpInitializer(loc, tmp_length);
913 else
914 fs->key->_init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs->key->type));
915
916 Statements *cs = new Statements();
917 if (vinit)
918 cs->push(new ExpStatement(loc, vinit));
919 cs->push(new ExpStatement(loc, tmp));
920 cs->push(new ExpStatement(loc, fs->key));
921 Statement *forinit = new CompoundDeclarationStatement(loc, cs);
922
923 Expression *cond;
924 if (fs->op == TOKforeach_reverse)
925 {
926 // key--
927 cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
928 }
929 else
930 {
931 // key < tmp.length
932 cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), tmp_length);
933 }
934
935 Expression *increment = NULL;
936 if (fs->op == TOKforeach)
937 {
938 // key += 1
939 increment = new AddAssignExp(loc, new VarExp(loc, fs->key), new IntegerExp(loc, 1, fs->key->type));
940 }
941
942 // T value = tmp[key];
943 fs->value->_init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs->key)));
944 Statement *ds = new ExpStatement(loc, fs->value);
945
946 if (dim == 2)
947 {
948 Parameter *p = (*fs->parameters)[0];
949 if ((p->storageClass & STCref) && p->type->equals(fs->key->type))
950 {
951 fs->key->range = NULL;
952 AliasDeclaration *v = new AliasDeclaration(loc, p->ident, fs->key);
953 fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
954 }
955 else
956 {
957 ExpInitializer *ei = new ExpInitializer(loc, new IdentifierExp(loc, fs->key->ident));
958 VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ei);
959 v->storage_class |= STCforeach | (p->storageClass & STCref);
960 fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
961 if (fs->key->range && !p->type->isMutable())
962 {
963 /* Limit the range of the key to the specified range
964 */
965 v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
966 }
967 }
968 }
969 fs->_body = new CompoundStatement(loc, ds, fs->_body);
970
971 s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
972 if (LabelStatement *ls = checkLabeledLoop(sc, fs)) // Bugzilla 15450: don't use sc2
973 ls->gotoTarget = s;
974 s = semantic(s, sc2);
975 break;
976 }
977
978 case Taarray:
979 if (fs->op == TOKforeach_reverse)
980 fs->warning("cannot use foreach_reverse with an associative array");
981 if (fs->checkForArgTypes())
982 {
983 result = fs;
984 return;
985 }
986
987 taa = (TypeAArray *)tab;
988 if (dim < 1 || dim > 2)
989 {
990 fs->error("only one or two arguments for associative array foreach");
991 goto Lerror2;
992 }
993 goto Lapply;
994
995 case Tclass:
996 case Tstruct:
997 /* Prefer using opApply, if it exists
998 */
999 if (sapply)
1000 goto Lapply;
1001
1002 {
1003 /* Look for range iteration, i.e. the properties
1004 * .empty, .popFront, .popBack, .front and .back
1005 * foreach (e; aggr) { ... }
1006 * translates to:
1007 * for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
1008 * auto e = __r.front;
1009 * ...
1010 * }
1011 */
1012 AggregateDeclaration *ad = (tab->ty == Tclass)
1013 ? (AggregateDeclaration *)((TypeClass *)tab)->sym
1014 : (AggregateDeclaration *)((TypeStruct *)tab)->sym;
1015 Identifier *idfront;
1016 Identifier *idpopFront;
1017 if (fs->op == TOKforeach)
1018 {
1019 idfront = Id::Ffront;
1020 idpopFront = Id::FpopFront;
1021 }
1022 else
1023 {
1024 idfront = Id::Fback;
1025 idpopFront = Id::FpopBack;
1026 }
1027 Dsymbol *sfront = ad->search(Loc(), idfront);
1028 if (!sfront)
1029 goto Lapply;
1030
1031 /* Generate a temporary __r and initialize it with the aggregate.
1032 */
1033 VarDeclaration *r;
1034 Statement *init;
1035 if (vinit && fs->aggr->op == TOKvar && ((VarExp *)fs->aggr)->var == vinit)
1036 {
1037 r = vinit;
1038 init = new ExpStatement(loc, vinit);
1039 }
1040 else
1041 {
1042 r = copyToTemp(0, "__r", fs->aggr);
1043 init = new ExpStatement(loc, r);
1044 if (vinit)
1045 init = new CompoundStatement(loc, new ExpStatement(loc, vinit), init);
1046 }
1047
1048 // !__r.empty
1049 Expression *e = new VarExp(loc, r);
1050 e = new DotIdExp(loc, e, Id::Fempty);
1051 Expression *condition = new NotExp(loc, e);
1052
1053 // __r.idpopFront()
1054 e = new VarExp(loc, r);
1055 Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront));
1056
1057 /* Declaration statement for e:
1058 * auto e = __r.idfront;
1059 */
1060 e = new VarExp(loc, r);
1061 Expression *einit = new DotIdExp(loc, e, idfront);
1062 Statement *makeargs, *forbody;
1063 if (dim == 1)
1064 {
1065 Parameter *p = (*fs->parameters)[0];
1066 VarDeclaration *ve = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, einit));
1067 ve->storage_class |= STCforeach;
1068 ve->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
1069
1070 makeargs = new ExpStatement(loc, ve);
1071 }
1072 else
1073 {
1074 VarDeclaration *vd = copyToTemp(STCref, "__front", einit);
1075 makeargs = new ExpStatement(loc, vd);
1076
1077 Type *tfront = NULL;
1078 if (FuncDeclaration *fd = sfront->isFuncDeclaration())
1079 {
1080 if (!fd->functionSemantic())
1081 goto Lrangeerr;
1082 tfront = fd->type;
1083 }
1084 else if (TemplateDeclaration *td = sfront->isTemplateDeclaration())
1085 {
1086 Expressions a;
1087 if (FuncDeclaration *f = resolveFuncCall(loc, sc, td, NULL, tab, &a, 1))
1088 tfront = f->type;
1089 }
1090 else if (Declaration *d = sfront->isDeclaration())
1091 {
1092 tfront = d->type;
1093 }
1094 if (!tfront || tfront->ty == Terror)
1095 goto Lrangeerr;
1096
1097 if (tfront->toBasetype()->ty == Tfunction)
1098 tfront = tfront->toBasetype()->nextOf();
1099 if (tfront->ty == Tvoid)
1100 {
1101 fs->error("%s.front is void and has no value", oaggr->toChars());
1102 goto Lerror2;
1103 }
1104
1105 // Resolve inout qualifier of front type
1106 tfront = tfront->substWildTo(tab->mod);
1107
1108 Expression *ve = new VarExp(loc, vd);
1109 ve->type = tfront;
1110
1111 Expressions *exps = new Expressions();
1112 exps->push(ve);
1113 int pos = 0;
1114 while (exps->dim < dim)
1115 {
1116 pos = expandAliasThisTuples(exps, pos);
1117 if (pos == -1)
1118 break;
1119 }
1120 if (exps->dim != dim)
1121 {
1122 const char *plural = exps->dim > 1 ? "s" : "";
1123 fs->error("cannot infer argument types, expected %d argument%s, not %d",
1124 exps->dim, plural, dim);
1125 goto Lerror2;
1126 }
1127
1128 for (size_t i = 0; i < dim; i++)
1129 {
1130 Parameter *p = (*fs->parameters)[i];
1131 Expression *exp = (*exps)[i];
1132 if (!p->type)
1133 p->type = exp->type;
1134 p->type = p->type->addStorageClass(p->storageClass)->semantic(loc, sc2);
1135 if (!exp->implicitConvTo(p->type))
1136 goto Lrangeerr;
1137
1138 VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, exp));
1139 var->storage_class |= STCctfe | STCref | STCforeach;
1140 makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var));
1141 }
1142
1143 }
1144
1145 forbody = new CompoundStatement(loc,
1146 makeargs, fs->_body);
1147
1148 s = new ForStatement(loc, init, condition, increment, forbody, fs->endloc);
1149 if (LabelStatement *ls = checkLabeledLoop(sc, fs))
1150 ls->gotoTarget = s;
1151 s = semantic(s, sc2);
1152 break;
1153
1154 Lrangeerr:
1155 fs->error("cannot infer argument types");
1156 goto Lerror2;
1157 }
1158 case Tdelegate:
1159 if (fs->op == TOKforeach_reverse)
1160 fs->deprecation("cannot use foreach_reverse with a delegate");
1161 Lapply:
1162 {
1163 if (fs->checkForArgTypes())
1164 {
1165 fs->_body = semanticNoScope(fs->_body, sc2);
1166 result = fs;
1167 return;
1168 }
1169
1170 TypeFunction *tfld = NULL;
1171 if (sapply)
1172 {
1173 FuncDeclaration *fdapply = sapply->isFuncDeclaration();
1174 if (fdapply)
1175 {
1176 assert(fdapply->type && fdapply->type->ty == Tfunction);
1177 tfld = (TypeFunction *)fdapply->type->semantic(loc, sc2);
1178 goto Lget;
1179 }
1180 else if (tab->ty == Tdelegate)
1181 {
1182 tfld = (TypeFunction *)tab->nextOf();
1183 Lget:
1184 //printf("tfld = %s\n", tfld->toChars());
1185 if (tfld->parameters->dim == 1)
1186 {
1187 Parameter *p = Parameter::getNth(tfld->parameters, 0);
1188 if (p->type && p->type->ty == Tdelegate)
1189 {
1190 Type *t = p->type->semantic(loc, sc2);
1191 assert(t->ty == Tdelegate);
1192 tfld = (TypeFunction *)t->nextOf();
1193 }
1194 }
1195 }
1196 }
1197
1198 /* Turn body into the function literal:
1199 * int delegate(ref T param) { body }
1200 */
1201 Parameters *params = new Parameters();
1202 for (size_t i = 0; i < dim; i++)
1203 {
1204 Parameter *p = (*fs->parameters)[i];
1205 StorageClass stc = STCref;
1206 Identifier *id;
1207
1208 p->type = p->type->semantic(loc, sc2);
1209 p->type = p->type->addStorageClass(p->storageClass);
1210 if (tfld)
1211 {
1212 Parameter *prm = Parameter::getNth(tfld->parameters, i);
1213 //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars());
1214 stc = prm->storageClass & STCref;
1215 id = p->ident; // argument copy is not need.
1216 if ((p->storageClass & STCref) != stc)
1217 {
1218 if (!stc)
1219 {
1220 fs->error("foreach: cannot make %s ref", p->ident->toChars());
1221 goto Lerror2;
1222 }
1223 goto LcopyArg;
1224 }
1225 }
1226 else if (p->storageClass & STCref)
1227 {
1228 // default delegate parameters are marked as ref, then
1229 // argument copy is not need.
1230 id = p->ident;
1231 }
1232 else
1233 {
1234 // Make a copy of the ref argument so it isn't
1235 // a reference.
1236 LcopyArg:
1237 id = Identifier::generateId("__applyArg", (int)i);
1238
1239 Initializer *ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id));
1240 VarDeclaration *v = new VarDeclaration(Loc(), p->type, p->ident, ie);
1241 v->storage_class |= STCtemp;
1242 s = new ExpStatement(Loc(), v);
1243 fs->_body = new CompoundStatement(loc, s, fs->_body);
1244 }
1245 params->push(new Parameter(stc, p->type, id, NULL));
1246 }
1247 // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
1248 StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, fs->func);
1249 tfld = new TypeFunction(params, Type::tint32, 0, LINKd, stc);
1250 fs->cases = new Statements();
1251 fs->gotos = new ScopeStatements();
1252 FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, fs);
1253 fld->fbody = fs->_body;
1254 Expression *flde = new FuncExp(loc, fld);
1255 flde = semantic(flde, sc2);
1256 fld->tookAddressOf = 0;
1257
1258 // Resolve any forward referenced goto's
1259 for (size_t i = 0; i < fs->gotos->dim; i++)
1260 {
1261 GotoStatement *gs = (GotoStatement *)(*fs->gotos)[i]->statement;
1262 if (!gs->label->statement)
1263 {
1264 // 'Promote' it to this scope, and replace with a return
1265 fs->cases->push(gs);
1266 s = new ReturnStatement(Loc(), new IntegerExp(fs->cases->dim + 1));
1267 (*fs->gotos)[i]->statement = s;
1268 }
1269 }
1270
1271 Expression *e = NULL;
1272 Expression *ec;
1273 if (vinit)
1274 {
1275 e = new DeclarationExp(loc, vinit);
1276 e = semantic(e, sc2);
1277 if (e->op == TOKerror)
1278 goto Lerror2;
1279 }
1280
1281 if (taa)
1282 {
1283 // Check types
1284 Parameter *p = (*fs->parameters)[0];
1285 bool isRef = (p->storageClass & STCref) != 0;
1286 Type *ta = p->type;
1287 if (dim == 2)
1288 {
1289 Type *ti = (isRef ? taa->index->addMod(MODconst) : taa->index);
1290 if (isRef ? !ti->constConv(ta) : !ti->implicitConvTo(ta))
1291 {
1292 fs->error("foreach: index must be type %s, not %s", ti->toChars(), ta->toChars());
1293 goto Lerror2;
1294 }
1295 p = (*fs->parameters)[1];
1296 isRef = (p->storageClass & STCref) != 0;
1297 ta = p->type;
1298 }
1299 Type *taav = taa->nextOf();
1300 if (isRef ? !taav->constConv(ta) : !taav->implicitConvTo(ta))
1301 {
1302 fs->error("foreach: value must be type %s, not %s", taav->toChars(), ta->toChars());
1303 goto Lerror2;
1304 }
1305
1306 /* Call:
1307 * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
1308 * _aaApply(aggr, keysize, flde)
1309 *
1310 * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
1311 * _aaApply2(aggr, keysize, flde)
1312 */
1313 static const char *name[2] = { "_aaApply", "_aaApply2" };
1314 static FuncDeclaration *fdapply[2] = { NULL, NULL };
1315 static TypeDelegate *fldeTy[2] = { NULL, NULL };
1316
1317 unsigned char i = (dim == 2 ? 1 : 0);
1318 if (!fdapply[i])
1319 {
1320 params = new Parameters();
1321 params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL));
1322 params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL));
1323 Parameters* dgparams = new Parameters;
1324 dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
1325 if (dim == 2)
1326 dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
1327 fldeTy[i] = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
1328 params->push(new Parameter(0, fldeTy[i], NULL, NULL));
1329 fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]);
1330 }
1331
1332 Expressions *exps = new Expressions();
1333 exps->push(fs->aggr);
1334 d_uns64 keysize = taa->index->size();
1335 if (keysize == SIZE_INVALID)
1336 goto Lerror2;
1337 assert(keysize < UINT64_MAX - Target::ptrsize);
1338 keysize = (keysize + (Target::ptrsize- 1)) & ~(Target::ptrsize - 1);
1339 // paint delegate argument to the type runtime expects
1340 if (!fldeTy[i]->equals(flde->type))
1341 {
1342 flde = new CastExp(loc, flde, flde->type);
1343 flde->type = fldeTy[i];
1344 }
1345 exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t));
1346 exps->push(flde);
1347
1348 ec = new VarExp(Loc(), fdapply[i], false);
1349 ec = new CallExp(loc, ec, exps);
1350 ec->type = Type::tint32; // don't run semantic() on ec
1351 }
1352 else if (tab->ty == Tarray || tab->ty == Tsarray)
1353 {
1354 /* Call:
1355 * _aApply(aggr, flde)
1356 */
1357 static const char fntab[9][3] =
1358 { "cc","cw","cd",
1359 "wc","cc","wd",
1360 "dc","dw","dd"
1361 };
1362 const int BUFFER_LEN = 7+1+2+ sizeof(dim)*3 + 1;
1363 char fdname[BUFFER_LEN];
1364 int flag;
1365
1366 switch (tn->ty)
1367 {
1368 case Tchar: flag = 0; break;
1369 case Twchar: flag = 3; break;
1370 case Tdchar: flag = 6; break;
1371 default: assert(0);
1372 }
1373 switch (tnv->ty)
1374 {
1375 case Tchar: flag += 0; break;
1376 case Twchar: flag += 1; break;
1377 case Tdchar: flag += 2; break;
1378 default: assert(0);
1379 }
1380 const char *r = (fs->op == TOKforeach_reverse) ? "R" : "";
1381 int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim);
1382 assert(j < BUFFER_LEN);
1383
1384 FuncDeclaration *fdapply;
1385 TypeDelegate *dgty;
1386 params = new Parameters();
1387 params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL));
1388 Parameters* dgparams = new Parameters;
1389 dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
1390 if (dim == 2)
1391 dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
1392 dgty = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
1393 params->push(new Parameter(0, dgty, NULL, NULL));
1394 fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname);
1395
1396 if (tab->ty == Tsarray)
1397 fs->aggr = fs->aggr->castTo(sc2, tn->arrayOf());
1398
1399 // paint delegate argument to the type runtime expects
1400 if (!dgty->equals(flde->type)) {
1401 flde = new CastExp(loc, flde, flde->type);
1402 flde->type = dgty;
1403 }
1404
1405 ec = new VarExp(Loc(), fdapply, false);
1406 ec = new CallExp(loc, ec, fs->aggr, flde);
1407 ec->type = Type::tint32; // don't run semantic() on ec
1408 }
1409 else if (tab->ty == Tdelegate)
1410 {
1411 /* Call:
1412 * aggr(flde)
1413 */
1414 if (fs->aggr->op == TOKdelegate &&
1415 ((DelegateExp *)fs->aggr)->func->isNested())
1416 {
1417 // See Bugzilla 3560
1418 fs->aggr = ((DelegateExp *)fs->aggr)->e1;
1419 }
1420 ec = new CallExp(loc, fs->aggr, flde);
1421 ec = semantic(ec, sc2);
1422 if (ec->op == TOKerror)
1423 goto Lerror2;
1424 if (ec->type != Type::tint32)
1425 {
1426 fs->error("opApply() function for %s must return an int", tab->toChars());
1427 goto Lerror2;
1428 }
1429 }
1430 else
1431 {
1432 if (global.params.vsafe)
1433 fld->tookAddressOf = 1; // allocate a closure unless the opApply() uses 'scope'
1434
1435 assert(tab->ty == Tstruct || tab->ty == Tclass);
1436 assert(sapply);
1437 /* Call:
1438 * aggr.apply(flde)
1439 */
1440 ec = new DotIdExp(loc, fs->aggr, sapply->ident);
1441 ec = new CallExp(loc, ec, flde);
1442 ec = semantic(ec, sc2);
1443 if (ec->op == TOKerror)
1444 goto Lerror2;
1445 if (ec->type != Type::tint32)
1446 {
1447 fs->error("opApply() function for %s must return an int", tab->toChars());
1448 goto Lerror2;
1449 }
1450 }
1451 e = Expression::combine(e, ec);
1452
1453 if (!fs->cases->dim)
1454 {
1455 // Easy case, a clean exit from the loop
1456 e = new CastExp(loc, e, Type::tvoid); // Bugzilla 13899
1457 s = new ExpStatement(loc, e);
1458 }
1459 else
1460 {
1461 // Construct a switch statement around the return value
1462 // of the apply function.
1463 Statements *a = new Statements();
1464
1465 // default: break; takes care of cases 0 and 1
1466 s = new BreakStatement(Loc(), NULL);
1467 s = new DefaultStatement(Loc(), s);
1468 a->push(s);
1469
1470 // cases 2...
1471 for (size_t i = 0; i < fs->cases->dim; i++)
1472 {
1473 s = (*fs->cases)[i];
1474 s = new CaseStatement(Loc(), new IntegerExp(i + 2), s);
1475 a->push(s);
1476 }
1477
1478 s = new CompoundStatement(loc, a);
1479 s = new SwitchStatement(loc, e, s, false);
1480 }
1481 s = semantic(s, sc2);
1482 break;
1483 }
1484 case Terror:
1485 Lerror2:
1486 s = new ErrorStatement();
1487 break;
1488
1489 default:
1490 fs->error("foreach: %s is not an aggregate type", fs->aggr->type->toChars());
1491 goto Lerror2;
1492 }
1493 sc2->noctor--;
1494 sc2->pop();
1495 result = s;
1496 }
1497
1498 void visit(ForeachRangeStatement *fs)
1499 {
1500 //printf("ForeachRangeStatement::semantic() %p\n", fs);
1501 Loc loc = fs->loc;
1502 fs->lwr = semantic(fs->lwr, sc);
1503 fs->lwr = resolveProperties(sc, fs->lwr);
1504 fs->lwr = fs->lwr->optimize(WANTvalue);
1505 if (!fs->lwr->type)
1506 {
1507 fs->error("invalid range lower bound %s", fs->lwr->toChars());
1508 Lerror:
1509 return setError();
1510 }
1511
1512 fs->upr = semantic(fs->upr, sc);
1513 fs->upr = resolveProperties(sc, fs->upr);
1514 fs->upr = fs->upr->optimize(WANTvalue);
1515 if (!fs->upr->type)
1516 {
1517 fs->error("invalid range upper bound %s", fs->upr->toChars());
1518 goto Lerror;
1519 }
1520
1521 if (fs->prm->type)
1522 {
1523 fs->prm->type = fs->prm->type->semantic(loc, sc);
1524 fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
1525 fs->lwr = fs->lwr->implicitCastTo(sc, fs->prm->type);
1526
1527 if (fs->upr->implicitConvTo(fs->prm->type) || (fs->prm->storageClass & STCref))
1528 {
1529 fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
1530 }
1531 else
1532 {
1533 // See if upr-1 fits in prm->type
1534 Expression *limit = new MinExp(loc, fs->upr, new IntegerExp(1));
1535 limit = semantic(limit, sc);
1536 limit = limit->optimize(WANTvalue);
1537 if (!limit->implicitConvTo(fs->prm->type))
1538 {
1539 fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
1540 }
1541 }
1542 }
1543 else
1544 {
1545 /* Must infer types from lwr and upr
1546 */
1547 Type *tlwr = fs->lwr->type->toBasetype();
1548 if (tlwr->ty == Tstruct || tlwr->ty == Tclass)
1549 {
1550 /* Just picking the first really isn't good enough.
1551 */
1552 fs->prm->type = fs->lwr->type;
1553 }
1554 else if (fs->lwr->type == fs->upr->type)
1555 {
1556 /* Same logic as CondExp ?lwr:upr
1557 */
1558 fs->prm->type = fs->lwr->type;
1559 }
1560 else
1561 {
1562 AddExp ea(loc, fs->lwr, fs->upr);
1563 if (typeCombine(&ea, sc))
1564 return setError();
1565 fs->prm->type = ea.type;
1566 fs->lwr = ea.e1;
1567 fs->upr = ea.e2;
1568 }
1569 fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
1570 }
1571 if (fs->prm->type->ty == Terror ||
1572 fs->lwr->op == TOKerror ||
1573 fs->upr->op == TOKerror)
1574 {
1575 return setError();
1576 }
1577
1578 /* Convert to a for loop:
1579 * foreach (key; lwr .. upr) =>
1580 * for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
1581 *
1582 * foreach_reverse (key; lwr .. upr) =>
1583 * for (auto tmp = lwr, auto key = upr; key-- > tmp;)
1584 */
1585 ExpInitializer *ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->lwr : fs->upr);
1586 fs->key = new VarDeclaration(loc, fs->upr->type->mutableOf(), Identifier::generateId("__key"), ie);
1587 fs->key->storage_class |= STCtemp;
1588 SignExtendedNumber lower = getIntRange(fs->lwr).imin;
1589 SignExtendedNumber upper = getIntRange(fs->upr).imax;
1590 if (lower <= upper)
1591 {
1592 fs->key->range = new IntRange(lower, upper);
1593 }
1594
1595 Identifier *id = Identifier::generateId("__limit");
1596 ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->upr : fs->lwr);
1597 VarDeclaration *tmp = new VarDeclaration(loc, fs->upr->type, id, ie);
1598 tmp->storage_class |= STCtemp;
1599
1600 Statements *cs = new Statements();
1601 // Keep order of evaluation as lwr, then upr
1602 if (fs->op == TOKforeach)
1603 {
1604 cs->push(new ExpStatement(loc, fs->key));
1605 cs->push(new ExpStatement(loc, tmp));
1606 }
1607 else
1608 {
1609 cs->push(new ExpStatement(loc, tmp));
1610 cs->push(new ExpStatement(loc, fs->key));
1611 }
1612 Statement *forinit = new CompoundDeclarationStatement(loc, cs);
1613
1614 Expression *cond;
1615 if (fs->op == TOKforeach_reverse)
1616 {
1617 cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
1618 if (fs->prm->type->isscalar())
1619 {
1620 // key-- > tmp
1621 cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp));
1622 }
1623 else
1624 {
1625 // key-- != tmp
1626 cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp));
1627 }
1628 }
1629 else
1630 {
1631 if (fs->prm->type->isscalar())
1632 {
1633 // key < tmp
1634 cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
1635 }
1636 else
1637 {
1638 // key != tmp
1639 cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
1640 }
1641 }
1642
1643 Expression *increment = NULL;
1644 if (fs->op == TOKforeach)
1645 {
1646 // key += 1
1647 //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
1648 increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, fs->key));
1649 }
1650
1651 if ((fs->prm->storageClass & STCref) && fs->prm->type->equals(fs->key->type))
1652 {
1653 fs->key->range = NULL;
1654 AliasDeclaration *v = new AliasDeclaration(loc, fs->prm->ident, fs->key);
1655 fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
1656 }
1657 else
1658 {
1659 ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs->key), fs->prm->type));
1660 VarDeclaration *v = new VarDeclaration(loc, fs->prm->type, fs->prm->ident, ie);
1661 v->storage_class |= STCtemp | STCforeach | (fs->prm->storageClass & STCref);
1662 fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
1663 if (fs->key->range && !fs->prm->type->isMutable())
1664 {
1665 /* Limit the range of the key to the specified range
1666 */
1667 v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
1668 }
1669 }
1670 if (fs->prm->storageClass & STCref)
1671 {
1672 if (fs->key->type->constConv(fs->prm->type) <= MATCHnomatch)
1673 {
1674 fs->error("prmument type mismatch, %s to ref %s",
1675 fs->key->type->toChars(), fs->prm->type->toChars());
1676 goto Lerror;
1677 }
1678 }
1679
1680 ForStatement *s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
1681 if (LabelStatement *ls = checkLabeledLoop(sc, fs))
1682 ls->gotoTarget = s;
1683 result = semantic(s, sc);
1684 }
1685
1686 void visit(IfStatement *ifs)
1687 {
1688 // Evaluate at runtime
1689 unsigned cs0 = sc->callSuper;
1690 unsigned cs1;
1691 unsigned *fi0 = sc->saveFieldInit();
1692 unsigned *fi1 = NULL;
1693
1694 // check in syntax level
1695 ifs->condition = checkAssignmentAsCondition(ifs->condition);
1696
1697 ScopeDsymbol *sym = new ScopeDsymbol();
1698 sym->parent = sc->scopesym;
1699 sym->endlinnum = ifs->endloc.linnum;
1700 Scope *scd = sc->push(sym);
1701 if (ifs->prm)
1702 {
1703 /* Declare prm, which we will set to be the
1704 * result of condition.
1705 */
1706 ExpInitializer *ei = new ExpInitializer(ifs->loc, ifs->condition);
1707 ifs->match = new VarDeclaration(ifs->loc, ifs->prm->type, ifs->prm->ident, ei);
1708 ifs->match->parent = sc->func;
1709 ifs->match->storage_class |= ifs->prm->storageClass;
1710 ifs->match->semantic(scd);
1711
1712 DeclarationExp *de = new DeclarationExp(ifs->loc, ifs->match);
1713 VarExp *ve = new VarExp(ifs->loc, ifs->match);
1714 ifs->condition = new CommaExp(ifs->loc, de, ve);
1715 ifs->condition = semantic(ifs->condition, scd);
1716
1717 if (ifs->match->edtor)
1718 {
1719 Statement *sdtor = new DtorExpStatement(ifs->loc, ifs->match->edtor, ifs->match);
1720 sdtor = new OnScopeStatement(ifs->loc, TOKon_scope_exit, sdtor);
1721 ifs->ifbody = new CompoundStatement(ifs->loc, sdtor, ifs->ifbody);
1722 ifs->match->storage_class |= STCnodtor;
1723 }
1724 }
1725 else
1726 {
1727 if (ifs->condition->op == TOKdotid)
1728 ((DotIdExp *)ifs->condition)->noderef = true;
1729
1730 ifs->condition = semantic(ifs->condition, sc);
1731 ifs->condition = resolveProperties(sc, ifs->condition);
1732 ifs->condition = ifs->condition->addDtorHook(sc);
1733 }
1734 if (checkNonAssignmentArrayOp(ifs->condition))
1735 ifs->condition = new ErrorExp();
1736 ifs->condition = checkGC(sc, ifs->condition);
1737
1738 // Convert to boolean after declaring prm so this works:
1739 // if (S prm = S()) {}
1740 // where S is a struct that defines opCast!bool.
1741 ifs->condition = ifs->condition->toBoolean(sc);
1742
1743 // If we can short-circuit evaluate the if statement, don't do the
1744 // semantic analysis of the skipped code.
1745 // This feature allows a limited form of conditional compilation.
1746 ifs->condition = ifs->condition->optimize(WANTvalue);
1747 ifs->ifbody = semanticNoScope(ifs->ifbody, scd);
1748 scd->pop();
1749
1750 cs1 = sc->callSuper;
1751 fi1 = sc->fieldinit;
1752 sc->callSuper = cs0;
1753 sc->fieldinit = fi0;
1754 if (ifs->elsebody)
1755 ifs->elsebody = semanticScope(ifs->elsebody, sc, NULL, NULL);
1756 sc->mergeCallSuper(ifs->loc, cs1);
1757 sc->mergeFieldInit(ifs->loc, fi1);
1758
1759 if (ifs->condition->op == TOKerror ||
1760 (ifs->ifbody && ifs->ifbody->isErrorStatement()) ||
1761 (ifs->elsebody && ifs->elsebody->isErrorStatement()))
1762 {
1763 return setError();
1764 }
1765 result = ifs;
1766 }
1767
1768 void visit(ConditionalStatement *cs)
1769 {
1770 //printf("ConditionalStatement::semantic()\n");
1771
1772 // If we can short-circuit evaluate the if statement, don't do the
1773 // semantic analysis of the skipped code.
1774 // This feature allows a limited form of conditional compilation.
1775 if (cs->condition->include(sc, NULL))
1776 {
1777 DebugCondition *dc = cs->condition->isDebugCondition();
1778 if (dc)
1779 {
1780 sc = sc->push();
1781 sc->flags |= SCOPEdebug;
1782 cs->ifbody = semantic(cs->ifbody, sc);
1783 sc->pop();
1784 }
1785 else
1786 cs->ifbody = semantic(cs->ifbody, sc);
1787 result = cs->ifbody;
1788 }
1789 else
1790 {
1791 if (cs->elsebody)
1792 cs->elsebody = semantic(cs->elsebody, sc);
1793 result = cs->elsebody;
1794 }
1795 }
1796
1797 void visit(PragmaStatement *ps)
1798 {
1799 // Should be merged with PragmaDeclaration
1800 //printf("PragmaStatement::semantic() %s\n", ps->toChars());
1801 //printf("body = %p\n", ps->_body);
1802 if (ps->ident == Id::msg)
1803 {
1804 if (ps->args)
1805 {
1806 for (size_t i = 0; i < ps->args->dim; i++)
1807 {
1808 Expression *e = (*ps->args)[i];
1809
1810 sc = sc->startCTFE();
1811 e = semantic(e, sc);
1812 e = resolveProperties(sc, e);
1813 sc = sc->endCTFE();
1814 // pragma(msg) is allowed to contain types as well as expressions
1815 e = ctfeInterpretForPragmaMsg(e);
1816 if (e->op == TOKerror)
1817 {
1818 errorSupplemental(ps->loc, "while evaluating pragma(msg, %s)", (*ps->args)[i]->toChars());
1819 goto Lerror;
1820 }
1821 StringExp *se = e->toStringExp();
1822 if (se)
1823 {
1824 se = se->toUTF8(sc);
1825 fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
1826 }
1827 else
1828 fprintf(stderr, "%s", e->toChars());
1829 }
1830 fprintf(stderr, "\n");
1831 }
1832 }
1833 else if (ps->ident == Id::lib)
1834 {
1835 /* Should this be allowed?
1836 */
1837 ps->error("pragma(lib) not allowed as statement");
1838 goto Lerror;
1839 }
1840 else if (ps->ident == Id::startaddress)
1841 {
1842 if (!ps->args || ps->args->dim != 1)
1843 ps->error("function name expected for start address");
1844 else
1845 {
1846 Expression *e = (*ps->args)[0];
1847
1848 sc = sc->startCTFE();
1849 e = semantic(e, sc);
1850 e = resolveProperties(sc, e);
1851 sc = sc->endCTFE();
1852
1853 e = e->ctfeInterpret();
1854 (*ps->args)[0] = e;
1855 Dsymbol *sa = getDsymbol(e);
1856 if (!sa || !sa->isFuncDeclaration())
1857 {
1858 ps->error("function name expected for start address, not '%s'", e->toChars());
1859 goto Lerror;
1860 }
1861 if (ps->_body)
1862 {
1863 ps->_body = semantic(ps->_body, sc);
1864 if (ps->_body->isErrorStatement())
1865 {
1866 result = ps->_body;
1867 return;
1868 }
1869 }
1870 result = ps;
1871 return;
1872 }
1873 }
1874 else if (ps->ident == Id::Pinline)
1875 {
1876 PINLINE inlining = PINLINEdefault;
1877 if (!ps->args || ps->args->dim == 0)
1878 inlining = PINLINEdefault;
1879 else if (!ps->args || ps->args->dim != 1)
1880 {
1881 ps->error("boolean expression expected for pragma(inline)");
1882 goto Lerror;
1883 }
1884 else
1885 {
1886 Expression *e = (*ps->args)[0];
1887
1888 if (e->op != TOKint64 || !e->type->equals(Type::tbool))
1889 {
1890 ps->error("pragma(inline, true or false) expected, not %s", e->toChars());
1891 goto Lerror;
1892 }
1893
1894 if (e->isBool(true))
1895 inlining = PINLINEalways;
1896 else if (e->isBool(false))
1897 inlining = PINLINEnever;
1898
1899 FuncDeclaration *fd = sc->func;
1900 if (!fd)
1901 {
1902 ps->error("pragma(inline) is not inside a function");
1903 goto Lerror;
1904 }
1905 fd->inlining = inlining;
1906 }
1907 }
1908 else
1909 {
1910 ps->error("unrecognized pragma(%s)", ps->ident->toChars());
1911 goto Lerror;
1912 }
1913
1914 if (ps->_body)
1915 {
1916 ps->_body = semantic(ps->_body, sc);
1917 }
1918 result = ps->_body;
1919 return;
1920
1921 Lerror:
1922 return setError();
1923 }
1924
1925 void visit(StaticAssertStatement *s)
1926 {
1927 s->sa->semantic2(sc);
1928 }
1929
1930 void visit(SwitchStatement *ss)
1931 {
1932 //printf("SwitchStatement::semantic(%p)\n", ss);
1933 ss->tf = sc->tf;
1934 if (ss->cases)
1935 {
1936 result = ss; // already run
1937 return;
1938 }
1939 bool conditionError = false;
1940 ss->condition = semantic(ss->condition, sc);
1941 ss->condition = resolveProperties(sc, ss->condition);
1942
1943 Type *att = NULL;
1944 TypeEnum *te = NULL;
1945 while (ss->condition->op != TOKerror)
1946 {
1947 // preserve enum type for final switches
1948 if (ss->condition->type->ty == Tenum)
1949 te = (TypeEnum *)ss->condition->type;
1950 if (ss->condition->type->isString())
1951 {
1952 // If it's not an array, cast it to one
1953 if (ss->condition->type->ty != Tarray)
1954 {
1955 ss->condition = ss->condition->implicitCastTo(sc, ss->condition->type->nextOf()->arrayOf());
1956 }
1957 ss->condition->type = ss->condition->type->constOf();
1958 break;
1959 }
1960 ss->condition = integralPromotions(ss->condition, sc);
1961 if (ss->condition->op != TOKerror && ss->condition->type->isintegral())
1962 break;
1963
1964 AggregateDeclaration *ad = isAggregate(ss->condition->type);
1965 if (ad && ad->aliasthis && ss->condition->type != att)
1966 {
1967 if (!att && ss->condition->type->checkAliasThisRec())
1968 att = ss->condition->type;
1969 if (Expression *e = resolveAliasThis(sc, ss->condition, true))
1970 {
1971 ss->condition = e;
1972 continue;
1973 }
1974 }
1975
1976 if (ss->condition->op != TOKerror)
1977 {
1978 ss->error("'%s' must be of integral or string type, it is a %s",
1979 ss->condition->toChars(), ss->condition->type->toChars());
1980 conditionError = true;
1981 break;
1982 }
1983 }
1984 if (checkNonAssignmentArrayOp(ss->condition))
1985 ss->condition = new ErrorExp();
1986 ss->condition = ss->condition->optimize(WANTvalue);
1987 ss->condition = checkGC(sc, ss->condition);
1988 if (ss->condition->op == TOKerror)
1989 conditionError = true;
1990
1991 bool needswitcherror = false;
1992
1993 ss->lastVar = sc->lastVar;
1994
1995 sc = sc->push();
1996 sc->sbreak = ss;
1997 sc->sw = ss;
1998
1999 ss->cases = new CaseStatements();
2000 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2001 ss->_body = semantic(ss->_body, sc);
2002 sc->noctor--;
2003
2004 if (conditionError || ss->_body->isErrorStatement())
2005 goto Lerror;
2006
2007 // Resolve any goto case's with exp
2008 for (size_t i = 0; i < ss->gotoCases.dim; i++)
2009 {
2010 GotoCaseStatement *gcs = ss->gotoCases[i];
2011
2012 if (!gcs->exp)
2013 {
2014 gcs->error("no case statement following goto case;");
2015 goto Lerror;
2016 }
2017
2018 for (Scope *scx = sc; scx; scx = scx->enclosing)
2019 {
2020 if (!scx->sw)
2021 continue;
2022 for (size_t j = 0; j < scx->sw->cases->dim; j++)
2023 {
2024 CaseStatement *cs = (*scx->sw->cases)[j];
2025
2026 if (cs->exp->equals(gcs->exp))
2027 {
2028 gcs->cs = cs;
2029 goto Lfoundcase;
2030 }
2031 }
2032 }
2033 gcs->error("case %s not found", gcs->exp->toChars());
2034 goto Lerror;
2035
2036 Lfoundcase:
2037 ;
2038 }
2039
2040 if (ss->isFinal)
2041 {
2042 Type *t = ss->condition->type;
2043 Dsymbol *ds;
2044 EnumDeclaration *ed = NULL;
2045 if (t && ((ds = t->toDsymbol(sc)) != NULL))
2046 ed = ds->isEnumDeclaration(); // typedef'ed enum
2047 if (!ed && te && ((ds = te->toDsymbol(sc)) != NULL))
2048 ed = ds->isEnumDeclaration();
2049 if (ed)
2050 {
2051 size_t dim = ed->members->dim;
2052 for (size_t i = 0; i < dim; i++)
2053 {
2054 EnumMember *em = (*ed->members)[i]->isEnumMember();
2055 if (em)
2056 {
2057 for (size_t j = 0; j < ss->cases->dim; j++)
2058 {
2059 CaseStatement *cs = (*ss->cases)[j];
2060 if (cs->exp->equals(em->value()) ||
2061 (!cs->exp->type->isString() && !em->value()->type->isString() &&
2062 cs->exp->toInteger() == em->value()->toInteger()))
2063 goto L1;
2064 }
2065 ss->error("enum member %s not represented in final switch", em->toChars());
2066 goto Lerror;
2067 }
2068 L1:
2069 ;
2070 }
2071 }
2072 else
2073 needswitcherror = true;
2074 }
2075
2076 if (!sc->sw->sdefault && (!ss->isFinal || needswitcherror || global.params.useAssert))
2077 {
2078 ss->hasNoDefault = 1;
2079
2080 if (!ss->isFinal && !ss->_body->isErrorStatement())
2081 ss->error("switch statement without a default; use 'final switch' or add 'default: assert(0);' or add 'default: break;'");
2082
2083 // Generate runtime error if the default is hit
2084 Statements *a = new Statements();
2085 CompoundStatement *cs;
2086 Statement *s;
2087
2088 if (global.params.useSwitchError &&
2089 global.params.checkAction != CHECKACTION_halt)
2090 {
2091 if (global.params.checkAction == CHECKACTION_C)
2092 {
2093 /* Rewrite as an assert(0) and let e2ir generate
2094 * the call to the C assert failure function
2095 */
2096 s = new ExpStatement(ss->loc, new AssertExp(ss->loc, new IntegerExp(ss->loc, 0, Type::tint32)));
2097 }
2098 else
2099 s = new SwitchErrorStatement(ss->loc);
2100 }
2101 else
2102 s = new ExpStatement(ss->loc, new HaltExp(ss->loc));
2103
2104 a->reserve(2);
2105 sc->sw->sdefault = new DefaultStatement(ss->loc, s);
2106 a->push(ss->_body);
2107 if (blockExit(ss->_body, sc->func, false) & BEfallthru)
2108 a->push(new BreakStatement(Loc(), NULL));
2109 a->push(sc->sw->sdefault);
2110 cs = new CompoundStatement(ss->loc, a);
2111 ss->_body = cs;
2112 }
2113
2114 if (ss->checkLabel())
2115 goto Lerror;
2116
2117 sc->pop();
2118 result = ss;
2119 return;
2120
2121 Lerror:
2122 sc->pop();
2123 result = new ErrorStatement();
2124 }
2125
2126 void visit(CaseStatement *cs)
2127 {
2128 SwitchStatement *sw = sc->sw;
2129 bool errors = false;
2130
2131 //printf("CaseStatement::semantic() %s\n", cs->toChars());
2132 sc = sc->startCTFE();
2133 cs->exp = semantic(cs->exp, sc);
2134 cs->exp = resolveProperties(sc, cs->exp);
2135 sc = sc->endCTFE();
2136 if (sw)
2137 {
2138 cs->exp = cs->exp->implicitCastTo(sc, sw->condition->type);
2139 cs->exp = cs->exp->optimize(WANTvalue | WANTexpand);
2140
2141 Expression *e = cs->exp;
2142 // Remove all the casts the user and/or implicitCastTo may introduce
2143 // otherwise we'd sometimes fail the check below.
2144 while (e->op == TOKcast)
2145 e = ((CastExp *)e)->e1;
2146
2147 /* This is where variables are allowed as case expressions.
2148 */
2149 if (e->op == TOKvar)
2150 {
2151 VarExp *ve = (VarExp *)e;
2152 VarDeclaration *v = ve->var->isVarDeclaration();
2153 Type *t = cs->exp->type->toBasetype();
2154 if (v && (t->isintegral() || t->ty == Tclass))
2155 {
2156 /* Flag that we need to do special code generation
2157 * for this, i.e. generate a sequence of if-then-else
2158 */
2159 sw->hasVars = 1;
2160
2161 /* TODO check if v can be uninitialized at that point.
2162 */
2163 if (!v->isConst() && !v->isImmutable())
2164 {
2165 cs->deprecation("case variables have to be const or immutable");
2166 }
2167
2168 if (sw->isFinal)
2169 {
2170 cs->error("case variables not allowed in final switch statements");
2171 errors = true;
2172 }
2173
2174 /* Also check if the VarExp is declared in a scope outside of this one.
2175 * 'scx' is set to the scope of the switch statement.
2176 */
2177 for (Scope *scx = sc; scx; scx = scx->enclosing)
2178 {
2179 if (scx->enclosing && scx->enclosing->sw == sw)
2180 continue;
2181 assert(scx->sw == sw);
2182
2183 if (!scx->search(cs->exp->loc, v->ident, NULL))
2184 {
2185 cs->error("case variable `%s` declared at %s cannot be declared in switch body",
2186 v->toChars(), v->loc.toChars());
2187 errors = true;
2188 }
2189 break;
2190 }
2191 goto L1;
2192 }
2193 }
2194 else
2195 cs->exp = cs->exp->ctfeInterpret();
2196
2197 if (StringExp *se = cs->exp->toStringExp())
2198 cs->exp = se;
2199 else if (cs->exp->op != TOKint64 && cs->exp->op != TOKerror)
2200 {
2201 cs->error("case must be a string or an integral constant, not %s", cs->exp->toChars());
2202 errors = true;
2203 }
2204
2205 L1:
2206 for (size_t i = 0; i < sw->cases->dim; i++)
2207 {
2208 CaseStatement *cs2 = (*sw->cases)[i];
2209
2210 //printf("comparing '%s' with '%s'\n", cs->exp->toChars(), cs2->exp->toChars());
2211 if (cs2->exp->equals(cs->exp))
2212 {
2213 cs->error("duplicate case %s in switch statement", cs->exp->toChars());
2214 errors = true;
2215 break;
2216 }
2217 }
2218
2219 sw->cases->push(cs);
2220
2221 // Resolve any goto case's with no exp to this case statement
2222 for (size_t i = 0; i < sw->gotoCases.dim; )
2223 {
2224 GotoCaseStatement *gcs = sw->gotoCases[i];
2225
2226 if (!gcs->exp)
2227 {
2228 gcs->cs = cs;
2229 sw->gotoCases.remove(i); // remove from array
2230 continue;
2231 }
2232 i++;
2233 }
2234
2235 if (sc->sw->tf != sc->tf)
2236 {
2237 cs->error("switch and case are in different finally blocks");
2238 errors = true;
2239 }
2240 }
2241 else
2242 {
2243 cs->error("case not in switch statement");
2244 errors = true;
2245 }
2246 cs->statement = semantic(cs->statement, sc);
2247 if (cs->statement->isErrorStatement())
2248 {
2249 result = cs->statement;
2250 return;
2251 }
2252 if (errors || cs->exp->op == TOKerror)
2253 return setError();
2254
2255 cs->lastVar = sc->lastVar;
2256 result = cs;
2257 }
2258
2259 void visit(CaseRangeStatement *crs)
2260 {
2261 SwitchStatement *sw = sc->sw;
2262 if (sw == NULL)
2263 {
2264 crs->error("case range not in switch statement");
2265 return setError();
2266 }
2267
2268 //printf("CaseRangeStatement::semantic() %s\n", toChars());
2269 bool errors = false;
2270 if (sw->isFinal)
2271 {
2272 crs->error("case ranges not allowed in final switch");
2273 errors = true;
2274 }
2275
2276 sc = sc->startCTFE();
2277 crs->first = semantic(crs->first, sc);
2278 crs->first = resolveProperties(sc, crs->first);
2279 sc = sc->endCTFE();
2280 crs->first = crs->first->implicitCastTo(sc, sw->condition->type);
2281 crs->first = crs->first->ctfeInterpret();
2282
2283 sc = sc->startCTFE();
2284 crs->last = semantic(crs->last, sc);
2285 crs->last = resolveProperties(sc, crs->last);
2286 sc = sc->endCTFE();
2287 crs->last = crs->last->implicitCastTo(sc, sw->condition->type);
2288 crs->last = crs->last->ctfeInterpret();
2289
2290 if (crs->first->op == TOKerror || crs->last->op == TOKerror || errors)
2291 {
2292 if (crs->statement)
2293 semantic(crs->statement, sc);
2294 return setError();
2295 }
2296
2297 uinteger_t fval = crs->first->toInteger();
2298 uinteger_t lval = crs->last->toInteger();
2299
2300
2301 if ( (crs->first->type->isunsigned() && fval > lval) ||
2302 (!crs->first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval))
2303 {
2304 crs->error("first case %s is greater than last case %s",
2305 crs->first->toChars(), crs->last->toChars());
2306 errors = true;
2307 lval = fval;
2308 }
2309
2310 if (lval - fval > 256)
2311 {
2312 crs->error("had %llu cases which is more than 256 cases in case range", lval - fval);
2313 errors = true;
2314 lval = fval + 256;
2315 }
2316
2317 if (errors)
2318 return setError();
2319
2320 /* This works by replacing the CaseRange with an array of Case's.
2321 *
2322 * case a: .. case b: s;
2323 * =>
2324 * case a:
2325 * [...]
2326 * case b:
2327 * s;
2328 */
2329
2330 Statements *statements = new Statements();
2331 for (uinteger_t i = fval; i != lval + 1; i++)
2332 {
2333 Statement *s = crs->statement;
2334 if (i != lval) // if not last case
2335 s = new ExpStatement(crs->loc, (Expression *)NULL);
2336 Expression *e = new IntegerExp(crs->loc, i, crs->first->type);
2337 Statement *cs = new CaseStatement(crs->loc, e, s);
2338 statements->push(cs);
2339 }
2340 Statement *s = new CompoundStatement(crs->loc, statements);
2341 s = semantic(s, sc);
2342 result = s;
2343 }
2344
2345 void visit(DefaultStatement *ds)
2346 {
2347 //printf("DefaultStatement::semantic()\n");
2348 bool errors = false;
2349 if (sc->sw)
2350 {
2351 if (sc->sw->sdefault)
2352 {
2353 ds->error("switch statement already has a default");
2354 errors = true;
2355 }
2356 sc->sw->sdefault = ds;
2357
2358 if (sc->sw->tf != sc->tf)
2359 {
2360 ds->error("switch and default are in different finally blocks");
2361 errors = true;
2362 }
2363 if (sc->sw->isFinal)
2364 {
2365 ds->error("default statement not allowed in final switch statement");
2366 errors = true;
2367 }
2368 }
2369 else
2370 {
2371 ds->error("default not in switch statement");
2372 errors = true;
2373 }
2374 ds->statement = semantic(ds->statement, sc);
2375 if (errors || ds->statement->isErrorStatement())
2376 return setError();
2377
2378 ds->lastVar = sc->lastVar;
2379 result = ds;
2380 }
2381
2382 void visit(GotoDefaultStatement *gds)
2383 {
2384 gds->sw = sc->sw;
2385 if (!gds->sw)
2386 {
2387 gds->error("goto default not in switch statement");
2388 return setError();
2389 }
2390 if (gds->sw->isFinal)
2391 {
2392 gds->error("goto default not allowed in final switch statement");
2393 return setError();
2394 }
2395 result = gds;
2396 }
2397
2398 void visit(GotoCaseStatement *gcs)
2399 {
2400 if (!sc->sw)
2401 {
2402 gcs->error("goto case not in switch statement");
2403 return setError();
2404 }
2405
2406 if (gcs->exp)
2407 {
2408 gcs->exp = semantic(gcs->exp, sc);
2409 gcs->exp = gcs->exp->implicitCastTo(sc, sc->sw->condition->type);
2410 gcs->exp = gcs->exp->optimize(WANTvalue);
2411 if (gcs->exp->op == TOKerror)
2412 return setError();
2413 }
2414
2415 sc->sw->gotoCases.push(gcs);
2416 result = gcs;
2417 }
2418
2419 void visit(ReturnStatement *rs)
2420 {
2421 //printf("ReturnStatement::semantic() %s\n", toChars());
2422
2423 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2424
2425 if (fd->fes)
2426 fd = fd->fes->func; // fd is now function enclosing foreach
2427
2428 TypeFunction *tf = (TypeFunction *)fd->type;
2429 assert(tf->ty == Tfunction);
2430
2431 if (rs->exp && rs->exp->op == TOKvar && ((VarExp *)rs->exp)->var == fd->vresult)
2432 {
2433 // return vresult;
2434 if (sc->fes)
2435 {
2436 assert(rs->caseDim == 0);
2437 sc->fes->cases->push(rs);
2438 result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
2439 return;
2440 }
2441 if (fd->returnLabel)
2442 {
2443 GotoStatement *gs = new GotoStatement(rs->loc, Id::returnLabel);
2444 gs->label = fd->returnLabel;
2445 result = gs;
2446 return;
2447 }
2448
2449 if (!fd->returns)
2450 fd->returns = new ReturnStatements();
2451 fd->returns->push(rs);
2452 result = rs;
2453 return;
2454 }
2455
2456 Type *tret = tf->next;
2457 Type *tbret = tret ? tret->toBasetype() : NULL;
2458
2459 bool inferRef = (tf->isref && (fd->storage_class & STCauto));
2460 Expression *e0 = NULL;
2461
2462 bool errors = false;
2463 if (sc->flags & SCOPEcontract)
2464 {
2465 rs->error("return statements cannot be in contracts");
2466 errors = true;
2467 }
2468 if (sc->os && sc->os->tok != TOKon_scope_failure)
2469 {
2470 rs->error("return statements cannot be in %s bodies", Token::toChars(sc->os->tok));
2471 errors = true;
2472 }
2473 if (sc->tf)
2474 {
2475 rs->error("return statements cannot be in finally bodies");
2476 errors = true;
2477 }
2478
2479 if (fd->isCtorDeclaration())
2480 {
2481 if (rs->exp)
2482 {
2483 rs->error("cannot return expression from constructor");
2484 errors = true;
2485 }
2486
2487 // Constructors implicitly do:
2488 // return this;
2489 rs->exp = new ThisExp(Loc());
2490 rs->exp->type = tret;
2491 }
2492 else if (rs->exp)
2493 {
2494 fd->hasReturnExp |= (fd->hasReturnExp & 1 ? 16 : 1);
2495
2496 FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration();
2497 if (tret)
2498 rs->exp = inferType(rs->exp, tret);
2499 else if (fld && fld->treq)
2500 rs->exp = inferType(rs->exp, fld->treq->nextOf()->nextOf());
2501 rs->exp = semantic(rs->exp, sc);
2502
2503 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2504 if (rs->exp->op == TOKtype)
2505 rs->exp = resolveAliasThis(sc, rs->exp);
2506
2507 rs->exp = resolveProperties(sc, rs->exp);
2508 if (rs->exp->checkType())
2509 rs->exp = new ErrorExp();
2510 if (FuncDeclaration *f = isFuncAddress(rs->exp))
2511 {
2512 if (fd->inferRetType && f->checkForwardRef(rs->exp->loc))
2513 rs->exp = new ErrorExp();
2514 }
2515 if (checkNonAssignmentArrayOp(rs->exp))
2516 rs->exp = new ErrorExp();
2517
2518 // Extract side-effect part
2519 rs->exp = Expression::extractLast(rs->exp, &e0);
2520 if (rs->exp->op == TOKcall)
2521 rs->exp = valueNoDtor(rs->exp);
2522
2523 if (e0)
2524 e0 = e0->optimize(WANTvalue);
2525
2526 /* Void-return function can have void typed expression
2527 * on return statement.
2528 */
2529 if ((tbret && tbret->ty == Tvoid) || rs->exp->type->ty == Tvoid)
2530 {
2531 if (rs->exp->type->ty != Tvoid)
2532 {
2533 rs->error("cannot return non-void from void function");
2534 errors = true;
2535
2536 rs->exp = new CastExp(rs->loc, rs->exp, Type::tvoid);
2537 rs->exp = semantic(rs->exp, sc);
2538 }
2539
2540 /* Replace:
2541 * return exp;
2542 * with:
2543 * exp; return;
2544 */
2545 e0 = Expression::combine(e0, rs->exp);
2546 rs->exp = NULL;
2547 }
2548 if (e0)
2549 e0 = checkGC(sc, e0);
2550 }
2551
2552 if (rs->exp)
2553 {
2554 if (fd->inferRetType) // infer return type
2555 {
2556 if (!tret)
2557 {
2558 tf->next = rs->exp->type;
2559 }
2560 else if (tret->ty != Terror && !rs->exp->type->equals(tret))
2561 {
2562 int m1 = rs->exp->type->implicitConvTo(tret);
2563 int m2 = tret->implicitConvTo(rs->exp->type);
2564 //printf("exp->type = %s m2<-->m1 tret %s\n", rs->exp->type->toChars(), tret->toChars());
2565 //printf("m1 = %d, m2 = %d\n", m1, m2);
2566
2567 if (m1 && m2)
2568 ;
2569 else if (!m1 && m2)
2570 tf->next = rs->exp->type;
2571 else if (m1 && !m2)
2572 ;
2573 else if (rs->exp->op != TOKerror)
2574 {
2575 rs->error("mismatched function return type inference of %s and %s",
2576 rs->exp->type->toChars(), tret->toChars());
2577 errors = true;
2578 tf->next = Type::terror;
2579 }
2580 }
2581
2582 tret = tf->next;
2583 tbret = tret->toBasetype();
2584 }
2585
2586 if (inferRef) // deduce 'auto ref'
2587 {
2588 /* Determine "refness" of function return:
2589 * if it's an lvalue, return by ref, else return by value
2590 */
2591 if (rs->exp->isLvalue())
2592 {
2593 /* May return by ref
2594 */
2595 if (checkReturnEscapeRef(sc, rs->exp, true))
2596 tf->isref = false; // return by value
2597 }
2598 else
2599 tf->isref = false; // return by value
2600
2601 /* The "refness" is determined by all of return statements.
2602 * This means:
2603 * return 3; return x; // ok, x can be a value
2604 * return x; return 3; // ok, x can be a value
2605 */
2606 }
2607
2608 // handle NRVO
2609 if (fd->nrvo_can && rs->exp->op == TOKvar)
2610 {
2611 VarExp *ve = (VarExp *)rs->exp;
2612 VarDeclaration *v = ve->var->isVarDeclaration();
2613
2614 if (tf->isref)
2615 {
2616 // Function returns a reference
2617 if (!inferRef)
2618 fd->nrvo_can = 0;
2619 }
2620 else if (!v || v->isOut() || v->isRef())
2621 fd->nrvo_can = 0;
2622 else if (fd->nrvo_var == NULL)
2623 {
2624 if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
2625 {
2626 //printf("Setting nrvo to %s\n", v->toChars());
2627 fd->nrvo_var = v;
2628 }
2629 else
2630 fd->nrvo_can = 0;
2631 }
2632 else if (fd->nrvo_var != v)
2633 fd->nrvo_can = 0;
2634 }
2635 else //if (!exp->isLvalue()) // keep NRVO-ability
2636 fd->nrvo_can = 0;
2637 }
2638 else
2639 {
2640 // handle NRVO
2641 fd->nrvo_can = 0;
2642
2643 // infer return type
2644 if (fd->inferRetType)
2645 {
2646 if (tf->next && tf->next->ty != Tvoid)
2647 {
2648 if (tf->next->ty != Terror)
2649 {
2650 rs->error("mismatched function return type inference of void and %s",
2651 tf->next->toChars());
2652 }
2653 errors = true;
2654 tf->next = Type::terror;
2655 }
2656 else
2657 tf->next = Type::tvoid;
2658
2659 tret = tf->next;
2660 tbret = tret->toBasetype();
2661 }
2662
2663 if (inferRef) // deduce 'auto ref'
2664 tf->isref = false;
2665
2666 if (tbret->ty != Tvoid) // if non-void return
2667 {
2668 if (tbret->ty != Terror)
2669 rs->error("return expression expected");
2670 errors = true;
2671 }
2672 else if (fd->isMain())
2673 {
2674 // main() returns 0, even if it returns void
2675 rs->exp = new IntegerExp(0);
2676 }
2677 }
2678
2679 // If any branches have called a ctor, but this branch hasn't, it's an error
2680 if (sc->callSuper & CSXany_ctor &&
2681 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
2682 {
2683 rs->error("return without calling constructor");
2684 errors = true;
2685 }
2686 sc->callSuper |= CSXreturn;
2687 if (sc->fieldinit)
2688 {
2689 AggregateDeclaration *ad = fd->isMember2();
2690 assert(ad);
2691 size_t dim = sc->fieldinit_dim;
2692 for (size_t i = 0; i < dim; i++)
2693 {
2694 VarDeclaration *v = ad->fields[i];
2695 bool mustInit = (v->storage_class & STCnodefaultctor ||
2696 v->type->needsNested());
2697 if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor))
2698 {
2699 rs->error("an earlier return statement skips field %s initialization", v->toChars());
2700 errors = true;
2701 }
2702 sc->fieldinit[i] |= CSXreturn;
2703 }
2704 }
2705
2706 if (errors)
2707 return setError();
2708
2709 if (sc->fes)
2710 {
2711 if (!rs->exp)
2712 {
2713 // Send out "case receiver" statement to the foreach.
2714 // return exp;
2715 Statement *s = new ReturnStatement(Loc(), rs->exp);
2716 sc->fes->cases->push(s);
2717
2718 // Immediately rewrite "this" return statement as:
2719 // return cases->dim+1;
2720 rs->exp = new IntegerExp(sc->fes->cases->dim + 1);
2721 if (e0)
2722 {
2723 result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
2724 return;
2725 }
2726 result = rs;
2727 return;
2728 }
2729 else
2730 {
2731 fd->buildResultVar(NULL, rs->exp->type);
2732 bool r = fd->vresult->checkNestedReference(sc, Loc());
2733 assert(!r); // vresult should be always accessible
2734
2735 // Send out "case receiver" statement to the foreach.
2736 // return vresult;
2737 Statement *s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult));
2738 sc->fes->cases->push(s);
2739
2740 // Save receiver index for the later rewriting from:
2741 // return exp;
2742 // to:
2743 // vresult = exp; retrun caseDim;
2744 rs->caseDim = sc->fes->cases->dim + 1;
2745 }
2746 }
2747 if (rs->exp)
2748 {
2749 if (!fd->returns)
2750 fd->returns = new ReturnStatements();
2751 fd->returns->push(rs);
2752 }
2753 if (e0)
2754 {
2755 result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
2756 return;
2757 }
2758 result = rs;
2759 }
2760
2761 void visit(BreakStatement *bs)
2762 {
2763 //printf("BreakStatement::semantic()\n");
2764 // If:
2765 // break Identifier;
2766 if (bs->ident)
2767 {
2768 bs->ident = fixupLabelName(sc, bs->ident);
2769
2770 FuncDeclaration *thisfunc = sc->func;
2771
2772 for (Scope *scx = sc; scx; scx = scx->enclosing)
2773 {
2774 if (scx->func != thisfunc) // if in enclosing function
2775 {
2776 if (sc->fes) // if this is the body of a foreach
2777 {
2778 /* Post this statement to the fes, and replace
2779 * it with a return value that caller will put into
2780 * a switch. Caller will figure out where the break
2781 * label actually is.
2782 * Case numbers start with 2, not 0, as 0 is continue
2783 * and 1 is break.
2784 */
2785 sc->fes->cases->push(bs);
2786 result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
2787 return;
2788 }
2789 break; // can't break to it
2790 }
2791
2792 LabelStatement *ls = scx->slabel;
2793 if (ls && ls->ident == bs->ident)
2794 {
2795 Statement *s = ls->statement;
2796
2797 if (!s || !s->hasBreak())
2798 bs->error("label '%s' has no break", bs->ident->toChars());
2799 else if (ls->tf != sc->tf)
2800 bs->error("cannot break out of finally block");
2801 else
2802 {
2803 ls->breaks = true;
2804 result = bs;
2805 return;
2806 }
2807 return setError();
2808 }
2809 }
2810 bs->error("enclosing label '%s' for break not found", bs->ident->toChars());
2811 return setError();
2812 }
2813 else if (!sc->sbreak)
2814 {
2815 if (sc->os && sc->os->tok != TOKon_scope_failure)
2816 {
2817 bs->error("break is not inside %s bodies", Token::toChars(sc->os->tok));
2818 }
2819 else if (sc->fes)
2820 {
2821 // Replace break; with return 1;
2822 result = new ReturnStatement(Loc(), new IntegerExp(1));
2823 return;
2824 }
2825 else
2826 bs->error("break is not inside a loop or switch");
2827 return setError();
2828 }
2829 result = bs;
2830 }
2831
2832 void visit(ContinueStatement *cs)
2833 {
2834 //printf("ContinueStatement::semantic() %p\n", cs);
2835 if (cs->ident)
2836 {
2837 cs->ident = fixupLabelName(sc, cs->ident);
2838
2839 Scope *scx;
2840 FuncDeclaration *thisfunc = sc->func;
2841
2842 for (scx = sc; scx; scx = scx->enclosing)
2843 {
2844 LabelStatement *ls;
2845
2846 if (scx->func != thisfunc) // if in enclosing function
2847 {
2848 if (sc->fes) // if this is the body of a foreach
2849 {
2850 for (; scx; scx = scx->enclosing)
2851 {
2852 ls = scx->slabel;
2853 if (ls && ls->ident == cs->ident && ls->statement == sc->fes)
2854 {
2855 // Replace continue ident; with return 0;
2856 result = new ReturnStatement(Loc(), new IntegerExp(0));
2857 return;
2858 }
2859 }
2860
2861 /* Post this statement to the fes, and replace
2862 * it with a return value that caller will put into
2863 * a switch. Caller will figure out where the break
2864 * label actually is.
2865 * Case numbers start with 2, not 0, as 0 is continue
2866 * and 1 is break.
2867 */
2868 sc->fes->cases->push(cs);
2869 result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
2870 return;
2871 }
2872 break; // can't continue to it
2873 }
2874
2875 ls = scx->slabel;
2876 if (ls && ls->ident == cs->ident)
2877 {
2878 Statement *s = ls->statement;
2879
2880 if (!s || !s->hasContinue())
2881 cs->error("label '%s' has no continue", cs->ident->toChars());
2882 else if (ls->tf != sc->tf)
2883 cs->error("cannot continue out of finally block");
2884 else
2885 {
2886 result = cs;
2887 return;
2888 }
2889 return setError();
2890 }
2891 }
2892 cs->error("enclosing label '%s' for continue not found", cs->ident->toChars());
2893 return setError();
2894 }
2895 else if (!sc->scontinue)
2896 {
2897 if (sc->os && sc->os->tok != TOKon_scope_failure)
2898 {
2899 cs->error("continue is not inside %s bodies", Token::toChars(sc->os->tok));
2900 }
2901 else if (sc->fes)
2902 {
2903 // Replace continue; with return 0;
2904 result = new ReturnStatement(Loc(), new IntegerExp(0));
2905 return;
2906 }
2907 else
2908 cs->error("continue is not inside a loop");
2909 return setError();
2910 }
2911 result = cs;
2912 }
2913
2914 void visit(SynchronizedStatement *ss)
2915 {
2916 if (ss->exp)
2917 {
2918 ss->exp = semantic(ss->exp, sc);
2919 ss->exp = resolveProperties(sc, ss->exp);
2920 ss->exp = ss->exp->optimize(WANTvalue);
2921 ss->exp = checkGC(sc, ss->exp);
2922 if (ss->exp->op == TOKerror)
2923 goto Lbody;
2924 ClassDeclaration *cd = ss->exp->type->isClassHandle();
2925 if (!cd)
2926 {
2927 ss->error("can only synchronize on class objects, not '%s'", ss->exp->type->toChars());
2928 return setError();
2929 }
2930 else if (cd->isInterfaceDeclaration())
2931 {
2932 /* Cast the interface to an object, as the object has the monitor,
2933 * not the interface.
2934 */
2935 if (!ClassDeclaration::object)
2936 {
2937 ss->error("missing or corrupt object.d");
2938 fatal();
2939 }
2940
2941 Type *t = ClassDeclaration::object->type;
2942 t = t->semantic(Loc(), sc)->toBasetype();
2943 assert(t->ty == Tclass);
2944
2945 ss->exp = new CastExp(ss->loc, ss->exp, t);
2946 ss->exp = semantic(ss->exp, sc);
2947 }
2948
2949 /* Rewrite as:
2950 * auto tmp = exp;
2951 * _d_monitorenter(tmp);
2952 * try { body } finally { _d_monitorexit(tmp); }
2953 */
2954 VarDeclaration *tmp = copyToTemp(0, "__sync", ss->exp);
2955
2956 Statements *cs = new Statements();
2957 cs->push(new ExpStatement(ss->loc, tmp));
2958
2959 Parameters* args = new Parameters;
2960 args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL));
2961
2962 FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
2963 Expression *e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp));
2964 e->type = Type::tvoid; // do not run semantic on e
2965 cs->push(new ExpStatement(ss->loc, e));
2966
2967 FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
2968 e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), new VarExp(ss->loc, tmp));
2969 e->type = Type::tvoid; // do not run semantic on e
2970 Statement *s = new ExpStatement(ss->loc, e);
2971 s = new TryFinallyStatement(ss->loc, ss->_body, s);
2972 cs->push(s);
2973
2974 s = new CompoundStatement(ss->loc, cs);
2975 result = semantic(s, sc);
2976 return;
2977 }
2978 else
2979 {
2980 /* Generate our own critical section, then rewrite as:
2981 * __gshared byte[CriticalSection.sizeof] critsec;
2982 * _d_criticalenter(critsec.ptr);
2983 * try { body } finally { _d_criticalexit(critsec.ptr); }
2984 */
2985 Identifier *id = Identifier::generateId("__critsec");
2986 Type *t = Type::tint8->sarrayOf(Target::ptrsize + Target::critsecsize());
2987 VarDeclaration *tmp = new VarDeclaration(ss->loc, t, id, NULL);
2988 tmp->storage_class |= STCtemp | STCgshared | STCstatic;
2989
2990 Statements *cs = new Statements();
2991 cs->push(new ExpStatement(ss->loc, tmp));
2992
2993 /* This is just a dummy variable for "goto skips declaration" error.
2994 * Backend optimizer could remove this unused variable.
2995 */
2996 VarDeclaration *v = new VarDeclaration(ss->loc, Type::tvoidptr, Identifier::generateId("__sync"), NULL);
2997 v->semantic(sc);
2998 cs->push(new ExpStatement(ss->loc, v));
2999
3000 Parameters* args = new Parameters;
3001 args->push(new Parameter(0, t->pointerTo(), NULL, NULL));
3002
3003 FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
3004 Expression *e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
3005 e = semantic(e, sc);
3006 e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
3007 e->type = Type::tvoid; // do not run semantic on e
3008 cs->push(new ExpStatement(ss->loc, e));
3009
3010 FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
3011 e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
3012 e = semantic(e, sc);
3013 e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
3014 e->type = Type::tvoid; // do not run semantic on e
3015 Statement *s = new ExpStatement(ss->loc, e);
3016 s = new TryFinallyStatement(ss->loc, ss->_body, s);
3017 cs->push(s);
3018
3019 s = new CompoundStatement(ss->loc, cs);
3020 result = semantic(s, sc);
3021 return;
3022 }
3023 Lbody:
3024 if (ss->_body)
3025 ss->_body = semantic(ss->_body, sc);
3026 if (ss->_body && ss->_body->isErrorStatement())
3027 {
3028 result = ss->_body;
3029 return;
3030 }
3031 result = ss;
3032 }
3033
3034 void visit(WithStatement *ws)
3035 {
3036 ScopeDsymbol *sym;
3037 Initializer *init;
3038
3039 //printf("WithStatement::semantic()\n");
3040 ws->exp = semantic(ws->exp, sc);
3041 ws->exp = resolveProperties(sc, ws->exp);
3042 ws->exp = ws->exp->optimize(WANTvalue);
3043 ws->exp = checkGC(sc, ws->exp);
3044 if (ws->exp->op == TOKerror)
3045 return setError();
3046 if (ws->exp->op == TOKscope)
3047 {
3048 sym = new WithScopeSymbol(ws);
3049 sym->parent = sc->scopesym;
3050 sym->endlinnum = ws->endloc.linnum;
3051 }
3052 else if (ws->exp->op == TOKtype)
3053 {
3054 Dsymbol *s = ((TypeExp *)ws->exp)->type->toDsymbol(sc);
3055 if (!s || !s->isScopeDsymbol())
3056 {
3057 ws->error("with type %s has no members", ws->exp->toChars());
3058 return setError();
3059 }
3060 sym = new WithScopeSymbol(ws);
3061 sym->parent = sc->scopesym;
3062 sym->endlinnum = ws->endloc.linnum;
3063 }
3064 else
3065 {
3066 Type *t = ws->exp->type->toBasetype();
3067
3068 Expression *olde = ws->exp;
3069 if (t->ty == Tpointer)
3070 {
3071 ws->exp = new PtrExp(ws->loc, ws->exp);
3072 ws->exp = semantic(ws->exp, sc);
3073 t = ws->exp->type->toBasetype();
3074 }
3075
3076 assert(t);
3077 t = t->toBasetype();
3078 if (t->isClassHandle())
3079 {
3080 init = new ExpInitializer(ws->loc, ws->exp);
3081 ws->wthis = new VarDeclaration(ws->loc, ws->exp->type, Id::withSym, init);
3082 ws->wthis->semantic(sc);
3083
3084 sym = new WithScopeSymbol(ws);
3085 sym->parent = sc->scopesym;
3086 sym->endlinnum = ws->endloc.linnum;
3087 }
3088 else if (t->ty == Tstruct)
3089 {
3090 if (!ws->exp->isLvalue())
3091 {
3092 /* Re-write to
3093 * {
3094 * auto __withtmp = exp
3095 * with(__withtmp)
3096 * {
3097 * ...
3098 * }
3099 * }
3100 */
3101 VarDeclaration *tmp = copyToTemp(0, "__withtmp", ws->exp);
3102 ExpStatement *es = new ExpStatement(ws->loc, tmp);
3103 ws->exp = new VarExp(ws->loc, tmp);
3104 Statement *ss = new ScopeStatement(ws->loc, new CompoundStatement(ws->loc, es, ws), ws->endloc);
3105 result = semantic(ss, sc);
3106 return;
3107 }
3108 Expression *e = ws->exp->addressOf();
3109 init = new ExpInitializer(ws->loc, e);
3110 ws->wthis = new VarDeclaration(ws->loc, e->type, Id::withSym, init);
3111 ws->wthis->semantic(sc);
3112 sym = new WithScopeSymbol(ws);
3113 // Need to set the scope to make use of resolveAliasThis
3114 sym->setScope(sc);
3115 sym->parent = sc->scopesym;
3116 sym->endlinnum = ws->endloc.linnum;
3117 }
3118 else
3119 {
3120 ws->error("with expressions must be aggregate types or pointers to them, not '%s'", olde->type->toChars());
3121 return setError();
3122 }
3123 }
3124
3125 if (ws->_body)
3126 {
3127 sym->_scope = sc;
3128 sc = sc->push(sym);
3129 sc->insert(sym);
3130 ws->_body = semantic(ws->_body, sc);
3131 sc->pop();
3132 if (ws->_body && ws->_body->isErrorStatement())
3133 {
3134 result = ws->_body;
3135 return;
3136 }
3137 }
3138
3139 result = ws;
3140 }
3141
3142 void visit(TryCatchStatement *tcs)
3143 {
3144 if (!global.params.useExceptions)
3145 {
3146 tcs->error("Cannot use try-catch statements with -betterC");
3147 return setError();
3148 }
3149
3150 if (!ClassDeclaration::throwable)
3151 {
3152 tcs->error("Cannot use try-catch statements because `object.Throwable` was not declared");
3153 return setError();
3154 }
3155
3156 unsigned flags = 0;
3157 const unsigned FLAGcpp = 1;
3158 const unsigned FLAGd = 2;
3159
3160 tcs->_body = semanticScope(tcs->_body, sc, NULL, NULL);
3161 assert(tcs->_body);
3162
3163 /* Even if body is empty, still do semantic analysis on catches
3164 */
3165 bool catchErrors = false;
3166 for (size_t i = 0; i < tcs->catches->dim; i++)
3167 {
3168 Catch *c = (*tcs->catches)[i];
3169 semantic(c, sc);
3170 if (c->errors)
3171 {
3172 catchErrors = true;
3173 continue;
3174 }
3175 ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
3176 flags |= cd->isCPPclass() ? FLAGcpp : FLAGd;
3177
3178 // Determine if current catch 'hides' any previous catches
3179 for (size_t j = 0; j < i; j++)
3180 {
3181 Catch *cj = (*tcs->catches)[j];
3182 const char *si = c->loc.toChars();
3183 const char *sj = cj->loc.toChars();
3184
3185 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3186 {
3187 tcs->error("catch at %s hides catch at %s", sj, si);
3188 catchErrors = true;
3189 }
3190 }
3191 }
3192
3193 if (sc->func)
3194 {
3195 if (flags == (FLAGcpp | FLAGd))
3196 {
3197 tcs->error("cannot mix catching D and C++ exceptions in the same try-catch");
3198 catchErrors = true;
3199 }
3200 }
3201
3202 if (catchErrors)
3203 return setError();
3204
3205 if (tcs->_body->isErrorStatement())
3206 {
3207 result = tcs->_body;
3208 return;
3209 }
3210
3211 /* If the try body never throws, we can eliminate any catches
3212 * of recoverable exceptions.
3213 */
3214
3215 if (!(blockExit(tcs->_body, sc->func, false) & BEthrow) && ClassDeclaration::exception)
3216 {
3217 for (size_t i = 0; i < tcs->catches->dim; i++)
3218 {
3219 Catch *c = (*tcs->catches)[i];
3220
3221 /* If catch exception type is derived from Exception
3222 */
3223 if (c->type->toBasetype()->implicitConvTo(ClassDeclaration::exception->type) &&
3224 (!c->handler || !c->handler->comeFrom()))
3225 {
3226 // Remove c from the array of catches
3227 tcs->catches->remove(i);
3228 --i;
3229 }
3230 }
3231 }
3232
3233 if (tcs->catches->dim == 0)
3234 {
3235 result = tcs->_body->hasCode() ? tcs->_body : NULL;
3236 return;
3237 }
3238
3239 result = tcs;
3240 }
3241
3242 void visit(TryFinallyStatement *tfs)
3243 {
3244 //printf("TryFinallyStatement::semantic()\n");
3245 tfs->_body = semantic(tfs->_body, sc);
3246 sc = sc->push();
3247 sc->tf = tfs;
3248 sc->sbreak = NULL;
3249 sc->scontinue = NULL; // no break or continue out of finally block
3250 tfs->finalbody = semanticNoScope(tfs->finalbody, sc);
3251 sc->pop();
3252
3253 if (!tfs->_body)
3254 {
3255 result = tfs->finalbody;
3256 return;
3257 }
3258
3259 if (!tfs->finalbody)
3260 {
3261 result = tfs->_body;
3262 return;
3263 }
3264
3265 int blockexit = blockExit(tfs->_body, sc->func, false);
3266
3267 // if not worrying about exceptions
3268 if (!(global.params.useExceptions && ClassDeclaration::throwable))
3269 blockexit &= ~BEthrow; // don't worry about paths that otherwise may throw
3270
3271 // Don't care about paths that halt, either
3272 if ((blockexit & ~BEhalt) == BEfallthru)
3273 {
3274 result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody);
3275 return;
3276 }
3277 result = tfs;
3278 }
3279
3280 void visit(OnScopeStatement *oss)
3281 {
3282 if (oss->tok != TOKon_scope_exit)
3283 {
3284 // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
3285 // so the generated catch block cannot be placed in finally block.
3286 // See also Catch::semantic.
3287 if (sc->os && sc->os->tok != TOKon_scope_failure)
3288 {
3289 // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
3290 oss->error("cannot put %s statement inside %s", Token::toChars(oss->tok), Token::toChars(sc->os->tok));
3291 return setError();
3292 }
3293 if (sc->tf)
3294 {
3295 oss->error("cannot put %s statement inside finally block", Token::toChars(oss->tok));
3296 return setError();
3297 }
3298 }
3299
3300 sc = sc->push();
3301 sc->tf = NULL;
3302 sc->os = oss;
3303 if (oss->tok != TOKon_scope_failure)
3304 {
3305 // Jump out from scope(failure) block is allowed.
3306 sc->sbreak = NULL;
3307 sc->scontinue = NULL;
3308 }
3309 oss->statement = semanticNoScope(oss->statement, sc);
3310 sc->pop();
3311
3312 if (!oss->statement || oss->statement->isErrorStatement())
3313 {
3314 result = oss->statement;
3315 return;
3316 }
3317 result = oss;
3318 }
3319
3320 void visit(ThrowStatement *ts)
3321 {
3322 //printf("ThrowStatement::semantic()\n");
3323
3324 if (!global.params.useExceptions)
3325 {
3326 ts->error("Cannot use `throw` statements with -betterC");
3327 return setError();
3328 }
3329
3330 if (!ClassDeclaration::throwable)
3331 {
3332 ts->error("Cannot use `throw` statements because `object.Throwable` was not declared");
3333 return setError();
3334 }
3335
3336 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3337 fd->hasReturnExp |= 2;
3338
3339 ts->exp = semantic(ts->exp, sc);
3340 ts->exp = resolveProperties(sc, ts->exp);
3341 ts->exp = checkGC(sc, ts->exp);
3342 if (ts->exp->op == TOKerror)
3343 return setError();
3344
3345 checkThrowEscape(sc, ts->exp, false);
3346
3347 ClassDeclaration *cd = ts->exp->type->toBasetype()->isClassHandle();
3348 if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL)))
3349 {
3350 ts->error("can only throw class objects derived from Throwable, not type %s", ts->exp->type->toChars());
3351 return setError();
3352 }
3353
3354 result = ts;
3355 }
3356
3357 void visit(DebugStatement *ds)
3358 {
3359 if (ds->statement)
3360 {
3361 sc = sc->push();
3362 sc->flags |= SCOPEdebug;
3363 ds->statement = semantic(ds->statement, sc);
3364 sc->pop();
3365 }
3366 result = ds->statement;
3367 }
3368
3369 void visit(GotoStatement *gs)
3370 {
3371 //printf("GotoStatement::semantic()\n");
3372 FuncDeclaration *fd = sc->func;
3373
3374 gs->ident = fixupLabelName(sc, gs->ident);
3375 gs->label = fd->searchLabel(gs->ident);
3376 gs->tf = sc->tf;
3377 gs->os = sc->os;
3378 gs->lastVar = sc->lastVar;
3379
3380 if (!gs->label->statement && sc->fes)
3381 {
3382 /* Either the goto label is forward referenced or it
3383 * is in the function that the enclosing foreach is in.
3384 * Can't know yet, so wrap the goto in a scope statement
3385 * so we can patch it later, and add it to a 'look at this later'
3386 * list.
3387 */
3388 ScopeStatement *ss = new ScopeStatement(gs->loc, gs, gs->loc);
3389 sc->fes->gotos->push(ss); // 'look at this later' list
3390 result = ss;
3391 return;
3392 }
3393
3394 // Add to fwdref list to check later
3395 if (!gs->label->statement)
3396 {
3397 if (!fd->gotos)
3398 fd->gotos = new GotoStatements();
3399 fd->gotos->push(gs);
3400 }
3401 else if (gs->checkLabel())
3402 return setError();
3403
3404 result = gs;
3405 }
3406
3407 void visit(LabelStatement *ls)
3408 {
3409 //printf("LabelStatement::semantic()\n");
3410 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3411
3412 ls->ident = fixupLabelName(sc, ls->ident);
3413 ls->tf = sc->tf;
3414 ls->os = sc->os;
3415 ls->lastVar = sc->lastVar;
3416
3417 LabelDsymbol *ls2 = fd->searchLabel(ls->ident);
3418 if (ls2->statement)
3419 {
3420 ls->error("label '%s' already defined", ls2->toChars());
3421 return setError();
3422 }
3423 else
3424 ls2->statement = ls;
3425
3426 sc = sc->push();
3427 sc->scopesym = sc->enclosing->scopesym;
3428 sc->callSuper |= CSXlabel;
3429 if (sc->fieldinit)
3430 {
3431 size_t dim = sc->fieldinit_dim;
3432 for (size_t i = 0; i < dim; i++)
3433 sc->fieldinit[i] |= CSXlabel;
3434 }
3435 sc->slabel = ls;
3436 if (ls->statement)
3437 ls->statement = semantic(ls->statement, sc);
3438 sc->pop();
3439
3440 result = ls;
3441 }
3442
3443 void visit(AsmStatement *s)
3444 {
3445 result = asmSemantic(s, sc);
3446 }
3447
3448 void visit(CompoundAsmStatement *cas)
3449 {
3450 // Apply postfix attributes of the asm block to each statement.
3451 sc = sc->push();
3452 sc->stc |= cas->stc;
3453
3454 for (size_t i = 0; i < cas->statements->dim; i++)
3455 {
3456 Statement *s = (*cas->statements)[i];
3457 (*cas->statements)[i] = s ? semantic(s, sc) : NULL;
3458 }
3459
3460 assert(sc->func);
3461 // use setImpure/setGC when the deprecation cycle is over
3462 PURE purity;
3463 if (!(cas->stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref)
3464 cas->deprecation("asm statement is assumed to be impure - mark it with 'pure' if it is not");
3465 if (!(cas->stc & STCnogc) && sc->func->isNogcBypassingInference())
3466 cas->deprecation("asm statement is assumed to use the GC - mark it with '@nogc' if it does not");
3467 if (!(cas->stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe())
3468 cas->error("asm statement is assumed to be @system - mark it with '@trusted' if it is not");
3469
3470 sc->pop();
3471 result = cas;
3472 }
3473
3474 void visit(ImportStatement *imps)
3475 {
3476 for (size_t i = 0; i < imps->imports->dim; i++)
3477 {
3478 Import *s = (*imps->imports)[i]->isImport();
3479 assert(!s->aliasdecls.dim);
3480 for (size_t j = 0; j < s->names.dim; j++)
3481 {
3482 Identifier *name = s->names[j];
3483 Identifier *alias = s->aliases[j];
3484
3485 if (!alias)
3486 alias = name;
3487
3488 TypeIdentifier *tname = new TypeIdentifier(s->loc, name);
3489 AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname);
3490 ad->_import = s;
3491 s->aliasdecls.push(ad);
3492 }
3493
3494 s->semantic(sc);
3495 Module::addDeferredSemantic2(s); // Bugzilla 14666
3496 sc->insert(s);
3497
3498 for (size_t j = 0; j < s->aliasdecls.dim; j++)
3499 {
3500 sc->insert(s->aliasdecls[j]);
3501 }
3502 }
3503 result = imps;
3504 }
3505 };
3506
3507 Statement *semantic(Statement *s, Scope *sc)
3508 {
3509 StatementSemanticVisitor v = StatementSemanticVisitor(sc);
3510 s->accept(&v);
3511 return v.result;
3512 }
3513
3514 void semantic(Catch *c, Scope *sc)
3515 {
3516 //printf("Catch::semantic(%s)\n", ident->toChars());
3517
3518 if (sc->os && sc->os->tok != TOKon_scope_failure)
3519 {
3520 // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
3521 error(c->loc, "cannot put catch statement inside %s", Token::toChars(sc->os->tok));
3522 c->errors = true;
3523 }
3524 if (sc->tf)
3525 {
3526 /* This is because the _d_local_unwind() gets the stack munged
3527 * up on this. The workaround is to place any try-catches into
3528 * a separate function, and call that.
3529 * To fix, have the compiler automatically convert the finally
3530 * body into a nested function.
3531 */
3532 error(c->loc, "cannot put catch statement inside finally block");
3533 c->errors = true;
3534 }
3535
3536 ScopeDsymbol *sym = new ScopeDsymbol();
3537 sym->parent = sc->scopesym;
3538 sc = sc->push(sym);
3539
3540 if (!c->type)
3541 {
3542 deprecation(c->loc, "catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior");
3543
3544 // reference .object.Throwable
3545 c->type = getThrowable();
3546 }
3547 c->type = c->type->semantic(c->loc, sc);
3548 if (c->type == Type::terror)
3549 c->errors = true;
3550 else
3551 {
3552 ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
3553 if (!cd)
3554 {
3555 error(c->loc, "can only catch class objects, not '%s'", c->type->toChars());
3556 c->errors = true;
3557 }
3558 else if (cd->isCPPclass())
3559 {
3560 if (!Target::cppExceptions)
3561 {
3562 error(c->loc, "catching C++ class objects not supported for this target");
3563 c->errors = true;
3564 }
3565 if (sc->func && !sc->intypeof && !c->internalCatch && sc->func->setUnsafe())
3566 {
3567 error(c->loc, "cannot catch C++ class objects in @safe code");
3568 c->errors = true;
3569 }
3570 }
3571 else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
3572 {
3573 error(c->loc, "can only catch class objects derived from Throwable, not '%s'", c->type->toChars());
3574 c->errors = true;
3575 }
3576 else if (sc->func && !sc->intypeof && !c->internalCatch &&
3577 cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
3578 sc->func->setUnsafe())
3579 {
3580 error(c->loc, "can only catch class objects derived from Exception in @safe code, not '%s'", c->type->toChars());
3581 c->errors = true;
3582 }
3583
3584 if (c->ident)
3585 {
3586 c->var = new VarDeclaration(c->loc, c->type, c->ident, NULL);
3587 c->var->semantic(sc);
3588 sc->insert(c->var);
3589 }
3590 c->handler = semantic(c->handler, sc);
3591 if (c->handler && c->handler->isErrorStatement())
3592 c->errors = true;
3593 }
3594 sc->pop();
3595 }
3596
3597 Statement *semanticNoScope(Statement *s, Scope *sc)
3598 {
3599 //printf("Statement::semanticNoScope() %s\n", toChars());
3600 if (!s->isCompoundStatement() && !s->isScopeStatement())
3601 {
3602 s = new CompoundStatement(s->loc, s); // so scopeCode() gets called
3603 }
3604 s = semantic(s, sc);
3605 return s;
3606 }
3607
3608 // Same as semanticNoScope(), but do create a new scope
3609 Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue)
3610 {
3611 ScopeDsymbol *sym = new ScopeDsymbol();
3612 sym->parent = sc->scopesym;
3613 Scope *scd = sc->push(sym);
3614 if (sbreak)
3615 scd->sbreak = sbreak;
3616 if (scontinue)
3617 scd->scontinue = scontinue;
3618 s = semanticNoScope(s, scd);
3619 scd->pop();
3620 return s;
3621 }