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