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.rmem;
48 import dmd.root.rootobject;
49 import dmd.sapply;
50 import dmd.sideeffect;
51 import dmd.staticassert;
52 import dmd.tokens;
53 import dmd.visitor;
54 
55 /**
56  * Returns:
57  *     `TypeIdentifier` corresponding to `object.Throwable`
58  */
59 TypeIdentifier getThrowable()
60 {
61     auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty);
62     tid.addIdent(Id.object);
63     tid.addIdent(Id.Throwable);
64     return tid;
65 }
66 
67 /**
68  * Returns:
69  *      TypeIdentifier corresponding to `object.Exception`
70  */
71 TypeIdentifier getException()
72 {
73     auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty);
74     tid.addIdent(Id.object);
75     tid.addIdent(Id.Exception);
76     return tid;
77 }
78 
79 /********************************
80  * Identify Statement types with this enum rather than
81  * virtual functions.
82  */
83 
84 enum STMT : ubyte
85 {
86     Error,
87     Peel,
88     Exp, DtorExp,
89     Compile,
90     Compound, CompoundDeclaration, CompoundAsm,
91     UnrolledLoop,
92     Scope,
93     Forwarding,
94     While,
95     Do,
96     For,
97     Foreach,
98     ForeachRange,
99     If,
100     Conditional,
101     StaticForeach,
102     Pragma,
103     StaticAssert,
104     Switch,
105     Case,
106     CaseRange,
107     Default,
108     GotoDefault,
109     GotoCase,
110     SwitchError,
111     Return,
112     Break,
113     Continue,
114     Synchronized,
115     With,
116     TryCatch,
117     TryFinally,
118     ScopeGuard,
119     Throw,
120     Debug,
121     Goto,
122     Label,
123     Asm, InlineAsm, GccAsm,
124     Import,
125 }
126 
127 
128 /***********************************************************
129  * Specification: http://dlang.org/spec/statement.html
130  */
131 extern (C++) abstract class Statement : ASTNode
132 {
133     const Loc loc;
134     const STMT stmt;
135 
136     override final DYNCAST dyncast() const
137     {
138         return DYNCAST.statement;
139     }
140 
141     final extern (D) this(const ref Loc loc, STMT stmt)
142     {
143         this.loc = loc;
144         this.stmt = stmt;
145         // If this is an in{} contract scope statement (skip for determining
146         //  inlineStatus of a function body for header content)
147     }
148 
149     Statement syntaxCopy()
150     {
151         assert(0);
152     }
153 
154     /*************************************
155      * Do syntax copy of an array of Statement's.
156      */
157     static Statements* arraySyntaxCopy(Statements* a)
158     {
159         Statements* b = null;
160         if (a)
161         {
162             b = a.copy();
163             foreach (i, s; *a)
164             {
165                 (*b)[i] = s ? s.syntaxCopy() : null;
166             }
167         }
168         return b;
169     }
170 
171     override final const(char)* toChars() const
172     {
173         HdrGenState hgs;
174         OutBuffer buf;
175         .toCBuffer(this, &buf, &hgs);
176         buf.writeByte(0);
177         return buf.extractSlice().ptr;
178     }
179 
180     static if (__VERSION__ < 2092)
181     {
182         final void error(const(char)* format, ...)
183         {
184             va_list ap;
185             va_start(ap, format);
186             .verror(loc, format, ap);
187             va_end(ap);
188         }
189 
190         final void warning(const(char)* format, ...)
191         {
192             va_list ap;
193             va_start(ap, format);
194             .vwarning(loc, format, ap);
195             va_end(ap);
196         }
197 
198         final void deprecation(const(char)* format, ...)
199         {
200             va_list ap;
201             va_start(ap, format);
202             .vdeprecation(loc, format, ap);
203             va_end(ap);
204         }
205     }
206     else
207     {
208         pragma(printf) final void error(const(char)* format, ...)
209         {
210             va_list ap;
211             va_start(ap, format);
212             .verror(loc, format, ap);
213             va_end(ap);
214         }
215 
216         pragma(printf) final void warning(const(char)* format, ...)
217         {
218             va_list ap;
219             va_start(ap, format);
220             .vwarning(loc, format, ap);
221             va_end(ap);
222         }
223 
224         pragma(printf) final void deprecation(const(char)* format, ...)
225         {
226             va_list ap;
227             va_start(ap, format);
228             .vdeprecation(loc, format, ap);
229             va_end(ap);
230         }
231     }
232 
233     Statement getRelatedLabeled()
234     {
235         return this;
236     }
237 
238     /****************************
239      * Determine if an enclosed `break` would apply to this
240      * statement, such as if it is a loop or switch statement.
241      * Returns:
242      *     `true` if it does
243      */
244     bool hasBreak() const pure nothrow
245     {
246         //printf("Statement::hasBreak()\n");
247         return false;
248     }
249 
250     /****************************
251      * Determine if an enclosed `continue` would apply to this
252      * statement, such as if it is a loop statement.
253      * Returns:
254      *     `true` if it does
255      */
256     bool hasContinue() const pure nothrow
257     {
258         return false;
259     }
260 
261     /**********************************
262      * Returns:
263      *     `true` if statement uses exception handling
264      */
265     final bool usesEH()
266     {
267         extern (C++) final class UsesEH : StoppableVisitor
268         {
269             alias visit = typeof(super).visit;
270         public:
271             override void visit(Statement s)
272             {
273             }
274 
275             override void visit(TryCatchStatement s)
276             {
277                 stop = true;
278             }
279 
280             override void visit(TryFinallyStatement s)
281             {
282                 stop = true;
283             }
284 
285             override void visit(ScopeGuardStatement s)
286             {
287                 stop = true;
288             }
289 
290             override void visit(SynchronizedStatement s)
291             {
292                 stop = true;
293             }
294         }
295 
296         scope UsesEH ueh = new UsesEH();
297         return walkPostorder(this, ueh);
298     }
299 
300     /**********************************
301      * Returns:
302      *   `true` if statement 'comes from' somewhere else, like a goto
303      */
304     final bool comeFrom()
305     {
306         extern (C++) final class ComeFrom : StoppableVisitor
307         {
308             alias visit = typeof(super).visit;
309         public:
310             override void visit(Statement s)
311             {
312             }
313 
314             override void visit(CaseStatement s)
315             {
316                 stop = true;
317             }
318 
319             override void visit(DefaultStatement s)
320             {
321                 stop = true;
322             }
323 
324             override void visit(LabelStatement s)
325             {
326                 stop = true;
327             }
328 
329             override void visit(AsmStatement s)
330             {
331                 stop = true;
332             }
333         }
334 
335         scope ComeFrom cf = new ComeFrom();
336         return walkPostorder(this, cf);
337     }
338 
339     /**********************************
340      * Returns:
341      *   `true` if statement has executable code.
342      */
343     final bool hasCode()
344     {
345         extern (C++) final class HasCode : StoppableVisitor
346         {
347             alias visit = typeof(super).visit;
348         public:
349             override void visit(Statement s)
350             {
351                 stop = true;
352             }
353 
354             override void visit(ExpStatement s)
355             {
356                 if (s.exp !is null)
357                 {
358                     stop = s.exp.hasCode();
359                 }
360             }
361 
362             override void visit(CompoundStatement s)
363             {
364             }
365 
366             override void visit(ScopeStatement s)
367             {
368             }
369 
370             override void visit(ImportStatement s)
371             {
372             }
373         }
374 
375         scope HasCode hc = new HasCode();
376         return walkPostorder(this, hc);
377     }
378 
379     /****************************************
380      * If this statement has code that needs to run in a finally clause
381      * at the end of the current scope, return that code in the form of
382      * a Statement.
383      * Params:
384      *     sc = context
385      *     sentry     = set to code executed upon entry to the scope
386      *     sexception = set to code executed upon exit from the scope via exception
387      *     sfinally   = set to code executed in finally block
388      * Returns:
389      *    code to be run in the finally clause
390      */
391     Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
392     {
393         //printf("Statement::scopeCode()\n");
394         *sentry = null;
395         *sexception = null;
396         *sfinally = null;
397         return this;
398     }
399 
400     /*********************************
401      * Flatten out the scope by presenting the statement
402      * as an array of statements.
403      * Params:
404      *     sc = context
405      * Returns:
406      *     The array of `Statements`, or `null` if no flattening necessary
407      */
408     Statements* flatten(Scope* sc)
409     {
410         return null;
411     }
412 
413     /*******************************
414      * Find last statement in a sequence of statements.
415      * Returns:
416      *  the last statement, or `null` if there isn't one
417      */
418     inout(Statement) last() inout nothrow pure
419     {
420         return this;
421     }
422 
423     /**************************
424      * Support Visitor Pattern
425      * Params:
426      *  v = visitor
427      */
428     override void accept(Visitor v)
429     {
430         v.visit(this);
431     }
432 
433     /************************************
434      * Does this statement end with a return statement?
435      *
436      * I.e. is it a single return statement or some compound statement
437      * that unconditionally hits a return statement.
438      * Returns:
439      *  return statement it ends with, otherwise null
440      */
441     pure nothrow @nogc
442     inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
443 
444   final pure inout nothrow @nogc:
445 
446     /********************
447      * A cheaper method of doing downcasting of Statements.
448      * Returns:
449      *    the downcast statement if it can be downcasted, otherwise `null`
450      */
451     inout(ErrorStatement)       isErrorStatement()       { return stmt == STMT.Error       ? cast(typeof(return))this : null; }
452     inout(ScopeStatement)       isScopeStatement()       { return stmt == STMT.Scope       ? cast(typeof(return))this : null; }
453     inout(ExpStatement)         isExpStatement()         { return stmt == STMT.Exp         ? cast(typeof(return))this : null; }
454     inout(CompoundStatement)    isCompoundStatement()    { return stmt == STMT.Compound    ? cast(typeof(return))this : null; }
455     inout(ReturnStatement)      isReturnStatement()      { return stmt == STMT.Return      ? cast(typeof(return))this : null; }
456     inout(IfStatement)          isIfStatement()          { return stmt == STMT.If          ? cast(typeof(return))this : null; }
457     inout(CaseStatement)        isCaseStatement()        { return stmt == STMT.Case        ? cast(typeof(return))this : null; }
458     inout(DefaultStatement)     isDefaultStatement()     { return stmt == STMT.Default     ? cast(typeof(return))this : null; }
459     inout(LabelStatement)       isLabelStatement()       { return stmt == STMT.Label       ? cast(typeof(return))this : null; }
460     inout(GotoStatement)        isGotoStatement()        { return stmt == STMT.Goto        ? cast(typeof(return))this : null; }
461     inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
462     inout(GotoCaseStatement)    isGotoCaseStatement()    { return stmt == STMT.GotoCase    ? cast(typeof(return))this : null; }
463     inout(BreakStatement)       isBreakStatement()       { return stmt == STMT.Break       ? cast(typeof(return))this : null; }
464     inout(DtorExpStatement)     isDtorExpStatement()     { return stmt == STMT.DtorExp     ? cast(typeof(return))this : null; }
465     inout(ForwardingStatement)  isForwardingStatement()  { return stmt == STMT.Forwarding  ? cast(typeof(return))this : null; }
466     inout(DoStatement)          isDoStatement()          { return stmt == STMT.Do          ? cast(typeof(return))this : null; }
467     inout(WhileStatement)       isWhileStatement()       { return stmt == STMT.While       ? cast(typeof(return))this : null; }
468     inout(ForStatement)         isForStatement()         { return stmt == STMT.For         ? cast(typeof(return))this : null; }
469     inout(ForeachStatement)     isForeachStatement()     { return stmt == STMT.Foreach     ? cast(typeof(return))this : null; }
470     inout(SwitchStatement)      isSwitchStatement()      { return stmt == STMT.Switch      ? cast(typeof(return))this : null; }
471     inout(ContinueStatement)    isContinueStatement()    { return stmt == STMT.Continue    ? cast(typeof(return))this : null; }
472     inout(WithStatement)        isWithStatement()        { return stmt == STMT.With        ? cast(typeof(return))this : null; }
473     inout(TryCatchStatement)    isTryCatchStatement()    { return stmt == STMT.TryCatch    ? cast(typeof(return))this : null; }
474     inout(ThrowStatement)       isThrowStatement()       { return stmt == STMT.Throw       ? cast(typeof(return))this : null; }
475     inout(TryFinallyStatement)  isTryFinallyStatement()  { return stmt == STMT.TryFinally  ? cast(typeof(return))this : null; }
476     inout(SwitchErrorStatement)  isSwitchErrorStatement()  { return stmt == STMT.SwitchError  ? cast(typeof(return))this : null; }
477     inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
478     inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
479     inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
480 }
481 
482 /***********************************************************
483  * Any Statement that fails semantic() or has a component that is an ErrorExp or
484  * a TypeError should return an ErrorStatement from semantic().
485  */
486 extern (C++) final class ErrorStatement : Statement
487 {
488     extern (D) this()
489     {
490         super(Loc.initial, STMT.Error);
491         assert(global.gaggedErrors || global.errors);
492     }
493 
494     override Statement syntaxCopy()
495     {
496         return this;
497     }
498 
499     override void accept(Visitor v)
500     {
501         v.visit(this);
502     }
503 }
504 
505 /***********************************************************
506  */
507 extern (C++) final class PeelStatement : Statement
508 {
509     Statement s;
510 
511     extern (D) this(Statement s)
512     {
513         super(s.loc, STMT.Peel);
514         this.s = s;
515     }
516 
517     override void accept(Visitor v)
518     {
519         v.visit(this);
520     }
521 }
522 
523 /***********************************************************
524  * Convert TemplateMixin members (== Dsymbols) to Statements.
525  */
526 private Statement toStatement(Dsymbol s)
527 {
528     extern (C++) final class ToStmt : Visitor
529     {
530         alias visit = Visitor.visit;
531     public:
532         Statement result;
533 
534         Statement visitMembers(Loc loc, Dsymbols* a)
535         {
536             if (!a)
537                 return null;
538 
539             auto statements = new Statements();
540             foreach (s; *a)
541             {
542                 statements.push(toStatement(s));
543             }
544             return new CompoundStatement(loc, statements);
545         }
546 
547         override void visit(Dsymbol s)
548         {
549             .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
550             result = new ErrorStatement();
551         }
552 
553         override void visit(TemplateMixin tm)
554         {
555             auto a = new Statements();
556             foreach (m; *tm.members)
557             {
558                 Statement s = toStatement(m);
559                 if (s)
560                     a.push(s);
561             }
562             result = new CompoundStatement(tm.loc, a);
563         }
564 
565         /* An actual declaration symbol will be converted to DeclarationExp
566          * with ExpStatement.
567          */
568         Statement declStmt(Dsymbol s)
569         {
570             auto de = new DeclarationExp(s.loc, s);
571             de.type = Type.tvoid; // avoid repeated semantic
572             return new ExpStatement(s.loc, de);
573         }
574 
575         override void visit(VarDeclaration d)
576         {
577             result = declStmt(d);
578         }
579 
580         override void visit(AggregateDeclaration d)
581         {
582             result = declStmt(d);
583         }
584 
585         override void visit(FuncDeclaration d)
586         {
587             result = declStmt(d);
588         }
589 
590         override void visit(EnumDeclaration d)
591         {
592             result = declStmt(d);
593         }
594 
595         override void visit(AliasDeclaration d)
596         {
597             result = declStmt(d);
598         }
599 
600         override void visit(TemplateDeclaration d)
601         {
602             result = declStmt(d);
603         }
604 
605         /* All attributes have been already picked by the semantic analysis of
606          * 'bottom' declarations (function, struct, class, etc).
607          * So we don't have to copy them.
608          */
609         override void visit(StorageClassDeclaration d)
610         {
611             result = visitMembers(d.loc, d.decl);
612         }
613 
614         override void visit(DeprecatedDeclaration d)
615         {
616             result = visitMembers(d.loc, d.decl);
617         }
618 
619         override void visit(LinkDeclaration d)
620         {
621             result = visitMembers(d.loc, d.decl);
622         }
623 
624         override void visit(ProtDeclaration d)
625         {
626             result = visitMembers(d.loc, d.decl);
627         }
628 
629         override void visit(AlignDeclaration d)
630         {
631             result = visitMembers(d.loc, d.decl);
632         }
633 
634         override void visit(UserAttributeDeclaration d)
635         {
636             result = visitMembers(d.loc, d.decl);
637         }
638 
639         override void visit(ForwardingAttribDeclaration d)
640         {
641             result = visitMembers(d.loc, d.decl);
642         }
643 
644         override void visit(StaticAssert s)
645         {
646         }
647 
648         override void visit(Import s)
649         {
650         }
651 
652         override void visit(PragmaDeclaration d)
653         {
654         }
655 
656         override void visit(ConditionalDeclaration d)
657         {
658             result = visitMembers(d.loc, d.include(null));
659         }
660 
661         override void visit(StaticForeachDeclaration d)
662         {
663             assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe);
664             result = visitMembers(d.loc, d.include(null));
665         }
666 
667         override void visit(CompileDeclaration d)
668         {
669             result = visitMembers(d.loc, d.include(null));
670         }
671     }
672 
673     if (!s)
674         return null;
675 
676     scope ToStmt v = new ToStmt();
677     s.accept(v);
678     return v.result;
679 }
680 
681 /***********************************************************
682  * https://dlang.org/spec/statement.html#ExpressionStatement
683  */
684 extern (C++) class ExpStatement : Statement
685 {
686     Expression exp;
687 
688     final extern (D) this(const ref Loc loc, Expression exp)
689     {
690         super(loc, STMT.Exp);
691         this.exp = exp;
692     }
693 
694     final extern (D) this(const ref Loc loc, Expression exp, STMT stmt)
695     {
696         super(loc, stmt);
697         this.exp = exp;
698     }
699 
700     final extern (D) this(const ref Loc loc, Dsymbol declaration)
701     {
702         super(loc, STMT.Exp);
703         this.exp = new DeclarationExp(loc, declaration);
704     }
705 
706     static ExpStatement create(Loc loc, Expression exp)
707     {
708         return new ExpStatement(loc, exp);
709     }
710 
711     override Statement syntaxCopy()
712     {
713         return new ExpStatement(loc, exp ? exp.syntaxCopy() : null);
714     }
715 
716     override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
717     {
718         //printf("ExpStatement::scopeCode()\n");
719 
720         *sentry = null;
721         *sexception = null;
722         *sfinally = null;
723 
724         if (exp && exp.op == TOK.declaration)
725         {
726             auto de = cast(DeclarationExp)exp;
727             auto v = de.declaration.isVarDeclaration();
728             if (v && !v.isDataseg())
729             {
730                 if (v.needsScopeDtor())
731                 {
732                     *sfinally = new DtorExpStatement(loc, v.edtor, v);
733                     v.storage_class |= STC.nodtor; // don't add in dtor again
734                 }
735             }
736         }
737         return this;
738     }
739 
740     override final Statements* flatten(Scope* sc)
741     {
742         /* https://issues.dlang.org/show_bug.cgi?id=14243
743          * expand template mixin in statement scope
744          * to handle variable destructors.
745          */
746         if (exp && exp.op == TOK.declaration)
747         {
748             Dsymbol d = (cast(DeclarationExp)exp).declaration;
749             if (TemplateMixin tm = d.isTemplateMixin())
750             {
751                 Expression e = exp.expressionSemantic(sc);
752                 if (e.op == TOK.error || tm.errors)
753                 {
754                     auto a = new Statements();
755                     a.push(new ErrorStatement());
756                     return a;
757                 }
758                 assert(tm.members);
759 
760                 Statement s = toStatement(tm);
761                 version (none)
762                 {
763                     OutBuffer buf;
764                     buf.doindent = 1;
765                     HdrGenState hgs;
766                     hgs.hdrgen = true;
767                     toCBuffer(s, &buf, &hgs);
768                     printf("tm ==> s = %s\n", buf.peekChars());
769                 }
770                 auto a = new Statements();
771                 a.push(s);
772                 return a;
773             }
774         }
775         return null;
776     }
777 
778     override void accept(Visitor v)
779     {
780         v.visit(this);
781     }
782 }
783 
784 /***********************************************************
785  */
786 extern (C++) final class DtorExpStatement : ExpStatement
787 {
788     // Wraps an expression that is the destruction of 'var'
789     VarDeclaration var;
790 
791     extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var)
792     {
793         super(loc, exp, STMT.DtorExp);
794         this.var = var;
795     }
796 
797     override Statement syntaxCopy()
798     {
799         return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var);
800     }
801 
802     override void accept(Visitor v)
803     {
804         v.visit(this);
805     }
806 }
807 
808 /***********************************************************
809  * https://dlang.org/spec/statement.html#mixin-statement
810  */
811 extern (C++) final class CompileStatement : Statement
812 {
813     Expressions* exps;
814 
815     extern (D) this(const ref Loc loc, Expression exp)
816     {
817         Expressions* exps = new Expressions();
818         exps.push(exp);
819         this(loc, exps);
820     }
821 
822     extern (D) this(const ref Loc loc, Expressions* exps)
823     {
824         super(loc, STMT.Compile);
825         this.exps = exps;
826     }
827 
828     override Statement syntaxCopy()
829     {
830         return new CompileStatement(loc, Expression.arraySyntaxCopy(exps));
831     }
832 
833     private Statements* compileIt(Scope* sc)
834     {
835         //printf("CompileStatement::compileIt() %s\n", exp.toChars());
836 
837         auto errorStatements()
838         {
839             auto a = new Statements();
840             a.push(new ErrorStatement());
841             return a;
842         }
843 
844 
845         OutBuffer buf;
846         if (expressionsToString(buf, sc, exps))
847             return errorStatements();
848 
849         const errors = global.errors;
850         const len = buf.length;
851         buf.writeByte(0);
852         const str = buf.extractSlice()[0 .. len];
853         scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
854         p.nextToken();
855 
856         auto a = new Statements();
857         while (p.token.value != TOK.endOfFile)
858         {
859             Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
860             p.reportDiagnostics();
861             if (!s || global.errors != errors)
862                 return errorStatements();
863             a.push(s);
864         }
865         return a;
866     }
867 
868     override Statements* flatten(Scope* sc)
869     {
870         //printf("CompileStatement::flatten() %s\n", exp.toChars());
871         return compileIt(sc);
872     }
873 
874     override void accept(Visitor v)
875     {
876         v.visit(this);
877     }
878 }
879 
880 /***********************************************************
881  */
882 extern (C++) class CompoundStatement : Statement
883 {
884     Statements* statements;
885 
886     /**
887      * Construct a `CompoundStatement` using an already existing
888      * array of `Statement`s
889      *
890      * Params:
891      *   loc = Instantiation information
892      *   statements   = An array of `Statement`s, that will referenced by this class
893      */
894     final extern (D) this(const ref Loc loc, Statements* statements)
895     {
896         super(loc, STMT.Compound);
897         this.statements = statements;
898     }
899 
900     final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt)
901     {
902         super(loc, stmt);
903         this.statements = statements;
904     }
905 
906     /**
907      * Construct a `CompoundStatement` from an array of `Statement`s
908      *
909      * Params:
910      *   loc = Instantiation information
911      *   sts   = A variadic array of `Statement`s, that will copied in this class
912      *         The entries themselves will not be copied.
913      */
914     final extern (D) this(const ref Loc loc, Statement[] sts...)
915     {
916         super(loc, STMT.Compound);
917         statements = new Statements();
918         statements.reserve(sts.length);
919         foreach (s; sts)
920             statements.push(s);
921     }
922 
923     static CompoundStatement create(Loc loc, Statement s1, Statement s2)
924     {
925         return new CompoundStatement(loc, s1, s2);
926     }
927 
928     override Statement syntaxCopy()
929     {
930         return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements));
931     }
932 
933     override Statements* flatten(Scope* sc)
934     {
935         return statements;
936     }
937 
938     override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
939     {
940         foreach (s; *statements)
941         {
942             if (s)
943             {
944                 if (inout rs = s.endsWithReturnStatement())
945                     return rs;
946             }
947         }
948         return null;
949     }
950 
951     override final inout(Statement) last() inout nothrow pure
952     {
953         Statement s = null;
954         for (size_t i = statements.dim; i; --i)
955         {
956             s = cast(Statement)(*statements)[i - 1];
957             if (s)
958             {
959                 s = cast(Statement)s.last();
960                 if (s)
961                     break;
962             }
963         }
964         return cast(inout)s;
965     }
966 
967     override void accept(Visitor v)
968     {
969         v.visit(this);
970     }
971 }
972 
973 /***********************************************************
974  */
975 extern (C++) final class CompoundDeclarationStatement : CompoundStatement
976 {
977     extern (D) this(const ref Loc loc, Statements* statements)
978     {
979         super(loc, statements, STMT.CompoundDeclaration);
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 CompoundDeclarationStatement(loc, a);
990     }
991 
992     override void accept(Visitor v)
993     {
994         v.visit(this);
995     }
996 }
997 
998 /***********************************************************
999  * The purpose of this is so that continue will go to the next
1000  * of the statements, and break will go to the end of the statements.
1001  */
1002 extern (C++) final class UnrolledLoopStatement : Statement
1003 {
1004     Statements* statements;
1005 
1006     extern (D) this(const ref Loc loc, Statements* statements)
1007     {
1008         super(loc, STMT.UnrolledLoop);
1009         this.statements = statements;
1010     }
1011 
1012     override Statement syntaxCopy()
1013     {
1014         auto a = new Statements(statements.dim);
1015         foreach (i, s; *statements)
1016         {
1017             (*a)[i] = s ? s.syntaxCopy() : null;
1018         }
1019         return new UnrolledLoopStatement(loc, a);
1020     }
1021 
1022     override bool hasBreak() const pure nothrow
1023     {
1024         return true;
1025     }
1026 
1027     override bool hasContinue() const pure nothrow
1028     {
1029         return true;
1030     }
1031 
1032     override void accept(Visitor v)
1033     {
1034         v.visit(this);
1035     }
1036 }
1037 
1038 /***********************************************************
1039  */
1040 extern (C++) class ScopeStatement : Statement
1041 {
1042     Statement statement;
1043     Loc endloc;                 // location of closing curly bracket
1044 
1045     extern (D) this(const ref Loc loc, Statement statement, Loc endloc)
1046     {
1047         super(loc, STMT.Scope);
1048         this.statement = statement;
1049         this.endloc = endloc;
1050     }
1051     override Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement syntaxCopy()
1620     {
1621         return new StaticAssertStatement(cast(StaticAssert)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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 Statement 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 }