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