1 /** 2 * Defines AST nodes for statements. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) 10 * Documentation: https://dlang.org/phobos/dmd_statement.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d 12 */ 13 14 module dmd.statement; 15 16 import core.stdc.stdarg; 17 import core.stdc.stdio; 18 19 import dmd.aggregate; 20 import dmd.arraytypes; 21 import dmd.astenums; 22 import dmd.ast_node; 23 import dmd.gluelayer; 24 import dmd.cond; 25 import dmd.dclass; 26 import dmd.declaration; 27 import dmd.denum; 28 import dmd.dimport; 29 import dmd.dscope; 30 import dmd.dsymbol; 31 import dmd.dtemplate; 32 import dmd.errors; 33 import dmd.expression; 34 import dmd.func; 35 import dmd.globals; 36 import dmd.hdrgen; 37 import dmd.id; 38 import dmd.identifier; 39 import dmd.location; 40 import dmd.dinterpret; 41 import dmd.mtype; 42 import dmd.common.outbuffer; 43 import dmd.root.rootobject; 44 import dmd.sapply; 45 import dmd.sideeffect; 46 import dmd.staticassert; 47 import dmd.tokens; 48 import dmd.visitor; 49 50 /** 51 * Returns: 52 * `TypeIdentifier` corresponding to `object.Throwable` 53 */ 54 TypeIdentifier getThrowable() 55 { 56 auto tid = new TypeIdentifier(Loc.initial, Id.empty); 57 tid.addIdent(Id.object); 58 tid.addIdent(Id.Throwable); 59 return tid; 60 } 61 62 /** 63 * Returns: 64 * TypeIdentifier corresponding to `object.Exception` 65 */ 66 TypeIdentifier getException() 67 { 68 auto tid = new TypeIdentifier(Loc.initial, Id.empty); 69 tid.addIdent(Id.object); 70 tid.addIdent(Id.Exception); 71 return tid; 72 } 73 74 /*********************************************************** 75 * Specification: https://dlang.org/spec/statement.html 76 */ 77 extern (C++) abstract class Statement : ASTNode 78 { 79 const Loc loc; 80 const STMT stmt; 81 82 override final DYNCAST dyncast() const 83 { 84 return DYNCAST.statement; 85 } 86 87 final extern (D) this(const ref Loc loc, STMT stmt) 88 { 89 this.loc = loc; 90 this.stmt = stmt; 91 // If this is an in{} contract scope statement (skip for determining 92 // inlineStatus of a function body for header content) 93 } 94 95 Statement syntaxCopy() 96 { 97 assert(0); 98 } 99 100 /************************************* 101 * Do syntax copy of an array of Statement's. 102 */ 103 static Statements* arraySyntaxCopy(Statements* a) 104 { 105 Statements* b = null; 106 if (a) 107 { 108 b = a.copy(); 109 foreach (i, s; *a) 110 { 111 (*b)[i] = s ? s.syntaxCopy() : null; 112 } 113 } 114 return b; 115 } 116 117 override final const(char)* toChars() const 118 { 119 HdrGenState hgs; 120 OutBuffer buf; 121 .toCBuffer(this, &buf, &hgs); 122 buf.writeByte(0); 123 return buf.extractSlice().ptr; 124 } 125 126 static if (__VERSION__ < 2092) 127 { 128 final void error(const(char)* format, ...) 129 { 130 va_list ap; 131 va_start(ap, format); 132 .verror(loc, format, ap); 133 va_end(ap); 134 } 135 136 final void warning(const(char)* format, ...) 137 { 138 va_list ap; 139 va_start(ap, format); 140 .vwarning(loc, format, ap); 141 va_end(ap); 142 } 143 144 final void deprecation(const(char)* format, ...) 145 { 146 va_list ap; 147 va_start(ap, format); 148 .vdeprecation(loc, format, ap); 149 va_end(ap); 150 } 151 } 152 else 153 { 154 pragma(printf) final void error(const(char)* format, ...) 155 { 156 va_list ap; 157 va_start(ap, format); 158 .verror(loc, format, ap); 159 va_end(ap); 160 } 161 162 pragma(printf) final void warning(const(char)* format, ...) 163 { 164 va_list ap; 165 va_start(ap, format); 166 .vwarning(loc, format, ap); 167 va_end(ap); 168 } 169 170 pragma(printf) final void deprecation(const(char)* format, ...) 171 { 172 va_list ap; 173 va_start(ap, format); 174 .vdeprecation(loc, format, ap); 175 va_end(ap); 176 } 177 } 178 179 Statement getRelatedLabeled() 180 { 181 return this; 182 } 183 184 /**************************** 185 * Determine if an enclosed `break` would apply to this 186 * statement, such as if it is a loop or switch statement. 187 * Returns: 188 * `true` if it does 189 */ 190 bool hasBreak() const pure nothrow 191 { 192 //printf("Statement::hasBreak()\n"); 193 return false; 194 } 195 196 /**************************** 197 * Determine if an enclosed `continue` would apply to this 198 * statement, such as if it is a loop statement. 199 * Returns: 200 * `true` if it does 201 */ 202 bool hasContinue() const pure nothrow 203 { 204 return false; 205 } 206 207 /********************************** 208 * Returns: 209 * `true` if statement uses exception handling 210 */ 211 final bool usesEH() 212 { 213 extern (C++) final class UsesEH : StoppableVisitor 214 { 215 alias visit = typeof(super).visit; 216 public: 217 override void visit(Statement s) 218 { 219 } 220 221 override void visit(TryCatchStatement s) 222 { 223 stop = true; 224 } 225 226 override void visit(TryFinallyStatement s) 227 { 228 stop = true; 229 } 230 231 override void visit(ScopeGuardStatement s) 232 { 233 stop = true; 234 } 235 236 override void visit(SynchronizedStatement s) 237 { 238 stop = true; 239 } 240 } 241 242 scope UsesEH ueh = new UsesEH(); 243 return walkPostorder(this, ueh); 244 } 245 246 /********************************** 247 * Returns: 248 * `true` if statement 'comes from' somewhere else, like a goto 249 */ 250 final bool comeFrom() 251 { 252 extern (C++) final class ComeFrom : StoppableVisitor 253 { 254 alias visit = typeof(super).visit; 255 public: 256 override void visit(Statement s) 257 { 258 } 259 260 override void visit(CaseStatement s) 261 { 262 stop = true; 263 } 264 265 override void visit(DefaultStatement s) 266 { 267 stop = true; 268 } 269 270 override void visit(LabelStatement s) 271 { 272 stop = true; 273 } 274 275 override void visit(AsmStatement s) 276 { 277 stop = true; 278 } 279 } 280 281 scope ComeFrom cf = new ComeFrom(); 282 return walkPostorder(this, cf); 283 } 284 285 /********************************** 286 * Returns: 287 * `true` if statement has executable code. 288 */ 289 final bool hasCode() 290 { 291 extern (C++) final class HasCode : StoppableVisitor 292 { 293 alias visit = typeof(super).visit; 294 public: 295 override void visit(Statement s) 296 { 297 stop = true; 298 } 299 300 override void visit(ExpStatement s) 301 { 302 if (s.exp !is null) 303 { 304 stop = s.exp.hasCode(); 305 } 306 } 307 308 override void visit(CompoundStatement s) 309 { 310 } 311 312 override void visit(ScopeStatement s) 313 { 314 } 315 316 override void visit(ImportStatement s) 317 { 318 } 319 320 override void visit(CaseStatement s) 321 { 322 } 323 324 override void visit(DefaultStatement s) 325 { 326 } 327 328 override void visit(LabelStatement s) 329 { 330 } 331 } 332 333 scope HasCode hc = new HasCode(); 334 return walkPostorder(this, hc); 335 } 336 337 /******************************* 338 * Find last statement in a sequence of statements. 339 * Returns: 340 * the last statement, or `null` if there isn't one 341 */ 342 inout(Statement) last() inout nothrow pure 343 { 344 return this; 345 } 346 347 /************************** 348 * Support Visitor Pattern 349 * Params: 350 * v = visitor 351 */ 352 override void accept(Visitor v) 353 { 354 v.visit(this); 355 } 356 357 /************************************ 358 * Does this statement end with a return statement? 359 * 360 * I.e. is it a single return statement or some compound statement 361 * that unconditionally hits a return statement. 362 * Returns: 363 * return statement it ends with, otherwise null 364 */ 365 pure nothrow @nogc 366 inout(ReturnStatement) endsWithReturnStatement() inout { return null; } 367 368 final pure inout nothrow @nogc @safe: 369 370 /******************** 371 * A cheaper method of doing downcasting of Statements. 372 * Returns: 373 * the downcast statement if it can be downcasted, otherwise `null` 374 */ 375 inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } 376 inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } 377 inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } 378 inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } 379 inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } 380 inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } 381 inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } 382 inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; } 383 inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; } 384 inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } 385 inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } 386 inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } 387 inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } 388 inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } 389 inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } 390 inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } 391 inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } 392 inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } 393 inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } 394 inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } 395 inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } 396 inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } 397 inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } 398 inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } 399 inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } 400 inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } 401 inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } 402 inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } 403 inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; } 404 inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } 405 inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; } 406 inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } 407 inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } 408 inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } 409 inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } 410 inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } 411 inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } 412 inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } 413 inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } 414 inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } 415 inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } 416 inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } 417 inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } 418 inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } 419 } 420 421 /*********************************************************** 422 * Any Statement that fails semantic() or has a component that is an ErrorExp or 423 * a TypeError should return an ErrorStatement from semantic(). 424 */ 425 extern (C++) final class ErrorStatement : Statement 426 { 427 extern (D) this() 428 { 429 super(Loc.initial, STMT.Error); 430 assert(global.gaggedErrors || global.errors); 431 } 432 433 override ErrorStatement syntaxCopy() 434 { 435 return this; 436 } 437 438 override void accept(Visitor v) 439 { 440 v.visit(this); 441 } 442 } 443 444 /*********************************************************** 445 */ 446 extern (C++) final class PeelStatement : Statement 447 { 448 Statement s; 449 450 extern (D) this(Statement s) 451 { 452 super(s.loc, STMT.Peel); 453 this.s = s; 454 } 455 456 override void accept(Visitor v) 457 { 458 v.visit(this); 459 } 460 } 461 462 463 /*********************************************************** 464 * https://dlang.org/spec/statement.html#ExpressionStatement 465 */ 466 extern (C++) class ExpStatement : Statement 467 { 468 Expression exp; 469 470 final extern (D) this(const ref Loc loc, Expression exp) 471 { 472 super(loc, STMT.Exp); 473 this.exp = exp; 474 } 475 476 final extern (D) this(const ref Loc loc, Expression exp, STMT stmt) 477 { 478 super(loc, stmt); 479 this.exp = exp; 480 } 481 482 final extern (D) this(const ref Loc loc, Dsymbol declaration) 483 { 484 super(loc, STMT.Exp); 485 this.exp = new DeclarationExp(loc, declaration); 486 } 487 488 static ExpStatement create(const ref Loc loc, Expression exp) 489 { 490 return new ExpStatement(loc, exp); 491 } 492 493 override ExpStatement syntaxCopy() 494 { 495 return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); 496 } 497 498 override void accept(Visitor v) 499 { 500 v.visit(this); 501 } 502 } 503 504 /*********************************************************** 505 */ 506 extern (C++) final class DtorExpStatement : ExpStatement 507 { 508 // Wraps an expression that is the destruction of 'var' 509 VarDeclaration var; 510 511 extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var) 512 { 513 super(loc, exp, STMT.DtorExp); 514 this.var = var; 515 } 516 517 override DtorExpStatement syntaxCopy() 518 { 519 return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); 520 } 521 522 override void accept(Visitor v) 523 { 524 v.visit(this); 525 } 526 } 527 528 /*********************************************************** 529 * https://dlang.org/spec/statement.html#mixin-statement 530 */ 531 // Note: was called CompileStatement 532 extern (C++) final class MixinStatement : Statement 533 { 534 Expressions* exps; 535 536 extern (D) this(const ref Loc loc, Expression exp) 537 { 538 Expressions* exps = new Expressions(); 539 exps.push(exp); 540 this(loc, exps); 541 } 542 543 extern (D) this(const ref Loc loc, Expressions* exps) 544 { 545 super(loc, STMT.Mixin); 546 this.exps = exps; 547 } 548 549 override MixinStatement syntaxCopy() 550 { 551 return new MixinStatement(loc, Expression.arraySyntaxCopy(exps)); 552 } 553 554 override void accept(Visitor v) 555 { 556 v.visit(this); 557 } 558 } 559 560 /*********************************************************** 561 */ 562 extern (C++) class CompoundStatement : Statement 563 { 564 Statements* statements; 565 566 /** 567 * Construct a `CompoundStatement` using an already existing 568 * array of `Statement`s 569 * 570 * Params: 571 * loc = Instantiation information 572 * statements = An array of `Statement`s, that will referenced by this class 573 */ 574 final extern (D) this(const ref Loc loc, Statements* statements) 575 { 576 super(loc, STMT.Compound); 577 this.statements = statements; 578 } 579 580 final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt) 581 { 582 super(loc, stmt); 583 this.statements = statements; 584 } 585 586 /** 587 * Construct a `CompoundStatement` from an array of `Statement`s 588 * 589 * Params: 590 * loc = Instantiation information 591 * sts = A variadic array of `Statement`s, that will copied in this class 592 * The entries themselves will not be copied. 593 */ 594 final extern (D) this(const ref Loc loc, Statement[] sts...) 595 { 596 super(loc, STMT.Compound); 597 statements = new Statements(); 598 statements.reserve(sts.length); 599 foreach (s; sts) 600 statements.push(s); 601 } 602 603 static CompoundStatement create(const ref Loc loc, Statement s1, Statement s2) 604 { 605 return new CompoundStatement(loc, s1, s2); 606 } 607 608 override CompoundStatement syntaxCopy() 609 { 610 return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements)); 611 } 612 613 override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 614 { 615 foreach (s; *statements) 616 { 617 if (s) 618 { 619 if (inout rs = s.endsWithReturnStatement()) 620 return rs; 621 } 622 } 623 return null; 624 } 625 626 override final inout(Statement) last() inout nothrow pure 627 { 628 Statement s = null; 629 for (size_t i = statements.length; i; --i) 630 { 631 s = cast(Statement)(*statements)[i - 1]; 632 if (s) 633 { 634 s = cast(Statement)s.last(); 635 if (s) 636 break; 637 } 638 } 639 return cast(inout)s; 640 } 641 642 override void accept(Visitor v) 643 { 644 v.visit(this); 645 } 646 } 647 648 /*********************************************************** 649 */ 650 extern (C++) final class CompoundDeclarationStatement : CompoundStatement 651 { 652 extern (D) this(const ref Loc loc, Statements* statements) 653 { 654 super(loc, statements, STMT.CompoundDeclaration); 655 } 656 657 override CompoundDeclarationStatement syntaxCopy() 658 { 659 auto a = new Statements(statements.length); 660 foreach (i, s; *statements) 661 { 662 (*a)[i] = s ? s.syntaxCopy() : null; 663 } 664 return new CompoundDeclarationStatement(loc, a); 665 } 666 667 override void accept(Visitor v) 668 { 669 v.visit(this); 670 } 671 } 672 673 /*********************************************************** 674 * The purpose of this is so that continue will go to the next 675 * of the statements, and break will go to the end of the statements. 676 */ 677 extern (C++) final class UnrolledLoopStatement : Statement 678 { 679 Statements* statements; 680 681 extern (D) this(const ref Loc loc, Statements* statements) 682 { 683 super(loc, STMT.UnrolledLoop); 684 this.statements = statements; 685 } 686 687 override UnrolledLoopStatement syntaxCopy() 688 { 689 auto a = new Statements(statements.length); 690 foreach (i, s; *statements) 691 { 692 (*a)[i] = s ? s.syntaxCopy() : null; 693 } 694 return new UnrolledLoopStatement(loc, a); 695 } 696 697 override bool hasBreak() const pure nothrow 698 { 699 return true; 700 } 701 702 override bool hasContinue() const pure nothrow 703 { 704 return true; 705 } 706 707 override void accept(Visitor v) 708 { 709 v.visit(this); 710 } 711 } 712 713 /*********************************************************** 714 */ 715 extern (C++) final class ScopeStatement : Statement 716 { 717 Statement statement; 718 Loc endloc; // location of closing curly bracket 719 720 extern (D) this(const ref Loc loc, Statement statement, Loc endloc) 721 { 722 super(loc, STMT.Scope); 723 this.statement = statement; 724 this.endloc = endloc; 725 } 726 727 override ScopeStatement syntaxCopy() 728 { 729 return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); 730 } 731 732 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 733 { 734 if (statement) 735 return statement.endsWithReturnStatement(); 736 return null; 737 } 738 739 override bool hasBreak() const pure nothrow 740 { 741 //printf("ScopeStatement::hasBreak() %s\n", toChars()); 742 return statement ? statement.hasBreak() : false; 743 } 744 745 override bool hasContinue() const pure nothrow 746 { 747 return statement ? statement.hasContinue() : false; 748 } 749 750 override void accept(Visitor v) 751 { 752 v.visit(this); 753 } 754 } 755 756 /*********************************************************** 757 * Statement whose symbol table contains foreach index variables in a 758 * local scope and forwards other members to the parent scope. This 759 * wraps a statement. 760 * 761 * Also see: `dmd.attrib.ForwardingAttribDeclaration` 762 */ 763 extern (C++) final class ForwardingStatement : Statement 764 { 765 /// The symbol containing the `static foreach` variables. 766 ForwardingScopeDsymbol sym = null; 767 /// The wrapped statement. 768 Statement statement; 769 770 extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement) 771 { 772 super(loc, STMT.Forwarding); 773 this.sym = sym; 774 assert(statement); 775 this.statement = statement; 776 } 777 778 extern (D) this(const ref Loc loc, Statement statement) 779 { 780 auto sym = new ForwardingScopeDsymbol(); 781 sym.symtab = new DsymbolTable(); 782 this(loc, sym, statement); 783 } 784 785 override ForwardingStatement syntaxCopy() 786 { 787 return new ForwardingStatement(loc, statement.syntaxCopy()); 788 } 789 790 override void accept(Visitor v) 791 { 792 v.visit(this); 793 } 794 } 795 796 797 /*********************************************************** 798 * https://dlang.org/spec/statement.html#while-statement 799 */ 800 extern (C++) final class WhileStatement : Statement 801 { 802 Parameter param; 803 Expression condition; 804 Statement _body; 805 Loc endloc; // location of closing curly bracket 806 807 extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) 808 { 809 super(loc, STMT.While); 810 this.condition = condition; 811 this._body = _body; 812 this.endloc = endloc; 813 this.param = param; 814 } 815 816 override WhileStatement syntaxCopy() 817 { 818 return new WhileStatement(loc, 819 condition.syntaxCopy(), 820 _body ? _body.syntaxCopy() : null, 821 endloc, param ? param.syntaxCopy() : null); 822 } 823 824 override bool hasBreak() const pure nothrow 825 { 826 return true; 827 } 828 829 override bool hasContinue() const pure nothrow 830 { 831 return true; 832 } 833 834 override void accept(Visitor v) 835 { 836 v.visit(this); 837 } 838 } 839 840 /*********************************************************** 841 * https://dlang.org/spec/statement.html#do-statement 842 */ 843 extern (C++) final class DoStatement : Statement 844 { 845 Statement _body; 846 Expression condition; 847 Loc endloc; // location of ';' after while 848 849 extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc) 850 { 851 super(loc, STMT.Do); 852 this._body = _body; 853 this.condition = condition; 854 this.endloc = endloc; 855 } 856 857 override DoStatement syntaxCopy() 858 { 859 return new DoStatement(loc, 860 _body ? _body.syntaxCopy() : null, 861 condition.syntaxCopy(), 862 endloc); 863 } 864 865 override bool hasBreak() const pure nothrow 866 { 867 return true; 868 } 869 870 override bool hasContinue() const pure nothrow 871 { 872 return true; 873 } 874 875 override void accept(Visitor v) 876 { 877 v.visit(this); 878 } 879 } 880 881 /*********************************************************** 882 * https://dlang.org/spec/statement.html#for-statement 883 */ 884 extern (C++) final class ForStatement : Statement 885 { 886 Statement _init; 887 Expression condition; 888 Expression increment; 889 Statement _body; 890 Loc endloc; // location of closing curly bracket 891 892 // When wrapped in try/finally clauses, this points to the outermost one, 893 // which may have an associated label. Internal break/continue statements 894 // treat that label as referring to this loop. 895 Statement relatedLabeled; 896 897 extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) 898 { 899 super(loc, STMT.For); 900 this._init = _init; 901 this.condition = condition; 902 this.increment = increment; 903 this._body = _body; 904 this.endloc = endloc; 905 } 906 907 override ForStatement syntaxCopy() 908 { 909 return new ForStatement(loc, 910 _init ? _init.syntaxCopy() : null, 911 condition ? condition.syntaxCopy() : null, 912 increment ? increment.syntaxCopy() : null, 913 _body.syntaxCopy(), 914 endloc); 915 } 916 917 override Statement getRelatedLabeled() 918 { 919 return relatedLabeled ? relatedLabeled : this; 920 } 921 922 override bool hasBreak() const pure nothrow 923 { 924 //printf("ForStatement::hasBreak()\n"); 925 return true; 926 } 927 928 override bool hasContinue() const pure nothrow 929 { 930 return true; 931 } 932 933 override void accept(Visitor v) 934 { 935 v.visit(this); 936 } 937 } 938 939 /*********************************************************** 940 * https://dlang.org/spec/statement.html#foreach-statement 941 */ 942 extern (C++) final class ForeachStatement : Statement 943 { 944 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 945 Parameters* parameters; // array of Parameters, one for each ForeachType 946 Expression aggr; // ForeachAggregate 947 Statement _body; // NoScopeNonEmptyStatement 948 Loc endloc; // location of closing curly bracket 949 950 VarDeclaration key; 951 VarDeclaration value; 952 953 FuncDeclaration func; // function we're lexically in 954 955 Statements* cases; // put breaks, continues, gotos and returns here 956 ScopeStatements* gotos; // forward referenced goto's go here 957 958 extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) 959 { 960 super(loc, STMT.Foreach); 961 this.op = op; 962 this.parameters = parameters; 963 this.aggr = aggr; 964 this._body = _body; 965 this.endloc = endloc; 966 } 967 968 override ForeachStatement syntaxCopy() 969 { 970 return new ForeachStatement(loc, op, 971 Parameter.arraySyntaxCopy(parameters), 972 aggr.syntaxCopy(), 973 _body ? _body.syntaxCopy() : null, 974 endloc); 975 } 976 977 override bool hasBreak() const pure nothrow 978 { 979 return true; 980 } 981 982 override bool hasContinue() const pure nothrow 983 { 984 return true; 985 } 986 987 override void accept(Visitor v) 988 { 989 v.visit(this); 990 } 991 } 992 993 /*********************************************************** 994 * https://dlang.org/spec/statement.html#foreach-range-statement 995 */ 996 extern (C++) final class ForeachRangeStatement : Statement 997 { 998 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 999 Parameter prm; // loop index variable 1000 Expression lwr; 1001 Expression upr; 1002 Statement _body; 1003 Loc endloc; // location of closing curly bracket 1004 1005 VarDeclaration key; 1006 1007 extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) 1008 { 1009 super(loc, STMT.ForeachRange); 1010 this.op = op; 1011 this.prm = prm; 1012 this.lwr = lwr; 1013 this.upr = upr; 1014 this._body = _body; 1015 this.endloc = endloc; 1016 } 1017 1018 override ForeachRangeStatement syntaxCopy() 1019 { 1020 return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 1021 } 1022 1023 override bool hasBreak() const pure nothrow 1024 { 1025 return true; 1026 } 1027 1028 override bool hasContinue() const pure nothrow 1029 { 1030 return true; 1031 } 1032 1033 override void accept(Visitor v) 1034 { 1035 v.visit(this); 1036 } 1037 } 1038 1039 /*********************************************************** 1040 * https://dlang.org/spec/statement.html#if-statement 1041 */ 1042 extern (C++) final class IfStatement : Statement 1043 { 1044 Parameter prm; 1045 Expression condition; 1046 Statement ifbody; 1047 Statement elsebody; 1048 VarDeclaration match; // for MatchExpression results 1049 Loc endloc; // location of closing curly bracket 1050 1051 extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) 1052 { 1053 super(loc, STMT.If); 1054 this.prm = prm; 1055 this.condition = condition; 1056 this.ifbody = ifbody; 1057 this.elsebody = elsebody; 1058 this.endloc = endloc; 1059 } 1060 1061 override IfStatement syntaxCopy() 1062 { 1063 return new IfStatement(loc, 1064 prm ? prm.syntaxCopy() : null, 1065 condition.syntaxCopy(), 1066 ifbody ? ifbody.syntaxCopy() : null, 1067 elsebody ? elsebody.syntaxCopy() : null, 1068 endloc); 1069 } 1070 1071 override void accept(Visitor v) 1072 { 1073 v.visit(this); 1074 } 1075 1076 /****** 1077 * Returns: true if `if (__ctfe)` 1078 */ 1079 bool isIfCtfeBlock() 1080 { 1081 if (auto cv = condition.isVarExp()) 1082 return cv.var.ident == Id.ctfe; 1083 return false; 1084 } 1085 } 1086 1087 /*********************************************************** 1088 * https://dlang.org/spec/version.html#ConditionalStatement 1089 */ 1090 extern (C++) final class ConditionalStatement : Statement 1091 { 1092 Condition condition; 1093 Statement ifbody; 1094 Statement elsebody; 1095 1096 extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) 1097 { 1098 super(loc, STMT.Conditional); 1099 this.condition = condition; 1100 this.ifbody = ifbody; 1101 this.elsebody = elsebody; 1102 } 1103 1104 override ConditionalStatement syntaxCopy() 1105 { 1106 return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); 1107 } 1108 1109 override void accept(Visitor v) 1110 { 1111 v.visit(this); 1112 } 1113 } 1114 1115 1116 /*********************************************************** 1117 * https://dlang.org/spec/version.html#StaticForeachStatement 1118 * Static foreach statements, like: 1119 * void main() 1120 * { 1121 * static foreach(i; 0 .. 10) 1122 * { 1123 * pragma(msg, i); 1124 * } 1125 * } 1126 */ 1127 extern (C++) final class StaticForeachStatement : Statement 1128 { 1129 StaticForeach sfe; 1130 1131 extern (D) this(const ref Loc loc, StaticForeach sfe) 1132 { 1133 super(loc, STMT.StaticForeach); 1134 this.sfe = sfe; 1135 } 1136 1137 override StaticForeachStatement syntaxCopy() 1138 { 1139 return new StaticForeachStatement(loc, sfe.syntaxCopy()); 1140 } 1141 1142 override void accept(Visitor v) 1143 { 1144 v.visit(this); 1145 } 1146 } 1147 1148 /*********************************************************** 1149 * https://dlang.org/spec/statement.html#pragma-statement 1150 */ 1151 extern (C++) final class PragmaStatement : Statement 1152 { 1153 const Identifier ident; 1154 Expressions* args; // array of Expression's 1155 Statement _body; 1156 1157 extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body) 1158 { 1159 super(loc, STMT.Pragma); 1160 this.ident = ident; 1161 this.args = args; 1162 this._body = _body; 1163 } 1164 1165 override PragmaStatement syntaxCopy() 1166 { 1167 return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); 1168 } 1169 1170 override void accept(Visitor v) 1171 { 1172 v.visit(this); 1173 } 1174 } 1175 1176 /*********************************************************** 1177 * https://dlang.org/spec/version.html#StaticAssert 1178 */ 1179 extern (C++) final class StaticAssertStatement : Statement 1180 { 1181 StaticAssert sa; 1182 1183 extern (D) this(StaticAssert sa) 1184 { 1185 super(sa.loc, STMT.StaticAssert); 1186 this.sa = sa; 1187 } 1188 1189 override StaticAssertStatement syntaxCopy() 1190 { 1191 return new StaticAssertStatement(sa.syntaxCopy(null)); 1192 } 1193 1194 override void accept(Visitor v) 1195 { 1196 v.visit(this); 1197 } 1198 } 1199 1200 /*********************************************************** 1201 * https://dlang.org/spec/statement.html#switch-statement 1202 */ 1203 extern (C++) final class SwitchStatement : Statement 1204 { 1205 Expression condition; /// switch(condition) 1206 Statement _body; /// 1207 bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement 1208 1209 DefaultStatement sdefault; /// default: 1210 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1211 TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement 1212 GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's 1213 CaseStatements* cases; /// array of CaseStatement's 1214 int hasNoDefault; /// !=0 if no default statement 1215 int hasVars; /// !=0 if has variable case values 1216 VarDeclaration lastVar; /// last observed variable declaration in this statement 1217 1218 extern (D) this(const ref Loc loc, Expression condition, Statement _body, bool isFinal) 1219 { 1220 super(loc, STMT.Switch); 1221 this.condition = condition; 1222 this._body = _body; 1223 this.isFinal = isFinal; 1224 } 1225 1226 override SwitchStatement syntaxCopy() 1227 { 1228 return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal); 1229 } 1230 1231 override bool hasBreak() const pure nothrow 1232 { 1233 return true; 1234 } 1235 1236 /************************************ 1237 * Returns: 1238 * true if error 1239 */ 1240 extern (D) bool checkLabel() 1241 { 1242 /* 1243 * Checks the scope of a label for existing variable declaration. 1244 * Params: 1245 * vd = last variable declared before this case/default label 1246 * Returns: `true` if the variables declared in this label would be skipped. 1247 */ 1248 bool checkVar(VarDeclaration vd) 1249 { 1250 for (auto v = vd; v && v != lastVar; v = v.lastVar) 1251 { 1252 if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp) && vd.ident != Id.withSym) || v._init.isVoidInitializer()) 1253 continue; 1254 if (vd.ident == Id.withSym) 1255 error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars()); 1256 else 1257 error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars()); 1258 return true; 1259 } 1260 return false; 1261 } 1262 1263 enum error = true; 1264 1265 if (sdefault && checkVar(sdefault.lastVar)) 1266 return !error; // return error once fully deprecated 1267 1268 foreach (scase; *cases) 1269 { 1270 if (scase && checkVar(scase.lastVar)) 1271 return !error; // return error once fully deprecated 1272 } 1273 return !error; 1274 } 1275 1276 override void accept(Visitor v) 1277 { 1278 v.visit(this); 1279 } 1280 } 1281 1282 /*********************************************************** 1283 * https://dlang.org/spec/statement.html#CaseStatement 1284 */ 1285 extern (C++) final class CaseStatement : Statement 1286 { 1287 Expression exp; 1288 Statement statement; 1289 1290 int index; // which case it is (since we sort this) 1291 VarDeclaration lastVar; 1292 void* extra; // for use by Statement_toIR() 1293 1294 extern (D) this(const ref Loc loc, Expression exp, Statement statement) 1295 { 1296 super(loc, STMT.Case); 1297 this.exp = exp; 1298 this.statement = statement; 1299 } 1300 1301 override CaseStatement syntaxCopy() 1302 { 1303 return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); 1304 } 1305 1306 override void accept(Visitor v) 1307 { 1308 v.visit(this); 1309 } 1310 } 1311 1312 /*********************************************************** 1313 * https://dlang.org/spec/statement.html#CaseRangeStatement 1314 */ 1315 extern (C++) final class CaseRangeStatement : Statement 1316 { 1317 Expression first; 1318 Expression last; 1319 Statement statement; 1320 1321 extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement) 1322 { 1323 super(loc, STMT.CaseRange); 1324 this.first = first; 1325 this.last = last; 1326 this.statement = statement; 1327 } 1328 1329 override CaseRangeStatement syntaxCopy() 1330 { 1331 return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); 1332 } 1333 1334 override void accept(Visitor v) 1335 { 1336 v.visit(this); 1337 } 1338 } 1339 1340 /*********************************************************** 1341 * https://dlang.org/spec/statement.html#DefaultStatement 1342 */ 1343 extern (C++) final class DefaultStatement : Statement 1344 { 1345 Statement statement; 1346 1347 VarDeclaration lastVar; 1348 1349 extern (D) this(const ref Loc loc, Statement statement) 1350 { 1351 super(loc, STMT.Default); 1352 this.statement = statement; 1353 } 1354 1355 override DefaultStatement syntaxCopy() 1356 { 1357 return new DefaultStatement(loc, statement.syntaxCopy()); 1358 } 1359 1360 override void accept(Visitor v) 1361 { 1362 v.visit(this); 1363 } 1364 } 1365 1366 /*********************************************************** 1367 * https://dlang.org/spec/statement.html#GotoStatement 1368 */ 1369 extern (C++) final class GotoDefaultStatement : Statement 1370 { 1371 SwitchStatement sw; 1372 1373 extern (D) this(const ref Loc loc) 1374 { 1375 super(loc, STMT.GotoDefault); 1376 } 1377 1378 override GotoDefaultStatement syntaxCopy() 1379 { 1380 return new GotoDefaultStatement(loc); 1381 } 1382 1383 override void accept(Visitor v) 1384 { 1385 v.visit(this); 1386 } 1387 } 1388 1389 /*********************************************************** 1390 * https://dlang.org/spec/statement.html#GotoStatement 1391 */ 1392 extern (C++) final class GotoCaseStatement : Statement 1393 { 1394 Expression exp; // null, or which case to goto 1395 1396 CaseStatement cs; // case statement it resolves to 1397 1398 extern (D) this(const ref Loc loc, Expression exp) 1399 { 1400 super(loc, STMT.GotoCase); 1401 this.exp = exp; 1402 } 1403 1404 override GotoCaseStatement syntaxCopy() 1405 { 1406 return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); 1407 } 1408 1409 override void accept(Visitor v) 1410 { 1411 v.visit(this); 1412 } 1413 } 1414 1415 /*********************************************************** 1416 */ 1417 extern (C++) final class SwitchErrorStatement : Statement 1418 { 1419 Expression exp; 1420 1421 extern (D) this(const ref Loc loc) 1422 { 1423 super(loc, STMT.SwitchError); 1424 } 1425 1426 final extern (D) this(const ref Loc loc, Expression exp) 1427 { 1428 super(loc, STMT.SwitchError); 1429 this.exp = exp; 1430 } 1431 1432 override void accept(Visitor v) 1433 { 1434 v.visit(this); 1435 } 1436 } 1437 1438 /*********************************************************** 1439 * https://dlang.org/spec/statement.html#return-statement 1440 */ 1441 extern (C++) final class ReturnStatement : Statement 1442 { 1443 Expression exp; 1444 size_t caseDim; 1445 1446 extern (D) this(const ref Loc loc, Expression exp) 1447 { 1448 super(loc, STMT.Return); 1449 this.exp = exp; 1450 } 1451 1452 override ReturnStatement syntaxCopy() 1453 { 1454 return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); 1455 } 1456 1457 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 1458 { 1459 return this; 1460 } 1461 1462 override void accept(Visitor v) 1463 { 1464 v.visit(this); 1465 } 1466 } 1467 1468 /*********************************************************** 1469 * https://dlang.org/spec/statement.html#break-statement 1470 */ 1471 extern (C++) final class BreakStatement : Statement 1472 { 1473 Identifier ident; 1474 1475 extern (D) this(const ref Loc loc, Identifier ident) 1476 { 1477 super(loc, STMT.Break); 1478 this.ident = ident; 1479 } 1480 1481 override BreakStatement syntaxCopy() 1482 { 1483 return new BreakStatement(loc, ident); 1484 } 1485 1486 override void accept(Visitor v) 1487 { 1488 v.visit(this); 1489 } 1490 } 1491 1492 /*********************************************************** 1493 * https://dlang.org/spec/statement.html#continue-statement 1494 */ 1495 extern (C++) final class ContinueStatement : Statement 1496 { 1497 Identifier ident; 1498 1499 extern (D) this(const ref Loc loc, Identifier ident) 1500 { 1501 super(loc, STMT.Continue); 1502 this.ident = ident; 1503 } 1504 1505 override ContinueStatement syntaxCopy() 1506 { 1507 return new ContinueStatement(loc, ident); 1508 } 1509 1510 override void accept(Visitor v) 1511 { 1512 v.visit(this); 1513 } 1514 } 1515 1516 /*********************************************************** 1517 * https://dlang.org/spec/statement.html#SynchronizedStatement 1518 */ 1519 extern (C++) final class SynchronizedStatement : Statement 1520 { 1521 Expression exp; 1522 Statement _body; 1523 1524 extern (D) this(const ref Loc loc, Expression exp, Statement _body) 1525 { 1526 super(loc, STMT.Synchronized); 1527 this.exp = exp; 1528 this._body = _body; 1529 } 1530 1531 override SynchronizedStatement syntaxCopy() 1532 { 1533 return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); 1534 } 1535 1536 override bool hasBreak() const pure nothrow 1537 { 1538 return false; //true; 1539 } 1540 1541 override bool hasContinue() const pure nothrow 1542 { 1543 return false; //true; 1544 } 1545 1546 override void accept(Visitor v) 1547 { 1548 v.visit(this); 1549 } 1550 } 1551 1552 /*********************************************************** 1553 * https://dlang.org/spec/statement.html#with-statement 1554 */ 1555 extern (C++) final class WithStatement : Statement 1556 { 1557 Expression exp; 1558 Statement _body; 1559 VarDeclaration wthis; 1560 Loc endloc; 1561 1562 extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc) 1563 { 1564 super(loc, STMT.With); 1565 this.exp = exp; 1566 this._body = _body; 1567 this.endloc = endloc; 1568 } 1569 1570 override WithStatement syntaxCopy() 1571 { 1572 return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 1573 } 1574 1575 override void accept(Visitor v) 1576 { 1577 v.visit(this); 1578 } 1579 } 1580 1581 /*********************************************************** 1582 * https://dlang.org/spec/statement.html#try-statement 1583 */ 1584 extern (C++) final class TryCatchStatement : Statement 1585 { 1586 Statement _body; 1587 Catches* catches; 1588 1589 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 1590 1591 extern (D) this(const ref Loc loc, Statement _body, Catches* catches) 1592 { 1593 super(loc, STMT.TryCatch); 1594 this._body = _body; 1595 this.catches = catches; 1596 } 1597 1598 override TryCatchStatement syntaxCopy() 1599 { 1600 auto a = new Catches(catches.length); 1601 foreach (i, c; *catches) 1602 { 1603 (*a)[i] = c.syntaxCopy(); 1604 } 1605 return new TryCatchStatement(loc, _body.syntaxCopy(), a); 1606 } 1607 1608 override bool hasBreak() const pure nothrow 1609 { 1610 return false; 1611 } 1612 1613 override void accept(Visitor v) 1614 { 1615 v.visit(this); 1616 } 1617 } 1618 1619 /*********************************************************** 1620 * https://dlang.org/spec/statement.html#Catch 1621 */ 1622 extern (C++) final class Catch : RootObject 1623 { 1624 const Loc loc; 1625 Type type; 1626 Identifier ident; 1627 Statement handler; 1628 1629 VarDeclaration var; 1630 bool errors; // set if semantic processing errors 1631 1632 // was generated by the compiler, wasn't present in source code 1633 bool internalCatch; 1634 1635 extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler) 1636 { 1637 //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); 1638 this.loc = loc; 1639 this.type = type; 1640 this.ident = ident; 1641 this.handler = handler; 1642 } 1643 1644 Catch syntaxCopy() 1645 { 1646 auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); 1647 c.internalCatch = internalCatch; 1648 return c; 1649 } 1650 } 1651 1652 /*********************************************************** 1653 * https://dlang.org/spec/statement.html#try-statement 1654 */ 1655 extern (C++) final class TryFinallyStatement : Statement 1656 { 1657 Statement _body; 1658 Statement finalbody; 1659 1660 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 1661 bool bodyFallsThru; /// true if _body falls through to finally 1662 1663 extern (D) this(const ref Loc loc, Statement _body, Statement finalbody) 1664 { 1665 super(loc, STMT.TryFinally); 1666 this._body = _body; 1667 this.finalbody = finalbody; 1668 this.bodyFallsThru = true; // assume true until statementSemantic() 1669 } 1670 1671 static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody) 1672 { 1673 return new TryFinallyStatement(loc, _body, finalbody); 1674 } 1675 1676 override TryFinallyStatement syntaxCopy() 1677 { 1678 return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); 1679 } 1680 1681 override bool hasBreak() const pure nothrow 1682 { 1683 return false; //true; 1684 } 1685 1686 override bool hasContinue() const pure nothrow 1687 { 1688 return false; //true; 1689 } 1690 1691 override void accept(Visitor v) 1692 { 1693 v.visit(this); 1694 } 1695 } 1696 1697 /*********************************************************** 1698 * https://dlang.org/spec/statement.html#scope-guard-statement 1699 */ 1700 extern (C++) final class ScopeGuardStatement : Statement 1701 { 1702 TOK tok; 1703 Statement statement; 1704 1705 extern (D) this(const ref Loc loc, TOK tok, Statement statement) 1706 { 1707 super(loc, STMT.ScopeGuard); 1708 this.tok = tok; 1709 this.statement = statement; 1710 } 1711 1712 override ScopeGuardStatement syntaxCopy() 1713 { 1714 return new ScopeGuardStatement(loc, tok, statement.syntaxCopy()); 1715 } 1716 1717 override void accept(Visitor v) 1718 { 1719 v.visit(this); 1720 } 1721 } 1722 1723 /*********************************************************** 1724 * https://dlang.org/spec/statement.html#throw-statement 1725 */ 1726 extern (C++) final class ThrowStatement : Statement 1727 { 1728 Expression exp; 1729 1730 // was generated by the compiler, wasn't present in source code 1731 bool internalThrow; 1732 1733 extern (D) this(const ref Loc loc, Expression exp) 1734 { 1735 super(loc, STMT.Throw); 1736 this.exp = exp; 1737 } 1738 1739 override ThrowStatement syntaxCopy() 1740 { 1741 auto s = new ThrowStatement(loc, exp.syntaxCopy()); 1742 s.internalThrow = internalThrow; 1743 return s; 1744 } 1745 1746 override void accept(Visitor v) 1747 { 1748 v.visit(this); 1749 } 1750 } 1751 1752 /*********************************************************** 1753 */ 1754 extern (C++) final class DebugStatement : Statement 1755 { 1756 Statement statement; 1757 1758 extern (D) this(const ref Loc loc, Statement statement) 1759 { 1760 super(loc, STMT.Debug); 1761 this.statement = statement; 1762 } 1763 1764 override DebugStatement syntaxCopy() 1765 { 1766 return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); 1767 } 1768 1769 override void accept(Visitor v) 1770 { 1771 v.visit(this); 1772 } 1773 } 1774 1775 /*********************************************************** 1776 * https://dlang.org/spec/statement.html#goto-statement 1777 */ 1778 extern (C++) final class GotoStatement : Statement 1779 { 1780 Identifier ident; 1781 LabelDsymbol label; 1782 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1783 TryFinallyStatement tf; 1784 ScopeGuardStatement os; 1785 VarDeclaration lastVar; 1786 bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block 1787 1788 extern (D) this(const ref Loc loc, Identifier ident) 1789 { 1790 super(loc, STMT.Goto); 1791 this.ident = ident; 1792 } 1793 1794 override GotoStatement syntaxCopy() 1795 { 1796 return new GotoStatement(loc, ident); 1797 } 1798 1799 /************** 1800 * Returns: true for error 1801 */ 1802 extern (D) bool checkLabel() 1803 { 1804 if (!label.statement) 1805 return true; // error should have been issued for this already 1806 1807 if (label.statement.os != os) 1808 { 1809 if (os && os.tok == TOK.onScopeFailure && !label.statement.os) 1810 { 1811 // Jump out from scope(failure) block is allowed. 1812 } 1813 else 1814 { 1815 if (label.statement.os) 1816 error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); 1817 else 1818 error("cannot `goto` out of `%s` block", Token.toChars(os.tok)); 1819 return true; 1820 } 1821 } 1822 1823 if (label.statement.tf != tf) 1824 { 1825 error("cannot `goto` in or out of `finally` block"); 1826 return true; 1827 } 1828 1829 if (label.statement.inCtfeBlock && !inCtfeBlock) 1830 { 1831 error("cannot `goto` into `if (__ctfe)` block"); 1832 return true; 1833 } 1834 1835 Statement stbnext; 1836 for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext) 1837 { 1838 if (!stb) 1839 { 1840 error("cannot `goto` into `try` block"); 1841 return true; 1842 } 1843 if (auto stf = stb.isTryFinallyStatement()) 1844 stbnext = stf.tryBody; 1845 else if (auto stc = stb.isTryCatchStatement()) 1846 stbnext = stc.tryBody; 1847 else 1848 assert(0); 1849 } 1850 1851 VarDeclaration vd = label.statement.lastVar; 1852 if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest)) 1853 return false; 1854 1855 VarDeclaration last = lastVar; 1856 while (last && last != vd) 1857 last = last.lastVar; 1858 if (last == vd) 1859 { 1860 // All good, the label's scope has no variables 1861 } 1862 else if (vd.storage_class & STC.exptemp) 1863 { 1864 // Lifetime ends at end of expression, so no issue with skipping the statement 1865 } 1866 else if (vd.ident == Id.withSym) 1867 { 1868 error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars()); 1869 return true; 1870 } 1871 else 1872 { 1873 error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars()); 1874 return true; 1875 } 1876 1877 return false; 1878 } 1879 1880 override void accept(Visitor v) 1881 { 1882 v.visit(this); 1883 } 1884 } 1885 1886 /*********************************************************** 1887 * https://dlang.org/spec/statement.html#LabeledStatement 1888 */ 1889 extern (C++) final class LabelStatement : Statement 1890 { 1891 Identifier ident; 1892 Statement statement; 1893 1894 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1895 TryFinallyStatement tf; 1896 ScopeGuardStatement os; 1897 VarDeclaration lastVar; 1898 Statement gotoTarget; // interpret 1899 void* extra; // used by Statement_toIR() 1900 bool breaks; // someone did a 'break ident' 1901 bool inCtfeBlock; // inside a block dominated by `if (__ctfe)` 1902 1903 extern (D) this(const ref Loc loc, Identifier ident, Statement statement) 1904 { 1905 super(loc, STMT.Label); 1906 this.ident = ident; 1907 this.statement = statement; 1908 } 1909 1910 override LabelStatement syntaxCopy() 1911 { 1912 return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); 1913 } 1914 1915 override void accept(Visitor v) 1916 { 1917 v.visit(this); 1918 } 1919 } 1920 1921 /*********************************************************** 1922 */ 1923 extern (C++) final class LabelDsymbol : Dsymbol 1924 { 1925 LabelStatement statement; 1926 1927 bool deleted; // set if rewritten to return in foreach delegate 1928 bool iasm; // set if used by inline assembler 1929 1930 extern (D) this(Identifier ident, const ref Loc loc = Loc.initial) 1931 { 1932 super(loc, ident); 1933 } 1934 1935 static LabelDsymbol create(Identifier ident) 1936 { 1937 return new LabelDsymbol(ident); 1938 } 1939 1940 // is this a LabelDsymbol()? 1941 override LabelDsymbol isLabel() 1942 { 1943 return this; 1944 } 1945 1946 override void accept(Visitor v) 1947 { 1948 v.visit(this); 1949 } 1950 } 1951 1952 /*********************************************************** 1953 * https://dlang.org/spec/statement.html#asm 1954 */ 1955 extern (C++) class AsmStatement : Statement 1956 { 1957 Token* tokens; 1958 1959 extern (D) this(const ref Loc loc, Token* tokens) 1960 { 1961 super(loc, STMT.Asm); 1962 this.tokens = tokens; 1963 } 1964 1965 extern (D) this(const ref Loc loc, Token* tokens, STMT stmt) 1966 { 1967 super(loc, stmt); 1968 this.tokens = tokens; 1969 } 1970 1971 override AsmStatement syntaxCopy() 1972 { 1973 return new AsmStatement(loc, tokens); 1974 } 1975 1976 override void accept(Visitor v) 1977 { 1978 v.visit(this); 1979 } 1980 } 1981 1982 /*********************************************************** 1983 * https://dlang.org/spec/iasm.html 1984 */ 1985 extern (C++) final class InlineAsmStatement : AsmStatement 1986 { 1987 code* asmcode; 1988 uint asmalign; // alignment of this statement 1989 uint regs; // mask of registers modified (must match regm_t in back end) 1990 bool refparam; // true if function parameter is referenced 1991 bool naked; // true if function is to be naked 1992 1993 extern (D) this(const ref Loc loc, Token* tokens) 1994 { 1995 super(loc, tokens, STMT.InlineAsm); 1996 } 1997 1998 override InlineAsmStatement syntaxCopy() 1999 { 2000 return new InlineAsmStatement(loc, tokens); 2001 } 2002 2003 override void accept(Visitor v) 2004 { 2005 v.visit(this); 2006 } 2007 } 2008 2009 /*********************************************************** 2010 * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 2011 * Assembler instructions with D expression operands. 2012 */ 2013 extern (C++) final class GccAsmStatement : AsmStatement 2014 { 2015 StorageClass stc; // attributes of the asm {} block 2016 Expression insn; // string expression that is the template for assembler code 2017 Expressions* args; // input and output operands of the statement 2018 uint outputargs; // of the operands in 'args', the number of output operands 2019 Identifiers* names; // list of symbolic names for the operands 2020 Expressions* constraints; // list of string constants specifying constraints on operands 2021 Expressions* clobbers; // list of string constants specifying clobbers and scratch registers 2022 Identifiers* labels; // list of goto labels 2023 GotoStatements* gotos; // of the goto labels, the equivalent statements they represent 2024 2025 extern (D) this(const ref Loc loc, Token* tokens) 2026 { 2027 super(loc, tokens, STMT.GccAsm); 2028 } 2029 2030 override GccAsmStatement syntaxCopy() 2031 { 2032 return new GccAsmStatement(loc, tokens); 2033 } 2034 2035 override void accept(Visitor v) 2036 { 2037 v.visit(this); 2038 } 2039 } 2040 2041 /*********************************************************** 2042 * a complete asm {} block 2043 */ 2044 extern (C++) final class CompoundAsmStatement : CompoundStatement 2045 { 2046 StorageClass stc; // postfix attributes like nothrow/pure/@trusted 2047 2048 extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc) 2049 { 2050 super(loc, statements, STMT.CompoundAsm); 2051 this.stc = stc; 2052 } 2053 2054 override CompoundAsmStatement syntaxCopy() 2055 { 2056 auto a = new Statements(statements.length); 2057 foreach (i, s; *statements) 2058 { 2059 (*a)[i] = s ? s.syntaxCopy() : null; 2060 } 2061 return new CompoundAsmStatement(loc, a, stc); 2062 } 2063 2064 override void accept(Visitor v) 2065 { 2066 v.visit(this); 2067 } 2068 } 2069 2070 /*********************************************************** 2071 * https://dlang.org/spec/module.html#ImportDeclaration 2072 */ 2073 extern (C++) final class ImportStatement : Statement 2074 { 2075 Dsymbols* imports; // Array of Import's 2076 2077 extern (D) this(const ref Loc loc, Dsymbols* imports) 2078 { 2079 super(loc, STMT.Import); 2080 this.imports = imports; 2081 } 2082 2083 override ImportStatement syntaxCopy() 2084 { 2085 auto m = new Dsymbols(imports.length); 2086 foreach (i, s; *imports) 2087 { 2088 (*m)[i] = s.syntaxCopy(null); 2089 } 2090 return new ImportStatement(loc, m); 2091 } 2092 2093 override void accept(Visitor v) 2094 { 2095 v.visit(this); 2096 } 2097 } 2098 2099 2100 mixin template VisitStatement(Result) 2101 { 2102 Result VisitStatement(Statement s) 2103 { 2104 final switch (s.stmt) 2105 { 2106 case STMT.Error: mixin(visitStmtCase("Error")); 2107 case STMT.Scope: mixin(visitStmtCase("Scope")); 2108 case STMT.Exp: mixin(visitStmtCase("Exp")); 2109 case STMT.Compound: mixin(visitStmtCase("Compound")); 2110 case STMT.Return: mixin(visitStmtCase("Return")); 2111 case STMT.If: mixin(visitStmtCase("If")); 2112 case STMT.Conditional: mixin(visitStmtCase("Conditional")); 2113 case STMT.StaticForeach: mixin(visitStmtCase("StaticForeach")); 2114 case STMT.Case: mixin(visitStmtCase("Case")); 2115 case STMT.Default: mixin(visitStmtCase("Default")); 2116 case STMT.Label: mixin(visitStmtCase("Label")); 2117 case STMT.Goto: mixin(visitStmtCase("Goto")); 2118 case STMT.GotoDefault: mixin(visitStmtCase("GotoDefault")); 2119 case STMT.GotoCase: mixin(visitStmtCase("GotoCase")); 2120 case STMT.Break: mixin(visitStmtCase("Break")); 2121 case STMT.DtorExp: mixin(visitStmtCase("DtorExp")); 2122 case STMT.Mixin: mixin(visitStmtCase("Mixin")); 2123 case STMT.Forwarding: mixin(visitStmtCase("Forwarding")); 2124 case STMT.Do: mixin(visitStmtCase("Do")); 2125 case STMT.While: mixin(visitStmtCase("While")); 2126 case STMT.For: mixin(visitStmtCase("For")); 2127 case STMT.Foreach: mixin(visitStmtCase("Foreach")); 2128 case STMT.Switch: mixin(visitStmtCase("Switch")); 2129 case STMT.Continue: mixin(visitStmtCase("Continue")); 2130 case STMT.With: mixin(visitStmtCase("With")); 2131 case STMT.TryCatch: mixin(visitStmtCase("TryCatch")); 2132 case STMT.Throw: mixin(visitStmtCase("Throw")); 2133 case STMT.Debug: mixin(visitStmtCase("Debug")); 2134 case STMT.TryFinally: mixin(visitStmtCase("TryFinally")); 2135 case STMT.ScopeGuard: mixin(visitStmtCase("ScopeGuard")); 2136 case STMT.SwitchError: mixin(visitStmtCase("SwitchError")); 2137 case STMT.UnrolledLoop: mixin(visitStmtCase("UnrolledLoop")); 2138 case STMT.ForeachRange: mixin(visitStmtCase("ForeachRange")); 2139 case STMT.CompoundDeclaration: mixin(visitStmtCase("CompoundDeclaration")); 2140 case STMT.Peel: mixin(visitStmtCase("Peel")); 2141 case STMT.CompoundAsm: mixin(visitStmtCase("CompoundAsm")); 2142 case STMT.Pragma: mixin(visitStmtCase("Pragma")); 2143 case STMT.StaticAssert: mixin(visitStmtCase("StaticAssert")); 2144 case STMT.CaseRange: mixin(visitStmtCase("CaseRange")); 2145 case STMT.Synchronized: mixin(visitStmtCase("Synchronized")); 2146 case STMT.Asm: mixin(visitStmtCase("Asm")); 2147 case STMT.InlineAsm: mixin(visitStmtCase("InlineAsm")); 2148 case STMT.GccAsm: mixin(visitStmtCase("GccAsm")); 2149 case STMT.Import: mixin(visitStmtCase("Import")); 2150 } 2151 } 2152 } 2153 2154 /**************************************** 2155 * CTFE-only helper function for VisitInitializer. 2156 * Params: 2157 * handler = string for the name of the visit handler 2158 * Returns: boilerplate code for a case 2159 */ 2160 pure string visitStmtCase(string handler) 2161 { 2162 if (__ctfe) 2163 { 2164 return 2165 " 2166 enum isVoid = is(Result == void); 2167 auto sx = s.is"~handler~"Statement(); 2168 static if (__traits(compiles, visit"~handler~"(sx))) 2169 { 2170 static if (isVoid) 2171 { 2172 visit"~handler~"(sx); 2173 return; 2174 } 2175 else 2176 { 2177 if (Result r = visit"~handler~"(sx)) 2178 return r; 2179 return Result.init; 2180 } 2181 } 2182 else static if (__traits(compiles, visitDefaultCase(s))) 2183 { 2184 static if (isVoid) 2185 { 2186 visitDefaultCase(sx); 2187 return; 2188 } 2189 else 2190 { 2191 if (Result r = visitDefaultCase(s)) 2192 return r; 2193 return Result.init; 2194 } 2195 } 2196 else 2197 static assert(0, "~handler~"); 2198 "; 2199 } 2200 assert(0); 2201 }