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 _statement.d) 9 */ 10 11 module ddmd.statement; 12 13 import core.stdc.stdarg; 14 import core.stdc.stdio; 15 16 import ddmd.aggregate; 17 import ddmd.arraytypes; 18 import ddmd.attrib; 19 import ddmd.gluelayer; 20 import ddmd.canthrow; 21 import ddmd.cond; 22 import ddmd.dclass; 23 import ddmd.declaration; 24 import ddmd.denum; 25 import ddmd.dimport; 26 import ddmd.dscope; 27 import ddmd.dsymbol; 28 import ddmd.dtemplate; 29 import ddmd.errors; 30 import ddmd.expression; 31 import ddmd.func; 32 import ddmd.globals; 33 import ddmd.hdrgen; 34 import ddmd.id; 35 import ddmd.identifier; 36 import ddmd.mtype; 37 import ddmd.parse; 38 import ddmd.root.outbuffer; 39 import ddmd.root.rootobject; 40 import ddmd.sapply; 41 import ddmd.sideeffect; 42 import ddmd.staticassert; 43 import ddmd.tokens; 44 import ddmd.visitor; 45 46 extern (C++) Identifier fixupLabelName(Scope* sc, Identifier ident) 47 { 48 uint flags = (sc.flags & SCOPEcontract); 49 const id = ident.toChars(); 50 if (flags && flags != SCOPEinvariant && !(id[0] == '_' && id[1] == '_')) 51 { 52 /* CTFE requires FuncDeclaration::labtab for the interpretation. 53 * So fixing the label name inside in/out contracts is necessary 54 * for the uniqueness in labtab. 55 */ 56 const(char)* prefix = flags == SCOPErequire ? "__in_" : "__out_"; 57 OutBuffer buf; 58 buf.printf("%s%s", prefix, ident.toChars()); 59 60 ident = Identifier.idPool(buf.peekSlice()); 61 } 62 return ident; 63 } 64 65 extern (C++) LabelStatement checkLabeledLoop(Scope* sc, Statement statement) 66 { 67 if (sc.slabel && sc.slabel.statement == statement) 68 { 69 return sc.slabel; 70 } 71 return null; 72 } 73 74 /*********************************************************** 75 * Check an assignment is used as a condition. 76 * Intended to be use before the `semantic` call on `e`. 77 * Params: 78 * e = condition expression which is not yet run semantic analysis. 79 * Returns: 80 * `e` or ErrorExp. 81 */ 82 Expression checkAssignmentAsCondition(Expression e) 83 { 84 auto ec = e; 85 while (ec.op == TOKcomma) 86 ec = (cast(CommaExp)ec).e2; 87 if (ec.op == TOKassign) 88 { 89 ec.error("assignment cannot be used as a condition, perhaps == was meant?"); 90 return new ErrorExp(); 91 } 92 return e; 93 } 94 95 /// Return a type identifier reference to 'object.Throwable' 96 TypeIdentifier getThrowable() 97 { 98 auto tid = new TypeIdentifier(Loc(), Id.empty); 99 tid.addIdent(Id.object); 100 tid.addIdent(Id.Throwable); 101 return tid; 102 } 103 104 enum BE : int 105 { 106 BEnone = 0, 107 BEfallthru = 1, 108 BEthrow = 2, 109 BEreturn = 4, 110 BEgoto = 8, 111 BEhalt = 0x10, 112 BEbreak = 0x20, 113 BEcontinue = 0x40, 114 BEerrthrow = 0x80, 115 BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), 116 } 117 118 alias BEnone = BE.BEnone; 119 alias BEfallthru = BE.BEfallthru; 120 alias BEthrow = BE.BEthrow; 121 alias BEreturn = BE.BEreturn; 122 alias BEgoto = BE.BEgoto; 123 alias BEhalt = BE.BEhalt; 124 alias BEbreak = BE.BEbreak; 125 alias BEcontinue = BE.BEcontinue; 126 alias BEerrthrow = BE.BEerrthrow; 127 alias BEany = BE.BEany; 128 129 /*********************************************************** 130 */ 131 extern (C++) abstract class Statement : RootObject 132 { 133 Loc loc; 134 135 final extern (D) this(Loc loc) 136 { 137 this.loc = loc; 138 // If this is an in{} contract scope statement (skip for determining 139 // inlineStatus of a function body for header content) 140 } 141 142 Statement syntaxCopy() 143 { 144 assert(0); 145 } 146 147 override final void print() 148 { 149 fprintf(stderr, "%s\n", toChars()); 150 fflush(stderr); 151 } 152 153 override final const(char)* toChars() 154 { 155 HdrGenState hgs; 156 OutBuffer buf; 157 .toCBuffer(this, &buf, &hgs); 158 return buf.extractString(); 159 } 160 161 final void error(const(char)* format, ...) 162 { 163 va_list ap; 164 va_start(ap, format); 165 .verror(loc, format, ap); 166 va_end(ap); 167 } 168 169 final void warning(const(char)* format, ...) 170 { 171 va_list ap; 172 va_start(ap, format); 173 .vwarning(loc, format, ap); 174 va_end(ap); 175 } 176 177 final void deprecation(const(char)* format, ...) 178 { 179 va_list ap; 180 va_start(ap, format); 181 .vdeprecation(loc, format, ap); 182 va_end(ap); 183 } 184 185 Statement getRelatedLabeled() 186 { 187 return this; 188 } 189 190 bool hasBreak() 191 { 192 //printf("Statement::hasBreak()\n"); 193 return false; 194 } 195 196 bool hasContinue() 197 { 198 return false; 199 } 200 201 /* ============================================== */ 202 // true if statement uses exception handling 203 final bool usesEH() 204 { 205 extern (C++) final class UsesEH : StoppableVisitor 206 { 207 alias visit = super.visit; 208 public: 209 override void visit(Statement s) 210 { 211 } 212 213 override void visit(TryCatchStatement s) 214 { 215 stop = true; 216 } 217 218 override void visit(TryFinallyStatement s) 219 { 220 stop = true; 221 } 222 223 override void visit(OnScopeStatement s) 224 { 225 stop = true; 226 } 227 228 override void visit(SynchronizedStatement s) 229 { 230 stop = true; 231 } 232 } 233 234 scope UsesEH ueh = new UsesEH(); 235 return walkPostorder(this, ueh); 236 } 237 238 /* ============================================== */ 239 /* Only valid after semantic analysis 240 * If 'mustNotThrow' is true, generate an error if it throws 241 */ 242 final int blockExit(FuncDeclaration func, bool mustNotThrow) 243 { 244 extern (C++) final class BlockExit : Visitor 245 { 246 alias visit = super.visit; 247 public: 248 FuncDeclaration func; 249 bool mustNotThrow; 250 int result; 251 252 extern (D) this(FuncDeclaration func, bool mustNotThrow) 253 { 254 this.func = func; 255 this.mustNotThrow = mustNotThrow; 256 result = BEnone; 257 } 258 259 override void visit(Statement s) 260 { 261 printf("Statement::blockExit(%p)\n", s); 262 printf("%s\n", s.toChars()); 263 assert(0); 264 } 265 266 override void visit(ErrorStatement s) 267 { 268 result = BEany; 269 } 270 271 override void visit(ExpStatement s) 272 { 273 result = BEfallthru; 274 if (s.exp) 275 { 276 if (s.exp.op == TOKhalt) 277 { 278 result = BEhalt; 279 return; 280 } 281 if (s.exp.op == TOKassert) 282 { 283 AssertExp a = cast(AssertExp)s.exp; 284 if (a.e1.isBool(false)) // if it's an assert(0) 285 { 286 result = BEhalt; 287 return; 288 } 289 } 290 if (canThrow(s.exp, func, mustNotThrow)) 291 result |= BEthrow; 292 } 293 } 294 295 override void visit(CompileStatement s) 296 { 297 assert(global.errors); 298 result = BEfallthru; 299 } 300 301 override void visit(CompoundStatement cs) 302 { 303 //printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.dim, result); 304 result = BEfallthru; 305 Statement slast = null; 306 foreach (s; *cs.statements) 307 { 308 if (s) 309 { 310 //printf("result = x%x\n", result); 311 //printf("s: %s\n", s.toChars()); 312 if (result & BEfallthru && slast) 313 { 314 slast = slast.last(); 315 if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement())) 316 { 317 // Allow if last case/default was empty 318 CaseStatement sc = slast.isCaseStatement(); 319 DefaultStatement sd = slast.isDefaultStatement(); 320 if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement())) 321 { 322 } 323 else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement())) 324 { 325 } 326 else 327 { 328 const(char)* gototype = s.isCaseStatement() ? "case" : "default"; 329 s.error("switch case fallthrough - use 'goto %s;' if intended", gototype); 330 } 331 } 332 } 333 334 if (!(result & BEfallthru) && !s.comeFrom()) 335 { 336 if (s.blockExit(func, mustNotThrow) != BEhalt && s.hasCode()) 337 s.warning("statement is not reachable"); 338 } 339 else 340 { 341 result &= ~BEfallthru; 342 result |= s.blockExit(func, mustNotThrow); 343 } 344 slast = s; 345 } 346 } 347 } 348 349 override void visit(UnrolledLoopStatement uls) 350 { 351 result = BEfallthru; 352 foreach (s; *uls.statements) 353 { 354 if (s) 355 { 356 int r = s.blockExit(func, mustNotThrow); 357 result |= r & ~(BEbreak | BEcontinue | BEfallthru); 358 if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0) 359 result &= ~BEfallthru; 360 } 361 } 362 } 363 364 override void visit(ScopeStatement s) 365 { 366 //printf("ScopeStatement::blockExit(%p)\n", s->statement); 367 result = s.statement ? s.statement.blockExit(func, mustNotThrow) : BEfallthru; 368 } 369 370 override void visit(WhileStatement s) 371 { 372 assert(global.errors); 373 result = BEfallthru; 374 } 375 376 override void visit(DoStatement s) 377 { 378 if (s._body) 379 { 380 result = s._body.blockExit(func, mustNotThrow); 381 if (result == BEbreak) 382 { 383 result = BEfallthru; 384 return; 385 } 386 if (result & BEcontinue) 387 result |= BEfallthru; 388 } 389 else 390 result = BEfallthru; 391 if (result & BEfallthru) 392 { 393 if (canThrow(s.condition, func, mustNotThrow)) 394 result |= BEthrow; 395 if (!(result & BEbreak) && s.condition.isBool(true)) 396 result &= ~BEfallthru; 397 } 398 result &= ~(BEbreak | BEcontinue); 399 } 400 401 override void visit(ForStatement s) 402 { 403 result = BEfallthru; 404 if (s._init) 405 { 406 result = s._init.blockExit(func, mustNotThrow); 407 if (!(result & BEfallthru)) 408 return; 409 } 410 if (s.condition) 411 { 412 if (canThrow(s.condition, func, mustNotThrow)) 413 result |= BEthrow; 414 if (s.condition.isBool(true)) 415 result &= ~BEfallthru; 416 else if (s.condition.isBool(false)) 417 return; 418 } 419 else 420 result &= ~BEfallthru; // the body must do the exiting 421 if (s._body) 422 { 423 int r = s._body.blockExit(func, mustNotThrow); 424 if (r & (BEbreak | BEgoto)) 425 result |= BEfallthru; 426 result |= r & ~(BEfallthru | BEbreak | BEcontinue); 427 } 428 if (s.increment && canThrow(s.increment, func, mustNotThrow)) 429 result |= BEthrow; 430 } 431 432 override void visit(ForeachStatement s) 433 { 434 result = BEfallthru; 435 if (canThrow(s.aggr, func, mustNotThrow)) 436 result |= BEthrow; 437 if (s._body) 438 result |= s._body.blockExit(func, mustNotThrow) & ~(BEbreak | BEcontinue); 439 } 440 441 override void visit(ForeachRangeStatement s) 442 { 443 assert(global.errors); 444 result = BEfallthru; 445 } 446 447 override void visit(IfStatement s) 448 { 449 //printf("IfStatement::blockExit(%p)\n", s); 450 result = BEnone; 451 if (canThrow(s.condition, func, mustNotThrow)) 452 result |= BEthrow; 453 if (s.condition.isBool(true)) 454 { 455 if (s.ifbody) 456 result |= s.ifbody.blockExit(func, mustNotThrow); 457 else 458 result |= BEfallthru; 459 } 460 else if (s.condition.isBool(false)) 461 { 462 if (s.elsebody) 463 result |= s.elsebody.blockExit(func, mustNotThrow); 464 else 465 result |= BEfallthru; 466 } 467 else 468 { 469 if (s.ifbody) 470 result |= s.ifbody.blockExit(func, mustNotThrow); 471 else 472 result |= BEfallthru; 473 if (s.elsebody) 474 result |= s.elsebody.blockExit(func, mustNotThrow); 475 else 476 result |= BEfallthru; 477 } 478 //printf("IfStatement::blockExit(%p) = x%x\n", s, result); 479 } 480 481 override void visit(ConditionalStatement s) 482 { 483 result = s.ifbody.blockExit(func, mustNotThrow); 484 if (s.elsebody) 485 result |= s.elsebody.blockExit(func, mustNotThrow); 486 } 487 488 override void visit(PragmaStatement s) 489 { 490 result = BEfallthru; 491 } 492 493 override void visit(StaticAssertStatement s) 494 { 495 result = BEfallthru; 496 } 497 498 override void visit(SwitchStatement s) 499 { 500 result = BEnone; 501 if (canThrow(s.condition, func, mustNotThrow)) 502 result |= BEthrow; 503 if (s._body) 504 { 505 result |= s._body.blockExit(func, mustNotThrow); 506 if (result & BEbreak) 507 { 508 result |= BEfallthru; 509 result &= ~BEbreak; 510 } 511 } 512 else 513 result |= BEfallthru; 514 } 515 516 override void visit(CaseStatement s) 517 { 518 result = s.statement.blockExit(func, mustNotThrow); 519 } 520 521 override void visit(DefaultStatement s) 522 { 523 result = s.statement.blockExit(func, mustNotThrow); 524 } 525 526 override void visit(GotoDefaultStatement s) 527 { 528 result = BEgoto; 529 } 530 531 override void visit(GotoCaseStatement s) 532 { 533 result = BEgoto; 534 } 535 536 override void visit(SwitchErrorStatement s) 537 { 538 // Switch errors are non-recoverable 539 result = BEhalt; 540 } 541 542 override void visit(ReturnStatement s) 543 { 544 result = BEreturn; 545 if (s.exp && canThrow(s.exp, func, mustNotThrow)) 546 result |= BEthrow; 547 } 548 549 override void visit(BreakStatement s) 550 { 551 //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak); 552 result = s.ident ? BEgoto : BEbreak; 553 } 554 555 override void visit(ContinueStatement s) 556 { 557 result = s.ident ? BEgoto : BEcontinue; 558 } 559 560 override void visit(SynchronizedStatement s) 561 { 562 result = s._body ? s._body.blockExit(func, mustNotThrow) : BEfallthru; 563 } 564 565 override void visit(WithStatement s) 566 { 567 result = BEnone; 568 if (canThrow(s.exp, func, mustNotThrow)) 569 result = BEthrow; 570 if (s._body) 571 result |= s._body.blockExit(func, mustNotThrow); 572 else 573 result |= BEfallthru; 574 } 575 576 override void visit(TryCatchStatement s) 577 { 578 assert(s._body); 579 result = s._body.blockExit(func, false); 580 581 int catchresult = 0; 582 foreach (c; *s.catches) 583 { 584 if (c.type == Type.terror) 585 continue; 586 587 int cresult; 588 if (c.handler) 589 cresult = c.handler.blockExit(func, mustNotThrow); 590 else 591 cresult = BEfallthru; 592 593 /* If we're catching Object, then there is no throwing 594 */ 595 Identifier id = c.type.toBasetype().isClassHandle().ident; 596 if (c.internalCatch && (cresult & BEfallthru)) 597 { 598 // Bugzilla 11542: leave blockExit flags of the body 599 cresult &= ~BEfallthru; 600 } 601 else if (id == Id.Object || id == Id.Throwable) 602 { 603 result &= ~(BEthrow | BEerrthrow); 604 } 605 else if (id == Id.Exception) 606 { 607 result &= ~BEthrow; 608 } 609 catchresult |= cresult; 610 } 611 if (mustNotThrow && (result & BEthrow)) 612 { 613 // now explain why this is nothrow 614 s._body.blockExit(func, mustNotThrow); 615 } 616 result |= catchresult; 617 } 618 619 override void visit(TryFinallyStatement s) 620 { 621 result = BEfallthru; 622 if (s._body) 623 result = s._body.blockExit(func, false); 624 625 // check finally body as well, it may throw (bug #4082) 626 int finalresult = BEfallthru; 627 if (s.finalbody) 628 finalresult = s.finalbody.blockExit(func, false); 629 630 // If either body or finalbody halts 631 if (result == BEhalt) 632 finalresult = BEnone; 633 if (finalresult == BEhalt) 634 result = BEnone; 635 636 if (mustNotThrow) 637 { 638 // now explain why this is nothrow 639 if (s._body && (result & BEthrow)) 640 s._body.blockExit(func, mustNotThrow); 641 if (s.finalbody && (finalresult & BEthrow)) 642 s.finalbody.blockExit(func, mustNotThrow); 643 } 644 645 version (none) 646 { 647 // Bugzilla 13201: Mask to prevent spurious warnings for 648 // destructor call, exit of synchronized statement, etc. 649 if (result == BEhalt && finalresult != BEhalt && s.finalbody && s.finalbody.hasCode()) 650 { 651 s.finalbody.warning("statement is not reachable"); 652 } 653 } 654 655 if (!(finalresult & BEfallthru)) 656 result &= ~BEfallthru; 657 result |= finalresult & ~BEfallthru; 658 } 659 660 override void visit(OnScopeStatement s) 661 { 662 // At this point, this statement is just an empty placeholder 663 result = BEfallthru; 664 } 665 666 override void visit(ThrowStatement s) 667 { 668 if (s.internalThrow) 669 { 670 // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow. 671 result = BEfallthru; 672 return; 673 } 674 675 Type t = s.exp.type.toBasetype(); 676 ClassDeclaration cd = t.isClassHandle(); 677 assert(cd); 678 679 if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null)) 680 { 681 result = BEerrthrow; 682 return; 683 } 684 if (mustNotThrow) 685 s.error("%s is thrown but not caught", s.exp.type.toChars()); 686 687 result = BEthrow; 688 } 689 690 override void visit(GotoStatement s) 691 { 692 //printf("GotoStatement::blockExit(%p)\n", s); 693 result = BEgoto; 694 } 695 696 override void visit(LabelStatement s) 697 { 698 //printf("LabelStatement::blockExit(%p)\n", s); 699 result = s.statement ? s.statement.blockExit(func, mustNotThrow) : BEfallthru; 700 if (s.breaks) 701 result |= BEfallthru; 702 } 703 704 override void visit(CompoundAsmStatement s) 705 { 706 if (mustNotThrow && !(s.stc & STCnothrow)) 707 s.deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not"); 708 709 // Assume the worst 710 result = BEfallthru | BEreturn | BEgoto | BEhalt; 711 if (!(s.stc & STCnothrow)) 712 result |= BEthrow; 713 } 714 715 override void visit(ImportStatement s) 716 { 717 result = BEfallthru; 718 } 719 } 720 721 scope BlockExit be = new BlockExit(func, mustNotThrow); 722 accept(be); 723 return be.result; 724 } 725 726 /* ============================================== */ 727 // true if statement 'comes from' somewhere else, like a goto 728 final bool comeFrom() 729 { 730 extern (C++) final class ComeFrom : StoppableVisitor 731 { 732 alias visit = super.visit; 733 public: 734 override void visit(Statement s) 735 { 736 } 737 738 override void visit(CaseStatement s) 739 { 740 stop = true; 741 } 742 743 override void visit(DefaultStatement s) 744 { 745 stop = true; 746 } 747 748 override void visit(LabelStatement s) 749 { 750 stop = true; 751 } 752 753 override void visit(AsmStatement s) 754 { 755 stop = true; 756 } 757 } 758 759 scope ComeFrom cf = new ComeFrom(); 760 return walkPostorder(this, cf); 761 } 762 763 /* ============================================== */ 764 // Return true if statement has executable code. 765 final bool hasCode() 766 { 767 extern (C++) final class HasCode : StoppableVisitor 768 { 769 alias visit = super.visit; 770 public: 771 override void visit(Statement s) 772 { 773 stop = true; 774 } 775 776 override void visit(ExpStatement s) 777 { 778 stop = s.exp !is null; 779 } 780 781 override void visit(CompoundStatement s) 782 { 783 } 784 785 override void visit(ScopeStatement s) 786 { 787 } 788 789 override void visit(ImportStatement s) 790 { 791 } 792 } 793 794 scope HasCode hc = new HasCode(); 795 return walkPostorder(this, hc); 796 } 797 798 /**************************************** 799 * If this statement has code that needs to run in a finally clause 800 * at the end of the current scope, return that code in the form of 801 * a Statement. 802 * Output: 803 * *sentry code executed upon entry to the scope 804 * *sexception code executed upon exit from the scope via exception 805 * *sfinally code executed in finally block 806 */ 807 Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 808 { 809 //printf("Statement::scopeCode()\n"); 810 //print(); 811 *sentry = null; 812 *sexception = null; 813 *sfinally = null; 814 return this; 815 } 816 817 /********************************* 818 * Flatten out the scope by presenting the statement 819 * as an array of statements. 820 * Returns NULL if no flattening necessary. 821 */ 822 Statements* flatten(Scope* sc) 823 { 824 return null; 825 } 826 827 inout(Statement) last() inout nothrow pure 828 { 829 return this; 830 } 831 832 // Avoid dynamic_cast 833 ErrorStatement isErrorStatement() 834 { 835 return null; 836 } 837 838 inout(ScopeStatement) isScopeStatement() inout nothrow pure 839 { 840 return null; 841 } 842 843 ExpStatement isExpStatement() 844 { 845 return null; 846 } 847 848 inout(CompoundStatement) isCompoundStatement() inout nothrow pure 849 { 850 return null; 851 } 852 853 inout(ReturnStatement) isReturnStatement() inout nothrow pure 854 { 855 return null; 856 } 857 858 IfStatement isIfStatement() 859 { 860 return null; 861 } 862 863 CaseStatement isCaseStatement() 864 { 865 return null; 866 } 867 868 DefaultStatement isDefaultStatement() 869 { 870 return null; 871 } 872 873 LabelStatement isLabelStatement() 874 { 875 return null; 876 } 877 878 GotoDefaultStatement isGotoDefaultStatement() pure 879 { 880 return null; 881 } 882 883 GotoCaseStatement isGotoCaseStatement() pure 884 { 885 return null; 886 } 887 888 inout(BreakStatement) isBreakStatement() inout nothrow pure 889 { 890 return null; 891 } 892 893 DtorExpStatement isDtorExpStatement() 894 { 895 return null; 896 } 897 898 void accept(Visitor v) 899 { 900 v.visit(this); 901 } 902 } 903 904 /*********************************************************** 905 * Any Statement that fails semantic() or has a component that is an ErrorExp or 906 * a TypeError should return an ErrorStatement from semantic(). 907 */ 908 extern (C++) final class ErrorStatement : Statement 909 { 910 extern (D) this() 911 { 912 super(Loc()); 913 assert(global.gaggedErrors || global.errors); 914 } 915 916 override Statement syntaxCopy() 917 { 918 return this; 919 } 920 921 override ErrorStatement isErrorStatement() 922 { 923 return this; 924 } 925 926 override void accept(Visitor v) 927 { 928 v.visit(this); 929 } 930 } 931 932 /*********************************************************** 933 */ 934 extern (C++) final class PeelStatement : Statement 935 { 936 Statement s; 937 938 extern (D) this(Statement s) 939 { 940 super(s.loc); 941 this.s = s; 942 } 943 944 override void accept(Visitor v) 945 { 946 v.visit(this); 947 } 948 } 949 950 /*********************************************************** 951 * Convert TemplateMixin members (== Dsymbols) to Statements. 952 */ 953 extern (C++) Statement toStatement(Dsymbol s) 954 { 955 extern (C++) final class ToStmt : Visitor 956 { 957 alias visit = super.visit; 958 public: 959 Statement result; 960 961 Statement visitMembers(Loc loc, Dsymbols* a) 962 { 963 if (!a) 964 return null; 965 966 auto statements = new Statements(); 967 foreach (s; *a) 968 { 969 statements.push(toStatement(s)); 970 } 971 return new CompoundStatement(loc, statements); 972 } 973 974 override void visit(Dsymbol s) 975 { 976 .error(Loc(), "Internal Compiler Error: cannot mixin %s %s\n", s.kind(), s.toChars()); 977 result = new ErrorStatement(); 978 } 979 980 override void visit(TemplateMixin tm) 981 { 982 auto a = new Statements(); 983 foreach (m; *tm.members) 984 { 985 Statement s = toStatement(m); 986 if (s) 987 a.push(s); 988 } 989 result = new CompoundStatement(tm.loc, a); 990 } 991 992 /* An actual declaration symbol will be converted to DeclarationExp 993 * with ExpStatement. 994 */ 995 Statement declStmt(Dsymbol s) 996 { 997 auto de = new DeclarationExp(s.loc, s); 998 de.type = Type.tvoid; // avoid repeated semantic 999 return new ExpStatement(s.loc, de); 1000 } 1001 1002 override void visit(VarDeclaration d) 1003 { 1004 result = declStmt(d); 1005 } 1006 1007 override void visit(AggregateDeclaration d) 1008 { 1009 result = declStmt(d); 1010 } 1011 1012 override void visit(FuncDeclaration d) 1013 { 1014 result = declStmt(d); 1015 } 1016 1017 override void visit(EnumDeclaration d) 1018 { 1019 result = declStmt(d); 1020 } 1021 1022 override void visit(AliasDeclaration d) 1023 { 1024 result = declStmt(d); 1025 } 1026 1027 override void visit(TemplateDeclaration d) 1028 { 1029 result = declStmt(d); 1030 } 1031 1032 /* All attributes have been already picked by the semantic analysis of 1033 * 'bottom' declarations (function, struct, class, etc). 1034 * So we don't have to copy them. 1035 */ 1036 override void visit(StorageClassDeclaration d) 1037 { 1038 result = visitMembers(d.loc, d.decl); 1039 } 1040 1041 override void visit(DeprecatedDeclaration d) 1042 { 1043 result = visitMembers(d.loc, d.decl); 1044 } 1045 1046 override void visit(LinkDeclaration d) 1047 { 1048 result = visitMembers(d.loc, d.decl); 1049 } 1050 1051 override void visit(ProtDeclaration d) 1052 { 1053 result = visitMembers(d.loc, d.decl); 1054 } 1055 1056 override void visit(AlignDeclaration d) 1057 { 1058 result = visitMembers(d.loc, d.decl); 1059 } 1060 1061 override void visit(UserAttributeDeclaration d) 1062 { 1063 result = visitMembers(d.loc, d.decl); 1064 } 1065 1066 override void visit(StaticAssert s) 1067 { 1068 } 1069 1070 override void visit(Import s) 1071 { 1072 } 1073 1074 override void visit(PragmaDeclaration d) 1075 { 1076 } 1077 1078 override void visit(ConditionalDeclaration d) 1079 { 1080 result = visitMembers(d.loc, d.include(null, null)); 1081 } 1082 1083 override void visit(CompileDeclaration d) 1084 { 1085 result = visitMembers(d.loc, d.include(null, null)); 1086 } 1087 } 1088 1089 if (!s) 1090 return null; 1091 1092 scope ToStmt v = new ToStmt(); 1093 s.accept(v); 1094 return v.result; 1095 } 1096 1097 /*********************************************************** 1098 */ 1099 extern (C++) class ExpStatement : Statement 1100 { 1101 Expression exp; 1102 1103 final extern (D) this(Loc loc, Expression exp) 1104 { 1105 super(loc); 1106 this.exp = exp; 1107 } 1108 1109 final extern (D) this(Loc loc, Dsymbol declaration) 1110 { 1111 super(loc); 1112 this.exp = new DeclarationExp(loc, declaration); 1113 } 1114 1115 static ExpStatement create(Loc loc, Expression exp) 1116 { 1117 return new ExpStatement(loc, exp); 1118 } 1119 1120 override Statement syntaxCopy() 1121 { 1122 return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); 1123 } 1124 1125 override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 1126 { 1127 //printf("ExpStatement::scopeCode()\n"); 1128 //print(); 1129 1130 *sentry = null; 1131 *sexception = null; 1132 *sfinally = null; 1133 1134 if (exp && exp.op == TOKdeclaration) 1135 { 1136 auto de = cast(DeclarationExp)exp; 1137 auto v = de.declaration.isVarDeclaration(); 1138 if (v && !v.isDataseg()) 1139 { 1140 if (v.needsScopeDtor()) 1141 { 1142 //printf("dtor is: "); v.edtor.print(); 1143 *sfinally = new DtorExpStatement(loc, v.edtor, v); 1144 v.storage_class |= STCnodtor; // don't add in dtor again 1145 } 1146 } 1147 } 1148 return this; 1149 } 1150 1151 override final Statements* flatten(Scope* sc) 1152 { 1153 /* Bugzilla 14243: expand template mixin in statement scope 1154 * to handle variable destructors. 1155 */ 1156 if (exp && exp.op == TOKdeclaration) 1157 { 1158 Dsymbol d = (cast(DeclarationExp)exp).declaration; 1159 if (TemplateMixin tm = d.isTemplateMixin()) 1160 { 1161 Expression e = exp.semantic(sc); 1162 if (e.op == TOKerror || tm.errors) 1163 { 1164 auto a = new Statements(); 1165 a.push(new ErrorStatement()); 1166 return a; 1167 } 1168 assert(tm.members); 1169 1170 Statement s = toStatement(tm); 1171 version (none) 1172 { 1173 OutBuffer buf; 1174 buf.doindent = 1; 1175 HdrGenState hgs; 1176 hgs.hdrgen = true; 1177 toCBuffer(s, &buf, &hgs); 1178 printf("tm ==> s = %s\n", buf.peekString()); 1179 } 1180 auto a = new Statements(); 1181 a.push(s); 1182 return a; 1183 } 1184 } 1185 return null; 1186 } 1187 1188 override final ExpStatement isExpStatement() 1189 { 1190 return this; 1191 } 1192 1193 override void accept(Visitor v) 1194 { 1195 v.visit(this); 1196 } 1197 } 1198 1199 /*********************************************************** 1200 */ 1201 extern (C++) final class DtorExpStatement : ExpStatement 1202 { 1203 // Wraps an expression that is the destruction of 'var' 1204 VarDeclaration var; 1205 1206 extern (D) this(Loc loc, Expression exp, VarDeclaration v) 1207 { 1208 super(loc, exp); 1209 this.var = v; 1210 } 1211 1212 override Statement syntaxCopy() 1213 { 1214 return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); 1215 } 1216 1217 override void accept(Visitor v) 1218 { 1219 v.visit(this); 1220 } 1221 1222 override DtorExpStatement isDtorExpStatement() 1223 { 1224 return this; 1225 } 1226 } 1227 1228 /*********************************************************** 1229 */ 1230 extern (C++) final class CompileStatement : Statement 1231 { 1232 Expression exp; 1233 1234 extern (D) this(Loc loc, Expression exp) 1235 { 1236 super(loc); 1237 this.exp = exp; 1238 } 1239 1240 override Statement syntaxCopy() 1241 { 1242 return new CompileStatement(loc, exp.syntaxCopy()); 1243 } 1244 1245 override Statements* flatten(Scope* sc) 1246 { 1247 //printf("CompileStatement::flatten() %s\n", exp->toChars()); 1248 1249 auto errorStatements() 1250 { 1251 auto a = new Statements(); 1252 a.push(new ErrorStatement()); 1253 return a; 1254 } 1255 1256 auto se = semanticString(sc, exp, "argument to mixin"); 1257 if (!se) 1258 return errorStatements(); 1259 se = se.toUTF8(sc); 1260 1261 uint errors = global.errors; 1262 scope Parser p = new Parser(loc, sc._module, se.toStringz(), false); 1263 p.nextToken(); 1264 1265 auto a = new Statements(); 1266 while (p.token.value != TOKeof) 1267 { 1268 Statement s = p.parseStatement(PSsemi | PScurlyscope); 1269 if (!s || p.errors) 1270 { 1271 assert(!p.errors || global.errors != errors); // make sure we caught all the cases 1272 return errorStatements(); 1273 } 1274 a.push(s); 1275 } 1276 return a; 1277 } 1278 1279 override void accept(Visitor v) 1280 { 1281 v.visit(this); 1282 } 1283 } 1284 1285 /*********************************************************** 1286 */ 1287 extern (C++) class CompoundStatement : Statement 1288 { 1289 Statements* statements; 1290 1291 /** 1292 * Construct a `CompoundStatement` using an already existing 1293 * array of `Statement`s 1294 * 1295 * Params: 1296 * loc = Instantiation informations 1297 * s = An array of `Statement`s, that will referenced by this class 1298 */ 1299 final extern (D) this(Loc loc, Statements* s) 1300 { 1301 super(loc); 1302 statements = s; 1303 } 1304 1305 /** 1306 * Construct a `CompoundStatement` from an array of `Statement`s 1307 * 1308 * Params: 1309 * loc = Instantiation informations 1310 * s = A variadic array of `Statement`s, that will copied in this class 1311 * The entries themselves will not be copied. 1312 */ 1313 final extern (D) this(Loc loc, Statement[] sts...) 1314 { 1315 super(loc); 1316 statements = new Statements(); 1317 statements.reserve(sts.length); 1318 foreach (s; sts) 1319 statements.push(s); 1320 } 1321 1322 static CompoundStatement create(Loc loc, Statement s1, Statement s2) 1323 { 1324 return new CompoundStatement(loc, s1, s2); 1325 } 1326 1327 override Statement syntaxCopy() 1328 { 1329 auto a = new Statements(); 1330 a.setDim(statements.dim); 1331 foreach (i, s; *statements) 1332 { 1333 (*a)[i] = s ? s.syntaxCopy() : null; 1334 } 1335 return new CompoundStatement(loc, a); 1336 } 1337 1338 override Statements* flatten(Scope* sc) 1339 { 1340 return statements; 1341 } 1342 1343 override final inout(ReturnStatement) isReturnStatement() inout nothrow pure 1344 { 1345 ReturnStatement rs = null; 1346 foreach (s; *statements) 1347 { 1348 if (s) 1349 { 1350 rs = cast(ReturnStatement)s.isReturnStatement(); 1351 if (rs) 1352 break; 1353 } 1354 } 1355 return cast(inout)rs; 1356 } 1357 1358 override final inout(Statement) last() inout nothrow pure 1359 { 1360 Statement s = null; 1361 for (size_t i = statements.dim; i; --i) 1362 { 1363 s = cast(Statement)(*statements)[i - 1]; 1364 if (s) 1365 { 1366 s = cast(Statement)s.last(); 1367 if (s) 1368 break; 1369 } 1370 } 1371 return cast(inout)s; 1372 } 1373 1374 override final inout(CompoundStatement) isCompoundStatement() inout nothrow pure 1375 { 1376 return this; 1377 } 1378 1379 override void accept(Visitor v) 1380 { 1381 v.visit(this); 1382 } 1383 } 1384 1385 /*********************************************************** 1386 */ 1387 extern (C++) final class CompoundDeclarationStatement : CompoundStatement 1388 { 1389 extern (D) this(Loc loc, Statements* s) 1390 { 1391 super(loc, s); 1392 statements = s; 1393 } 1394 1395 override Statement syntaxCopy() 1396 { 1397 auto a = new Statements(); 1398 a.setDim(statements.dim); 1399 foreach (i, s; *statements) 1400 { 1401 (*a)[i] = s ? s.syntaxCopy() : null; 1402 } 1403 return new CompoundDeclarationStatement(loc, a); 1404 } 1405 1406 override void accept(Visitor v) 1407 { 1408 v.visit(this); 1409 } 1410 } 1411 1412 /*********************************************************** 1413 * The purpose of this is so that continue will go to the next 1414 * of the statements, and break will go to the end of the statements. 1415 */ 1416 extern (C++) final class UnrolledLoopStatement : Statement 1417 { 1418 Statements* statements; 1419 1420 extern (D) this(Loc loc, Statements* s) 1421 { 1422 super(loc); 1423 statements = s; 1424 } 1425 1426 override Statement syntaxCopy() 1427 { 1428 auto a = new Statements(); 1429 a.setDim(statements.dim); 1430 foreach (i, s; *statements) 1431 { 1432 (*a)[i] = s ? s.syntaxCopy() : null; 1433 } 1434 return new UnrolledLoopStatement(loc, a); 1435 } 1436 1437 override bool hasBreak() 1438 { 1439 return true; 1440 } 1441 1442 override bool hasContinue() 1443 { 1444 return true; 1445 } 1446 1447 override void accept(Visitor v) 1448 { 1449 v.visit(this); 1450 } 1451 } 1452 1453 /*********************************************************** 1454 */ 1455 extern (C++) final class ScopeStatement : Statement 1456 { 1457 Statement statement; 1458 Loc endloc; // location of closing curly bracket 1459 1460 extern (D) this(Loc loc, Statement s, Loc endloc) 1461 { 1462 super(loc); 1463 this.statement = s; 1464 this.endloc = endloc; 1465 } 1466 1467 override Statement syntaxCopy() 1468 { 1469 return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); 1470 } 1471 1472 override inout(ScopeStatement) isScopeStatement() inout nothrow pure 1473 { 1474 return this; 1475 } 1476 1477 override inout(ReturnStatement) isReturnStatement() inout nothrow pure 1478 { 1479 if (statement) 1480 return statement.isReturnStatement(); 1481 return null; 1482 } 1483 1484 override bool hasBreak() 1485 { 1486 //printf("ScopeStatement::hasBreak() %s\n", toChars()); 1487 return statement ? statement.hasBreak() : false; 1488 } 1489 1490 override bool hasContinue() 1491 { 1492 return statement ? statement.hasContinue() : false; 1493 } 1494 1495 override void accept(Visitor v) 1496 { 1497 v.visit(this); 1498 } 1499 } 1500 1501 /*********************************************************** 1502 */ 1503 extern (C++) final class WhileStatement : Statement 1504 { 1505 Expression condition; 1506 Statement _body; 1507 Loc endloc; // location of closing curly bracket 1508 1509 extern (D) this(Loc loc, Expression c, Statement b, Loc endloc) 1510 { 1511 super(loc); 1512 condition = c; 1513 _body = b; 1514 this.endloc = endloc; 1515 } 1516 1517 override Statement syntaxCopy() 1518 { 1519 return new WhileStatement(loc, 1520 condition.syntaxCopy(), 1521 _body ? _body.syntaxCopy() : null, 1522 endloc); 1523 } 1524 1525 override bool hasBreak() 1526 { 1527 return true; 1528 } 1529 1530 override bool hasContinue() 1531 { 1532 return true; 1533 } 1534 1535 override void accept(Visitor v) 1536 { 1537 v.visit(this); 1538 } 1539 } 1540 1541 /*********************************************************** 1542 */ 1543 extern (C++) final class DoStatement : Statement 1544 { 1545 Statement _body; 1546 Expression condition; 1547 Loc endloc; // location of ';' after while 1548 1549 extern (D) this(Loc loc, Statement b, Expression c, Loc endloc) 1550 { 1551 super(loc); 1552 _body = b; 1553 condition = c; 1554 this.endloc = endloc; 1555 } 1556 1557 override Statement syntaxCopy() 1558 { 1559 return new DoStatement(loc, 1560 _body ? _body.syntaxCopy() : null, 1561 condition.syntaxCopy(), 1562 endloc); 1563 } 1564 1565 override bool hasBreak() 1566 { 1567 return true; 1568 } 1569 1570 override bool hasContinue() 1571 { 1572 return true; 1573 } 1574 1575 override void accept(Visitor v) 1576 { 1577 v.visit(this); 1578 } 1579 } 1580 1581 /*********************************************************** 1582 */ 1583 extern (C++) final class ForStatement : Statement 1584 { 1585 Statement _init; 1586 Expression condition; 1587 Expression increment; 1588 Statement _body; 1589 Loc endloc; // location of closing curly bracket 1590 1591 // When wrapped in try/finally clauses, this points to the outermost one, 1592 // which may have an associated label. Internal break/continue statements 1593 // treat that label as referring to this loop. 1594 Statement relatedLabeled; 1595 1596 extern (D) this(Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) 1597 { 1598 super(loc); 1599 this._init = _init; 1600 this.condition = condition; 1601 this.increment = increment; 1602 this._body = _body; 1603 this.endloc = endloc; 1604 } 1605 1606 override Statement syntaxCopy() 1607 { 1608 return new ForStatement(loc, 1609 _init ? _init.syntaxCopy() : null, 1610 condition ? condition.syntaxCopy() : null, 1611 increment ? increment.syntaxCopy() : null, 1612 _body.syntaxCopy(), 1613 endloc); 1614 } 1615 1616 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 1617 { 1618 //printf("ForStatement::scopeCode()\n"); 1619 Statement.scopeCode(sc, sentry, sexception, sfinally); 1620 return this; 1621 } 1622 1623 override Statement getRelatedLabeled() 1624 { 1625 return relatedLabeled ? relatedLabeled : this; 1626 } 1627 1628 override bool hasBreak() 1629 { 1630 //printf("ForStatement::hasBreak()\n"); 1631 return true; 1632 } 1633 1634 override bool hasContinue() 1635 { 1636 return true; 1637 } 1638 1639 override void accept(Visitor v) 1640 { 1641 v.visit(this); 1642 } 1643 } 1644 1645 /*********************************************************** 1646 */ 1647 extern (C++) final class ForeachStatement : Statement 1648 { 1649 TOK op; // TOKforeach or TOKforeach_reverse 1650 Parameters* parameters; // array of Parameter*'s 1651 Expression aggr; 1652 Statement _body; 1653 Loc endloc; // location of closing curly bracket 1654 1655 VarDeclaration key; 1656 VarDeclaration value; 1657 1658 FuncDeclaration func; // function we're lexically in 1659 1660 Statements* cases; // put breaks, continues, gotos and returns here 1661 ScopeStatements* gotos; // forward referenced goto's go here 1662 1663 extern (D) this(Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) 1664 { 1665 super(loc); 1666 this.op = op; 1667 this.parameters = parameters; 1668 this.aggr = aggr; 1669 this._body = _body; 1670 this.endloc = endloc; 1671 } 1672 1673 override Statement syntaxCopy() 1674 { 1675 return new ForeachStatement(loc, op, 1676 Parameter.arraySyntaxCopy(parameters), 1677 aggr.syntaxCopy(), 1678 _body ? _body.syntaxCopy() : null, 1679 endloc); 1680 } 1681 1682 bool checkForArgTypes() 1683 { 1684 bool result = false; 1685 foreach (p; *parameters) 1686 { 1687 if (!p.type) 1688 { 1689 error("cannot infer type for %s", p.ident.toChars()); 1690 p.type = Type.terror; 1691 result = true; 1692 } 1693 } 1694 return result; 1695 } 1696 1697 override bool hasBreak() 1698 { 1699 return true; 1700 } 1701 1702 override bool hasContinue() 1703 { 1704 return true; 1705 } 1706 1707 override void accept(Visitor v) 1708 { 1709 v.visit(this); 1710 } 1711 } 1712 1713 /*********************************************************** 1714 */ 1715 extern (C++) final class ForeachRangeStatement : Statement 1716 { 1717 TOK op; // TOKforeach or TOKforeach_reverse 1718 Parameter prm; // loop index variable 1719 Expression lwr; 1720 Expression upr; 1721 Statement _body; 1722 Loc endloc; // location of closing curly bracket 1723 1724 VarDeclaration key; 1725 1726 extern (D) this(Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) 1727 { 1728 super(loc); 1729 this.op = op; 1730 this.prm = prm; 1731 this.lwr = lwr; 1732 this.upr = upr; 1733 this._body = _body; 1734 this.endloc = endloc; 1735 } 1736 1737 override Statement syntaxCopy() 1738 { 1739 return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 1740 } 1741 1742 override bool hasBreak() 1743 { 1744 return true; 1745 } 1746 1747 override bool hasContinue() 1748 { 1749 return true; 1750 } 1751 1752 override void accept(Visitor v) 1753 { 1754 v.visit(this); 1755 } 1756 } 1757 1758 /*********************************************************** 1759 */ 1760 extern (C++) final class IfStatement : Statement 1761 { 1762 Parameter prm; 1763 Expression condition; 1764 Statement ifbody; 1765 Statement elsebody; 1766 VarDeclaration match; // for MatchExpression results 1767 Loc endloc; // location of closing curly bracket 1768 1769 extern (D) this(Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) 1770 { 1771 super(loc); 1772 this.prm = prm; 1773 this.condition = condition; 1774 this.ifbody = ifbody; 1775 this.elsebody = elsebody; 1776 this.endloc = endloc; 1777 } 1778 1779 override Statement syntaxCopy() 1780 { 1781 return new IfStatement(loc, 1782 prm ? prm.syntaxCopy() : null, 1783 condition.syntaxCopy(), 1784 ifbody ? ifbody.syntaxCopy() : null, 1785 elsebody ? elsebody.syntaxCopy() : null, 1786 endloc); 1787 } 1788 1789 override IfStatement isIfStatement() 1790 { 1791 return this; 1792 } 1793 1794 override void accept(Visitor v) 1795 { 1796 v.visit(this); 1797 } 1798 } 1799 1800 /*********************************************************** 1801 */ 1802 extern (C++) final class ConditionalStatement : Statement 1803 { 1804 Condition condition; 1805 Statement ifbody; 1806 Statement elsebody; 1807 1808 extern (D) this(Loc loc, Condition condition, Statement ifbody, Statement elsebody) 1809 { 1810 super(loc); 1811 this.condition = condition; 1812 this.ifbody = ifbody; 1813 this.elsebody = elsebody; 1814 } 1815 1816 override Statement syntaxCopy() 1817 { 1818 return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); 1819 } 1820 1821 override Statements* flatten(Scope* sc) 1822 { 1823 Statement s; 1824 1825 //printf("ConditionalStatement::flatten()\n"); 1826 if (condition.include(sc, null)) 1827 { 1828 DebugCondition dc = condition.isDebugCondition(); 1829 if (dc) 1830 s = new DebugStatement(loc, ifbody); 1831 else 1832 s = ifbody; 1833 } 1834 else 1835 s = elsebody; 1836 1837 auto a = new Statements(); 1838 a.push(s); 1839 return a; 1840 } 1841 1842 override void accept(Visitor v) 1843 { 1844 v.visit(this); 1845 } 1846 } 1847 1848 /*********************************************************** 1849 */ 1850 extern (C++) final class PragmaStatement : Statement 1851 { 1852 Identifier ident; 1853 Expressions* args; // array of Expression's 1854 Statement _body; 1855 1856 extern (D) this(Loc loc, Identifier ident, Expressions* args, Statement _body) 1857 { 1858 super(loc); 1859 this.ident = ident; 1860 this.args = args; 1861 this._body = _body; 1862 } 1863 1864 override Statement syntaxCopy() 1865 { 1866 return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); 1867 } 1868 1869 override void accept(Visitor v) 1870 { 1871 v.visit(this); 1872 } 1873 } 1874 1875 /*********************************************************** 1876 */ 1877 extern (C++) final class StaticAssertStatement : Statement 1878 { 1879 StaticAssert sa; 1880 1881 extern (D) this(StaticAssert sa) 1882 { 1883 super(sa.loc); 1884 this.sa = sa; 1885 } 1886 1887 override Statement syntaxCopy() 1888 { 1889 return new StaticAssertStatement(cast(StaticAssert)sa.syntaxCopy(null)); 1890 } 1891 1892 override void accept(Visitor v) 1893 { 1894 v.visit(this); 1895 } 1896 } 1897 1898 /*********************************************************** 1899 */ 1900 extern (C++) final class SwitchStatement : Statement 1901 { 1902 Expression condition; 1903 Statement _body; 1904 bool isFinal; 1905 1906 DefaultStatement sdefault; 1907 TryFinallyStatement tf; 1908 GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's 1909 CaseStatements* cases; // array of CaseStatement's 1910 int hasNoDefault; // !=0 if no default statement 1911 int hasVars; // !=0 if has variable case values 1912 VarDeclaration lastVar; 1913 1914 extern (D) this(Loc loc, Expression c, Statement b, bool isFinal) 1915 { 1916 super(loc); 1917 this.condition = c; 1918 this._body = b; 1919 this.isFinal = isFinal; 1920 } 1921 1922 override Statement syntaxCopy() 1923 { 1924 return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal); 1925 } 1926 1927 override bool hasBreak() 1928 { 1929 return true; 1930 } 1931 1932 final bool checkLabel() 1933 { 1934 bool checkVar(VarDeclaration vd) 1935 { 1936 if (!vd || vd.isDataseg() || (vd.storage_class & STCmanifest)) 1937 return false; 1938 1939 VarDeclaration last = lastVar; 1940 while (last && last != vd) 1941 last = last.lastVar; 1942 if (last == vd) 1943 { 1944 // All good, the label's scope has no variables 1945 } 1946 else if (vd.ident == Id.withSym) 1947 { 1948 deprecation("'switch' skips declaration of 'with' temporary at %s", vd.loc.toChars()); 1949 return true; 1950 } 1951 else 1952 { 1953 deprecation("'switch' skips declaration of variable %s at %s", vd.toPrettyChars(), vd.loc.toChars()); 1954 return true; 1955 } 1956 1957 return false; 1958 } 1959 1960 enum error = true; 1961 1962 if (sdefault && checkVar(sdefault.lastVar)) 1963 return !error; // return error once fully deprecated 1964 1965 foreach (scase; *cases) 1966 { 1967 if (scase && checkVar(scase.lastVar)) 1968 return !error; // return error once fully deprecated 1969 } 1970 return !error; 1971 } 1972 1973 override void accept(Visitor v) 1974 { 1975 v.visit(this); 1976 } 1977 } 1978 1979 /*********************************************************** 1980 */ 1981 extern (C++) final class CaseStatement : Statement 1982 { 1983 Expression exp; 1984 Statement statement; 1985 int index; // which case it is (since we sort this) 1986 VarDeclaration lastVar; 1987 1988 extern (D) this(Loc loc, Expression exp, Statement s) 1989 { 1990 super(loc); 1991 this.exp = exp; 1992 this.statement = s; 1993 } 1994 1995 override Statement syntaxCopy() 1996 { 1997 return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); 1998 } 1999 2000 override int compare(RootObject obj) 2001 { 2002 // Sort cases so we can do an efficient lookup 2003 CaseStatement cs2 = cast(CaseStatement)obj; 2004 return exp.compare(cs2.exp); 2005 } 2006 2007 override CaseStatement isCaseStatement() 2008 { 2009 return this; 2010 } 2011 2012 override void accept(Visitor v) 2013 { 2014 v.visit(this); 2015 } 2016 } 2017 2018 /*********************************************************** 2019 */ 2020 extern (C++) final class CaseRangeStatement : Statement 2021 { 2022 Expression first; 2023 Expression last; 2024 Statement statement; 2025 2026 extern (D) this(Loc loc, Expression first, Expression last, Statement s) 2027 { 2028 super(loc); 2029 this.first = first; 2030 this.last = last; 2031 this.statement = s; 2032 } 2033 2034 override Statement syntaxCopy() 2035 { 2036 return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); 2037 } 2038 2039 override void accept(Visitor v) 2040 { 2041 v.visit(this); 2042 } 2043 } 2044 2045 /*********************************************************** 2046 */ 2047 extern (C++) final class DefaultStatement : Statement 2048 { 2049 Statement statement; 2050 VarDeclaration lastVar; 2051 2052 extern (D) this(Loc loc, Statement s) 2053 { 2054 super(loc); 2055 this.statement = s; 2056 } 2057 2058 override Statement syntaxCopy() 2059 { 2060 return new DefaultStatement(loc, statement.syntaxCopy()); 2061 } 2062 2063 override DefaultStatement isDefaultStatement() 2064 { 2065 return this; 2066 } 2067 2068 override void accept(Visitor v) 2069 { 2070 v.visit(this); 2071 } 2072 } 2073 2074 /*********************************************************** 2075 */ 2076 extern (C++) final class GotoDefaultStatement : Statement 2077 { 2078 SwitchStatement sw; 2079 2080 extern (D) this(Loc loc) 2081 { 2082 super(loc); 2083 } 2084 2085 override Statement syntaxCopy() 2086 { 2087 return new GotoDefaultStatement(loc); 2088 } 2089 2090 override GotoDefaultStatement isGotoDefaultStatement() pure 2091 { 2092 return this; 2093 } 2094 2095 override void accept(Visitor v) 2096 { 2097 v.visit(this); 2098 } 2099 } 2100 2101 /*********************************************************** 2102 */ 2103 extern (C++) final class GotoCaseStatement : Statement 2104 { 2105 Expression exp; // null, or which case to goto 2106 CaseStatement cs; // case statement it resolves to 2107 2108 extern (D) this(Loc loc, Expression exp) 2109 { 2110 super(loc); 2111 this.exp = exp; 2112 } 2113 2114 override Statement syntaxCopy() 2115 { 2116 return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); 2117 } 2118 2119 override GotoCaseStatement isGotoCaseStatement() pure 2120 { 2121 return this; 2122 } 2123 2124 override void accept(Visitor v) 2125 { 2126 v.visit(this); 2127 } 2128 } 2129 2130 /*********************************************************** 2131 */ 2132 extern (C++) final class SwitchErrorStatement : Statement 2133 { 2134 extern (D) this(Loc loc) 2135 { 2136 super(loc); 2137 } 2138 2139 override void accept(Visitor v) 2140 { 2141 v.visit(this); 2142 } 2143 } 2144 2145 /*********************************************************** 2146 */ 2147 extern (C++) final class ReturnStatement : Statement 2148 { 2149 Expression exp; 2150 size_t caseDim; 2151 2152 extern (D) this(Loc loc, Expression exp) 2153 { 2154 super(loc); 2155 this.exp = exp; 2156 } 2157 2158 override Statement syntaxCopy() 2159 { 2160 return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); 2161 } 2162 2163 override inout(ReturnStatement) isReturnStatement() inout nothrow pure 2164 { 2165 return this; 2166 } 2167 2168 override void accept(Visitor v) 2169 { 2170 v.visit(this); 2171 } 2172 } 2173 2174 /*********************************************************** 2175 */ 2176 extern (C++) final class BreakStatement : Statement 2177 { 2178 Identifier ident; 2179 2180 extern (D) this(Loc loc, Identifier ident) 2181 { 2182 super(loc); 2183 this.ident = ident; 2184 } 2185 2186 override Statement syntaxCopy() 2187 { 2188 return new BreakStatement(loc, ident); 2189 } 2190 2191 override inout(BreakStatement) isBreakStatement() inout nothrow pure 2192 { 2193 return this; 2194 } 2195 2196 override void accept(Visitor v) 2197 { 2198 v.visit(this); 2199 } 2200 } 2201 2202 /*********************************************************** 2203 */ 2204 extern (C++) final class ContinueStatement : Statement 2205 { 2206 Identifier ident; 2207 2208 extern (D) this(Loc loc, Identifier ident) 2209 { 2210 super(loc); 2211 this.ident = ident; 2212 } 2213 2214 override Statement syntaxCopy() 2215 { 2216 return new ContinueStatement(loc, ident); 2217 } 2218 2219 override void accept(Visitor v) 2220 { 2221 v.visit(this); 2222 } 2223 } 2224 2225 /*********************************************************** 2226 */ 2227 extern (C++) final class SynchronizedStatement : Statement 2228 { 2229 Expression exp; 2230 Statement _body; 2231 2232 extern (D) this(Loc loc, Expression exp, Statement _body) 2233 { 2234 super(loc); 2235 this.exp = exp; 2236 this._body = _body; 2237 } 2238 2239 override Statement syntaxCopy() 2240 { 2241 return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); 2242 } 2243 2244 override bool hasBreak() 2245 { 2246 return false; //true; 2247 } 2248 2249 override bool hasContinue() 2250 { 2251 return false; //true; 2252 } 2253 2254 override void accept(Visitor v) 2255 { 2256 v.visit(this); 2257 } 2258 } 2259 2260 /*********************************************************** 2261 */ 2262 extern (C++) final class WithStatement : Statement 2263 { 2264 Expression exp; 2265 Statement _body; 2266 VarDeclaration wthis; 2267 Loc endloc; 2268 2269 extern (D) this(Loc loc, Expression exp, Statement _body, Loc endloc) 2270 { 2271 super(loc); 2272 this.exp = exp; 2273 this._body = _body; 2274 this.endloc = endloc; 2275 } 2276 2277 override Statement syntaxCopy() 2278 { 2279 return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 2280 } 2281 2282 override void accept(Visitor v) 2283 { 2284 v.visit(this); 2285 } 2286 } 2287 2288 /*********************************************************** 2289 */ 2290 extern (C++) final class TryCatchStatement : Statement 2291 { 2292 Statement _body; 2293 Catches* catches; 2294 2295 extern (D) this(Loc loc, Statement _body, Catches* catches) 2296 { 2297 super(loc); 2298 this._body = _body; 2299 this.catches = catches; 2300 } 2301 2302 override Statement syntaxCopy() 2303 { 2304 auto a = new Catches(); 2305 a.setDim(catches.dim); 2306 foreach (i, c; *catches) 2307 { 2308 (*a)[i] = c.syntaxCopy(); 2309 } 2310 return new TryCatchStatement(loc, _body.syntaxCopy(), a); 2311 } 2312 2313 override bool hasBreak() 2314 { 2315 return false; 2316 } 2317 2318 override void accept(Visitor v) 2319 { 2320 v.visit(this); 2321 } 2322 } 2323 2324 /*********************************************************** 2325 */ 2326 extern (C++) final class Catch : RootObject 2327 { 2328 Loc loc; 2329 Type type; 2330 Identifier ident; 2331 VarDeclaration var; 2332 Statement handler; 2333 2334 bool errors; // set if semantic processing errors 2335 2336 // was generated by the compiler, wasn't present in source code 2337 bool internalCatch; 2338 2339 extern (D) this(Loc loc, Type t, Identifier id, Statement handler) 2340 { 2341 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); 2342 this.loc = loc; 2343 this.type = t; 2344 this.ident = id; 2345 this.handler = handler; 2346 } 2347 2348 Catch syntaxCopy() 2349 { 2350 auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); 2351 c.internalCatch = internalCatch; 2352 return c; 2353 } 2354 } 2355 2356 /*********************************************************** 2357 */ 2358 extern (C++) final class TryFinallyStatement : Statement 2359 { 2360 Statement _body; 2361 Statement finalbody; 2362 2363 extern (D) this(Loc loc, Statement _body, Statement finalbody) 2364 { 2365 super(loc); 2366 this._body = _body; 2367 this.finalbody = finalbody; 2368 } 2369 2370 static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody) 2371 { 2372 return new TryFinallyStatement(loc, _body, finalbody); 2373 } 2374 2375 override Statement syntaxCopy() 2376 { 2377 return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); 2378 } 2379 2380 override bool hasBreak() 2381 { 2382 return false; //true; 2383 } 2384 2385 override bool hasContinue() 2386 { 2387 return false; //true; 2388 } 2389 2390 override void accept(Visitor v) 2391 { 2392 v.visit(this); 2393 } 2394 } 2395 2396 /*********************************************************** 2397 */ 2398 extern (C++) final class OnScopeStatement : Statement 2399 { 2400 TOK tok; 2401 Statement statement; 2402 2403 extern (D) this(Loc loc, TOK tok, Statement statement) 2404 { 2405 super(loc); 2406 this.tok = tok; 2407 this.statement = statement; 2408 } 2409 2410 override Statement syntaxCopy() 2411 { 2412 return new OnScopeStatement(loc, tok, statement.syntaxCopy()); 2413 } 2414 2415 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 2416 { 2417 //printf("OnScopeStatement::scopeCode()\n"); 2418 //print(); 2419 *sentry = null; 2420 *sexception = null; 2421 *sfinally = null; 2422 2423 Statement s = new PeelStatement(statement); 2424 2425 switch (tok) 2426 { 2427 case TOKon_scope_exit: 2428 *sfinally = s; 2429 break; 2430 2431 case TOKon_scope_failure: 2432 *sexception = s; 2433 break; 2434 2435 case TOKon_scope_success: 2436 { 2437 /* Create: 2438 * sentry: bool x = false; 2439 * sexception: x = true; 2440 * sfinally: if (!x) statement; 2441 */ 2442 auto v = copyToTemp(0, "__os", new IntegerExp(Loc(), 0, Type.tbool)); 2443 *sentry = new ExpStatement(loc, v); 2444 2445 Expression e = new IntegerExp(Loc(), 1, Type.tbool); 2446 e = new AssignExp(Loc(), new VarExp(Loc(), v), e); 2447 *sexception = new ExpStatement(Loc(), e); 2448 2449 e = new VarExp(Loc(), v); 2450 e = new NotExp(Loc(), e); 2451 *sfinally = new IfStatement(Loc(), null, e, s, null, Loc()); 2452 2453 break; 2454 } 2455 default: 2456 assert(0); 2457 } 2458 return null; 2459 } 2460 2461 override void accept(Visitor v) 2462 { 2463 v.visit(this); 2464 } 2465 } 2466 2467 /*********************************************************** 2468 */ 2469 extern (C++) final class ThrowStatement : Statement 2470 { 2471 Expression exp; 2472 2473 // was generated by the compiler, wasn't present in source code 2474 bool internalThrow; 2475 2476 extern (D) this(Loc loc, Expression exp) 2477 { 2478 super(loc); 2479 this.exp = exp; 2480 } 2481 2482 override Statement syntaxCopy() 2483 { 2484 auto s = new ThrowStatement(loc, exp.syntaxCopy()); 2485 s.internalThrow = internalThrow; 2486 return s; 2487 } 2488 2489 override void accept(Visitor v) 2490 { 2491 v.visit(this); 2492 } 2493 } 2494 2495 /*********************************************************** 2496 */ 2497 extern (C++) final class DebugStatement : Statement 2498 { 2499 Statement statement; 2500 2501 extern (D) this(Loc loc, Statement statement) 2502 { 2503 super(loc); 2504 this.statement = statement; 2505 } 2506 2507 override Statement syntaxCopy() 2508 { 2509 return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); 2510 } 2511 2512 override Statements* flatten(Scope* sc) 2513 { 2514 Statements* a = statement ? statement.flatten(sc) : null; 2515 if (a) 2516 { 2517 foreach (ref s; *a) 2518 { 2519 s = new DebugStatement(loc, s); 2520 } 2521 } 2522 return a; 2523 } 2524 2525 override void accept(Visitor v) 2526 { 2527 v.visit(this); 2528 } 2529 } 2530 2531 /*********************************************************** 2532 */ 2533 extern (C++) final class GotoStatement : Statement 2534 { 2535 Identifier ident; 2536 LabelDsymbol label; 2537 TryFinallyStatement tf; 2538 OnScopeStatement os; 2539 VarDeclaration lastVar; 2540 2541 extern (D) this(Loc loc, Identifier ident) 2542 { 2543 super(loc); 2544 this.ident = ident; 2545 } 2546 2547 override Statement syntaxCopy() 2548 { 2549 return new GotoStatement(loc, ident); 2550 } 2551 2552 final bool checkLabel() 2553 { 2554 if (!label.statement) 2555 { 2556 error("label '%s' is undefined", label.toChars()); 2557 return true; 2558 } 2559 2560 if (label.statement.os != os) 2561 { 2562 if (os && os.tok == TOKon_scope_failure && !label.statement.os) 2563 { 2564 // Jump out from scope(failure) block is allowed. 2565 } 2566 else 2567 { 2568 if (label.statement.os) 2569 error("cannot goto in to %s block", Token.toChars(label.statement.os.tok)); 2570 else 2571 error("cannot goto out of %s block", Token.toChars(os.tok)); 2572 return true; 2573 } 2574 } 2575 2576 if (label.statement.tf != tf) 2577 { 2578 error("cannot goto in or out of finally block"); 2579 return true; 2580 } 2581 2582 VarDeclaration vd = label.statement.lastVar; 2583 if (!vd || vd.isDataseg() || (vd.storage_class & STCmanifest)) 2584 return false; 2585 2586 VarDeclaration last = lastVar; 2587 while (last && last != vd) 2588 last = last.lastVar; 2589 if (last == vd) 2590 { 2591 // All good, the label's scope has no variables 2592 } 2593 else if (vd.storage_class & STCexptemp) 2594 { 2595 // Lifetime ends at end of expression, so no issue with skipping the statement 2596 } 2597 else if (vd.ident == Id.withSym) 2598 { 2599 error("goto skips declaration of with temporary at %s", vd.loc.toChars()); 2600 return true; 2601 } 2602 else 2603 { 2604 error("goto skips declaration of variable %s at %s", vd.toPrettyChars(), vd.loc.toChars()); 2605 return true; 2606 } 2607 2608 return false; 2609 } 2610 2611 override void accept(Visitor v) 2612 { 2613 v.visit(this); 2614 } 2615 } 2616 2617 /*********************************************************** 2618 */ 2619 extern (C++) final class LabelStatement : Statement 2620 { 2621 Identifier ident; 2622 Statement statement; 2623 TryFinallyStatement tf; 2624 OnScopeStatement os; 2625 VarDeclaration lastVar; 2626 Statement gotoTarget; // interpret 2627 bool breaks; // someone did a 'break ident' 2628 2629 extern (D) this(Loc loc, Identifier ident, Statement statement) 2630 { 2631 super(loc); 2632 this.ident = ident; 2633 this.statement = statement; 2634 } 2635 2636 override Statement syntaxCopy() 2637 { 2638 return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); 2639 } 2640 2641 override Statements* flatten(Scope* sc) 2642 { 2643 Statements* a = null; 2644 if (statement) 2645 { 2646 a = statement.flatten(sc); 2647 if (a) 2648 { 2649 if (!a.dim) 2650 { 2651 a.push(new ExpStatement(loc, cast(Expression)null)); 2652 } 2653 2654 // reuse 'this' LabelStatement 2655 this.statement = (*a)[0]; 2656 (*a)[0] = this; 2657 } 2658 } 2659 return a; 2660 } 2661 2662 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexit, Statement* sfinally) 2663 { 2664 //printf("LabelStatement::scopeCode()\n"); 2665 if (statement) 2666 statement = statement.scopeCode(sc, sentry, sexit, sfinally); 2667 else 2668 { 2669 *sentry = null; 2670 *sexit = null; 2671 *sfinally = null; 2672 } 2673 return this; 2674 } 2675 2676 override LabelStatement isLabelStatement() 2677 { 2678 return this; 2679 } 2680 2681 override void accept(Visitor v) 2682 { 2683 v.visit(this); 2684 } 2685 } 2686 2687 /*********************************************************** 2688 */ 2689 extern (C++) final class LabelDsymbol : Dsymbol 2690 { 2691 LabelStatement statement; 2692 2693 extern (D) this(Identifier ident) 2694 { 2695 super(ident); 2696 } 2697 2698 static LabelDsymbol create(Identifier ident) 2699 { 2700 return new LabelDsymbol(ident); 2701 } 2702 2703 // is this a LabelDsymbol()? 2704 override LabelDsymbol isLabel() 2705 { 2706 return this; 2707 } 2708 2709 override void accept(Visitor v) 2710 { 2711 v.visit(this); 2712 } 2713 } 2714 2715 /*********************************************************** 2716 */ 2717 extern (C++) final class AsmStatement : Statement 2718 { 2719 Token* tokens; 2720 code* asmcode; 2721 uint asmalign; // alignment of this statement 2722 uint regs; // mask of registers modified (must match regm_t in back end) 2723 bool refparam; // true if function parameter is referenced 2724 bool naked; // true if function is to be naked 2725 2726 extern (D) this(Loc loc, Token* tokens) 2727 { 2728 super(loc); 2729 this.tokens = tokens; 2730 } 2731 2732 override Statement syntaxCopy() 2733 { 2734 return new AsmStatement(loc, tokens); 2735 } 2736 2737 override void accept(Visitor v) 2738 { 2739 v.visit(this); 2740 } 2741 } 2742 2743 /*********************************************************** 2744 * a complete asm {} block 2745 */ 2746 extern (C++) final class CompoundAsmStatement : CompoundStatement 2747 { 2748 StorageClass stc; // postfix attributes like nothrow/pure/@trusted 2749 2750 extern (D) this(Loc loc, Statements* s, StorageClass stc) 2751 { 2752 super(loc, s); 2753 this.stc = stc; 2754 } 2755 2756 override CompoundAsmStatement syntaxCopy() 2757 { 2758 auto a = new Statements(); 2759 a.setDim(statements.dim); 2760 foreach (i, s; *statements) 2761 { 2762 (*a)[i] = s ? s.syntaxCopy() : null; 2763 } 2764 return new CompoundAsmStatement(loc, a, stc); 2765 } 2766 2767 override Statements* flatten(Scope* sc) 2768 { 2769 return null; 2770 } 2771 2772 override void accept(Visitor v) 2773 { 2774 v.visit(this); 2775 } 2776 } 2777 2778 /*********************************************************** 2779 */ 2780 extern (C++) final class ImportStatement : Statement 2781 { 2782 Dsymbols* imports; // Array of Import's 2783 2784 extern (D) this(Loc loc, Dsymbols* imports) 2785 { 2786 super(loc); 2787 this.imports = imports; 2788 } 2789 2790 override Statement syntaxCopy() 2791 { 2792 auto m = new Dsymbols(); 2793 m.setDim(imports.dim); 2794 foreach (i, s; *imports) 2795 { 2796 (*m)[i] = s.syntaxCopy(null); 2797 } 2798 return new ImportStatement(loc, m); 2799 } 2800 2801 override void accept(Visitor v) 2802 { 2803 v.visit(this); 2804 } 2805 }