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