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