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