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