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