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