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