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