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