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