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