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