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