1
/**
2
 * Defines AST nodes for statements.
3
 *
4
 * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements)
5
 *
6
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d)
10
 * Documentation:  https://dlang.org/phobos/dmd_statement.html
11
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d
12
 */
13

14
module dmd.statement;
15

16
import core.stdc.stdarg;
17
import core.stdc.stdio;
18

19
import dmd.aggregate;
20
import dmd.arraytypes;
21
import dmd.attrib;
22
import dmd.astcodegen;
23
import dmd.ast_node;
24
import dmd.gluelayer;
25
import dmd.canthrow;
26
import dmd.cond;
27
import dmd.dclass;
28
import dmd.declaration;
29
import dmd.denum;
30
import dmd.dimport;
31
import dmd.dscope;
32
import dmd.dsymbol;
33
import dmd.dsymbolsem;
34
import dmd.dtemplate;
35
import dmd.errors;
36
import dmd.expression;
37
import dmd.expressionsem;
38
import dmd.func;
39
import dmd.globals;
40
import dmd.hdrgen;
41
import dmd.id;
42
import dmd.identifier;
43
import dmd.dinterpret;
44
import dmd.mtype;
45
import dmd.parse;
46
import dmd.root.outbuffer;
47
import dmd.root.rmem;
48
import dmd.root.rootobject;
49
import dmd.sapply;
50
import dmd.sideeffect;
51
import dmd.staticassert;
52
import dmd.tokens;
53
import dmd.visitor;
54

55
/**
56
 * Returns:
57
 *     `TypeIdentifier` corresponding to `object.Throwable`
58
 */
59
TypeIdentifier getThrowable()
60
{
61 1
    auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty);
62 1
    tid.addIdent(Id.object);
63 1
    tid.addIdent(Id.Throwable);
64 1
    return tid;
65
}
66

67
/**
68
 * Returns:
69
 *      TypeIdentifier corresponding to `object.Exception`
70
 */
71
TypeIdentifier getException()
72
{
73 1
    auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty);
74 1
    tid.addIdent(Id.object);
75 1
    tid.addIdent(Id.Exception);
76 1
    return tid;
77
}
78

79
/********************************
80
 * Identify Statement types with this enum rather than
81
 * virtual functions.
82
 */
83

84
enum STMT : ubyte
85
{
86
    Error,
87
    Peel,
88
    Exp, DtorExp,
89
    Compile,
90
    Compound, CompoundDeclaration, CompoundAsm,
91
    UnrolledLoop,
92
    Scope,
93
    Forwarding,
94
    While,
95
    Do,
96
    For,
97
    Foreach,
98
    ForeachRange,
99
    If,
100
    Conditional,
101
    StaticForeach,
102
    Pragma,
103
    StaticAssert,
104
    Switch,
105
    Case,
106
    CaseRange,
107
    Default,
108
    GotoDefault,
109
    GotoCase,
110
    SwitchError,
111
    Return,
112
    Break,
113
    Continue,
114
    Synchronized,
115
    With,
116
    TryCatch,
117
    TryFinally,
118
    ScopeGuard,
119
    Throw,
120
    Debug,
121
    Goto,
122
    Label,
123
    Asm, InlineAsm, GccAsm,
124
    Import,
125
}
126

127

128
/***********************************************************
129
 * Specification: http://dlang.org/spec/statement.html
130
 */
131
extern (C++) abstract class Statement : ASTNode
132
{
133
    const Loc loc;
134
    const STMT stmt;
135

136
    override final DYNCAST dyncast() const
137
    {
138 0
        return DYNCAST.statement;
139
    }
140

141 1
    final extern (D) this(const ref Loc loc, STMT stmt)
142
    {
143 1
        this.loc = loc;
144 1
        this.stmt = stmt;
145
        // If this is an in{} contract scope statement (skip for determining
146
        //  inlineStatus of a function body for header content)
147
    }
148

149
    Statement syntaxCopy()
150
    {
151 0
        assert(0);
152
    }
153

154
    /*************************************
155
     * Do syntax copy of an array of Statement's.
156
     */
157
    static Statements* arraySyntaxCopy(Statements* a)
158
    {
159 1
        Statements* b = null;
160 1
        if (a)
161
        {
162 1
            b = a.copy();
163 1
            foreach (i, s; *a)
164
            {
165 1
                (*b)[i] = s ? s.syntaxCopy() : null;
166
            }
167
        }
168 1
        return b;
169
    }
170

171
    override final const(char)* toChars() const
172
    {
173 0
        HdrGenState hgs;
174 0
        OutBuffer buf;
175 0
        .toCBuffer(this, &buf, &hgs);
176 0
        buf.writeByte(0);
177 0
        return buf.extractSlice().ptr;
178
    }
179

180
    final void error(const(char)* format, ...)
181
    {
182 1
        va_list ap;
183 1
        va_start(ap, format);
184 1
        .verror(loc, format, ap);
185 1
        va_end(ap);
186
    }
187

188
    final void warning(const(char)* format, ...)
189
    {
190 1
        va_list ap;
191 1
        va_start(ap, format);
192 1
        .vwarning(loc, format, ap);
193 1
        va_end(ap);
194
    }
195

196
    final void deprecation(const(char)* format, ...)
197
    {
198 1
        va_list ap;
199 1
        va_start(ap, format);
200 1
        .vdeprecation(loc, format, ap);
201 1
        va_end(ap);
202
    }
203

204
    Statement getRelatedLabeled()
205
    {
206 1
        return this;
207
    }
208

209
    /****************************
210
     * Determine if an enclosed `break` would apply to this
211
     * statement, such as if it is a loop or switch statement.
212
     * Returns:
213
     *     `true` if it does
214
     */
215
    bool hasBreak() const pure nothrow
216
    {
217
        //printf("Statement::hasBreak()\n");
218 1
        return false;
219
    }
220

221
    /****************************
222
     * Determine if an enclosed `continue` would apply to this
223
     * statement, such as if it is a loop statement.
224
     * Returns:
225
     *     `true` if it does
226
     */
227
    bool hasContinue() const pure nothrow
228
    {
229 0
        return false;
230
    }
231

232
    /**********************************
233
     * Returns:
234
     *     `true` if statement uses exception handling
235
     */
236
    final bool usesEH()
237
    {
238 0
        extern (C++) final class UsesEH : StoppableVisitor
239
        {
240
            alias visit = typeof(super).visit;
241
        public:
242
            override void visit(Statement s)
243
            {
244
            }
245

246
            override void visit(TryCatchStatement s)
247
            {
248 0
                stop = true;
249
            }
250

251
            override void visit(TryFinallyStatement s)
252
            {
253 0
                stop = true;
254
            }
255

256
            override void visit(ScopeGuardStatement s)
257
            {
258 0
                stop = true;
259
            }
260

261
            override void visit(SynchronizedStatement s)
262
            {
263 0
                stop = true;
264
            }
265
        }
266

267 0
        scope UsesEH ueh = new UsesEH();
268 0
        return walkPostorder(this, ueh);
269
    }
270

271
    /**********************************
272
     * Returns:
273
     *   `true` if statement 'comes from' somewhere else, like a goto
274
     */
275
    final bool comeFrom()
276
    {
277 1
        extern (C++) final class ComeFrom : StoppableVisitor
278
        {
279
            alias visit = typeof(super).visit;
280
        public:
281
            override void visit(Statement s)
282
            {
283
            }
284

285
            override void visit(CaseStatement s)
286
            {
287 1
                stop = true;
288
            }
289

290
            override void visit(DefaultStatement s)
291
            {
292 1
                stop = true;
293
            }
294

295
            override void visit(LabelStatement s)
296
            {
297 1
                stop = true;
298
            }
299

300
            override void visit(AsmStatement s)
301
            {
302 0
                stop = true;
303
            }
304
        }
305

306 1
        scope ComeFrom cf = new ComeFrom();
307 1
        return walkPostorder(this, cf);
308
    }
309

310
    /**********************************
311
     * Returns:
312
     *   `true` if statement has executable code.
313
     */
314
    final bool hasCode()
315
    {
316 1
        extern (C++) final class HasCode : StoppableVisitor
317
        {
318
            alias visit = typeof(super).visit;
319
        public:
320
            override void visit(Statement s)
321
            {
322 1
                stop = true;
323
            }
324

325
            override void visit(ExpStatement s)
326
            {
327 1
                if (s.exp !is null)
328
                {
329 1
                    stop = s.exp.hasCode();
330
                }
331
            }
332

333
            override void visit(CompoundStatement s)
334
            {
335
            }
336

337
            override void visit(ScopeStatement s)
338
            {
339
            }
340

341
            override void visit(ImportStatement s)
342
            {
343
            }
344
        }
345

346 1
        scope HasCode hc = new HasCode();
347 1
        return walkPostorder(this, hc);
348
    }
349

350
    /****************************************
351
     * If this statement has code that needs to run in a finally clause
352
     * at the end of the current scope, return that code in the form of
353
     * a Statement.
354
     * Params:
355
     *     sc = context
356
     *     sentry     = set to code executed upon entry to the scope
357
     *     sexception = set to code executed upon exit from the scope via exception
358
     *     sfinally   = set to code executed in finally block
359
     * Returns:
360
     *    code to be run in the finally clause
361
     */
362
    Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
363
    {
364
        //printf("Statement::scopeCode()\n");
365 1
        *sentry = null;
366 1
        *sexception = null;
367 1
        *sfinally = null;
368 1
        return this;
369
    }
370

371
    /*********************************
372
     * Flatten out the scope by presenting the statement
373
     * as an array of statements.
374
     * Params:
375
     *     sc = context
376
     * Returns:
377
     *     The array of `Statements`, or `null` if no flattening necessary
378
     */
379
    Statements* flatten(Scope* sc)
380
    {
381 1
        return null;
382
    }
383

384
    /*******************************
385
     * Find last statement in a sequence of statements.
386
     * Returns:
387
     *  the last statement, or `null` if there isn't one
388
     */
389
    inout(Statement) last() inout nothrow pure
390
    {
391 1
        return this;
392
    }
393

394
    /**************************
395
     * Support Visitor Pattern
396
     * Params:
397
     *  v = visitor
398
     */
399
    override void accept(Visitor v)
400
    {
401 0
        v.visit(this);
402
    }
403

404
    /************************************
405
     * Does this statement end with a return statement?
406
     *
407
     * I.e. is it a single return statement or some compound statement
408
     * that unconditionally hits a return statement.
409
     * Returns:
410
     *  return statement it ends with, otherwise null
411
     */
412
    pure nothrow @nogc
413 1
    inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
414

415
  final pure inout nothrow @nogc:
416

417
    /********************
418
     * A cheaper method of doing downcasting of Statements.
419
     * Returns:
420
     *    the downcast statement if it can be downcasted, otherwise `null`
421
     */
422 1
    inout(ErrorStatement)       isErrorStatement()       { return stmt == STMT.Error       ? cast(typeof(return))this : null; }
423 1
    inout(ScopeStatement)       isScopeStatement()       { return stmt == STMT.Scope       ? cast(typeof(return))this : null; }
424 1
    inout(ExpStatement)         isExpStatement()         { return stmt == STMT.Exp         ? cast(typeof(return))this : null; }
425 1
    inout(CompoundStatement)    isCompoundStatement()    { return stmt == STMT.Compound    ? cast(typeof(return))this : null; }
426 1
    inout(ReturnStatement)      isReturnStatement()      { return stmt == STMT.Return      ? cast(typeof(return))this : null; }
427 1
    inout(IfStatement)          isIfStatement()          { return stmt == STMT.If          ? cast(typeof(return))this : null; }
428 1
    inout(CaseStatement)        isCaseStatement()        { return stmt == STMT.Case        ? cast(typeof(return))this : null; }
429 1
    inout(DefaultStatement)     isDefaultStatement()     { return stmt == STMT.Default     ? cast(typeof(return))this : null; }
430 0
    inout(LabelStatement)       isLabelStatement()       { return stmt == STMT.Label       ? cast(typeof(return))this : null; }
431 1
    inout(GotoStatement)        isGotoStatement()        { return stmt == STMT.Goto        ? cast(typeof(return))this : null; }
432 0
    inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
433 0
    inout(GotoCaseStatement)    isGotoCaseStatement()    { return stmt == STMT.GotoCase    ? cast(typeof(return))this : null; }
434 0
    inout(BreakStatement)       isBreakStatement()       { return stmt == STMT.Break       ? cast(typeof(return))this : null; }
435 1
    inout(DtorExpStatement)     isDtorExpStatement()     { return stmt == STMT.DtorExp     ? cast(typeof(return))this : null; }
436 1
    inout(ForwardingStatement)  isForwardingStatement()  { return stmt == STMT.Forwarding  ? cast(typeof(return))this : null; }
437 0
    inout(DoStatement)          isDoStatement()          { return stmt == STMT.Do          ? cast(typeof(return))this : null; }
438 0
    inout(WhileStatement)       isWhileStatement()       { return stmt == STMT.While       ? cast(typeof(return))this : null; }
439 1
    inout(ForStatement)         isForStatement()         { return stmt == STMT.For         ? cast(typeof(return))this : null; }
440 0
    inout(ForeachStatement)     isForeachStatement()     { return stmt == STMT.Foreach     ? cast(typeof(return))this : null; }
441 0
    inout(SwitchStatement)      isSwitchStatement()      { return stmt == STMT.Switch      ? cast(typeof(return))this : null; }
442 0
    inout(ContinueStatement)    isContinueStatement()    { return stmt == STMT.Continue    ? cast(typeof(return))this : null; }
443 0
    inout(WithStatement)        isWithStatement()        { return stmt == STMT.With        ? cast(typeof(return))this : null; }
444 0
    inout(TryCatchStatement)    isTryCatchStatement()    { return stmt == STMT.TryCatch    ? cast(typeof(return))this : null; }
445 1
    inout(ThrowStatement)       isThrowStatement()       { return stmt == STMT.Throw       ? cast(typeof(return))this : null; }
446 1
    inout(TryFinallyStatement)  isTryFinallyStatement()  { return stmt == STMT.TryFinally  ? cast(typeof(return))this : null; }
447 0
    inout(SwitchErrorStatement)  isSwitchErrorStatement()  { return stmt == STMT.SwitchError  ? cast(typeof(return))this : null; }
448 0
    inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
449 0
    inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
450 0
    inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
451
}
452

453
/***********************************************************
454
 * Any Statement that fails semantic() or has a component that is an ErrorExp or
455
 * a TypeError should return an ErrorStatement from semantic().
456
 */
457
extern (C++) final class ErrorStatement : Statement
458
{
459 1
    extern (D) this()
460
    {
461 1
        super(Loc.initial, STMT.Error);
462 1
        assert(global.gaggedErrors || global.errors);
463
    }
464

465
    override Statement syntaxCopy()
466
    {
467 0
        return this;
468
    }
469

470
    override void accept(Visitor v)
471
    {
472 1
        v.visit(this);
473
    }
474
}
475

476
/***********************************************************
477
 */
478
extern (C++) final class PeelStatement : Statement
479
{
480
    Statement s;
481

482 1
    extern (D) this(Statement s)
483
    {
484 1
        super(s.loc, STMT.Peel);
485 1
        this.s = s;
486
    }
487

488
    override void accept(Visitor v)
489
    {
490 1
        v.visit(this);
491
    }
492
}
493

494
/***********************************************************
495
 * Convert TemplateMixin members (== Dsymbols) to Statements.
496
 */
497
private Statement toStatement(Dsymbol s)
498
{
499
    extern (C++) final class ToStmt : Visitor
500
    {
501
        alias visit = Visitor.visit;
502
    public:
503
        Statement result;
504

505
        Statement visitMembers(Loc loc, Dsymbols* a)
506
        {
507 1
            if (!a)
508 0
                return null;
509

510 1
            auto statements = new Statements();
511 1
            foreach (s; *a)
512
            {
513 1
                statements.push(toStatement(s));
514
            }
515 1
            return new CompoundStatement(loc, statements);
516
        }
517

518
        override void visit(Dsymbol s)
519
        {
520 0
            .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
521 0
            result = new ErrorStatement();
522
        }
523

524
        override void visit(TemplateMixin tm)
525
        {
526 1
            auto a = new Statements();
527 1
            foreach (m; *tm.members)
528
            {
529 1
                Statement s = toStatement(m);
530 1
                if (s)
531 1
                    a.push(s);
532
            }
533 1
            result = new CompoundStatement(tm.loc, a);
534
        }
535

536
        /* An actual declaration symbol will be converted to DeclarationExp
537
         * with ExpStatement.
538
         */
539
        Statement declStmt(Dsymbol s)
540
        {
541 1
            auto de = new DeclarationExp(s.loc, s);
542 1
            de.type = Type.tvoid; // avoid repeated semantic
543 1
            return new ExpStatement(s.loc, de);
544
        }
545

546
        override void visit(VarDeclaration d)
547
        {
548 1
            result = declStmt(d);
549
        }
550

551
        override void visit(AggregateDeclaration d)
552
        {
553 1
            result = declStmt(d);
554
        }
555

556
        override void visit(FuncDeclaration d)
557
        {
558 1
            result = declStmt(d);
559
        }
560

561
        override void visit(EnumDeclaration d)
562
        {
563 1
            result = declStmt(d);
564
        }
565

566
        override void visit(AliasDeclaration d)
567
        {
568 1
            result = declStmt(d);
569
        }
570

571
        override void visit(TemplateDeclaration d)
572
        {
573 1
            result = declStmt(d);
574
        }
575

576
        /* All attributes have been already picked by the semantic analysis of
577
         * 'bottom' declarations (function, struct, class, etc).
578
         * So we don't have to copy them.
579
         */
580
        override void visit(StorageClassDeclaration d)
581
        {
582 1
            result = visitMembers(d.loc, d.decl);
583
        }
584

585
        override void visit(DeprecatedDeclaration d)
586
        {
587 0
            result = visitMembers(d.loc, d.decl);
588
        }
589

590
        override void visit(LinkDeclaration d)
591
        {
592 0
            result = visitMembers(d.loc, d.decl);
593
        }
594

595
        override void visit(ProtDeclaration d)
596
        {
597 0
            result = visitMembers(d.loc, d.decl);
598
        }
599

600
        override void visit(AlignDeclaration d)
601
        {
602 0
            result = visitMembers(d.loc, d.decl);
603
        }
604

605
        override void visit(UserAttributeDeclaration d)
606
        {
607 0
            result = visitMembers(d.loc, d.decl);
608
        }
609

610
        override void visit(ForwardingAttribDeclaration d)
611
        {
612 1
            result = visitMembers(d.loc, d.decl);
613
        }
614

615
        override void visit(StaticAssert s)
616
        {
617
        }
618

619
        override void visit(Import s)
620
        {
621
        }
622

623
        override void visit(PragmaDeclaration d)
624
        {
625
        }
626

627
        override void visit(ConditionalDeclaration d)
628
        {
629 1
            result = visitMembers(d.loc, d.include(null));
630
        }
631

632
        override void visit(StaticForeachDeclaration d)
633
        {
634 1
            assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe);
635 1
            result = visitMembers(d.loc, d.include(null));
636
        }
637

638
        override void visit(CompileDeclaration d)
639
        {
640 1
            result = visitMembers(d.loc, d.include(null));
641
        }
642
    }
643

644 1
    if (!s)
645 0
        return null;
646

647 1
    scope ToStmt v = new ToStmt();
648 1
    s.accept(v);
649 1
    return v.result;
650
}
651

652
/***********************************************************
653
 * https://dlang.org/spec/statement.html#ExpressionStatement
654
 */
655
extern (C++) class ExpStatement : Statement
656
{
657
    Expression exp;
658

659 1
    final extern (D) this(const ref Loc loc, Expression exp)
660
    {
661 1
        super(loc, STMT.Exp);
662 1
        this.exp = exp;
663
    }
664

665 1
    final extern (D) this(const ref Loc loc, Expression exp, STMT stmt)
666
    {
667 1
        super(loc, stmt);
668 1
        this.exp = exp;
669
    }
670

671 1
    final extern (D) this(const ref Loc loc, Dsymbol declaration)
672
    {
673 1
        super(loc, STMT.Exp);
674 1
        this.exp = new DeclarationExp(loc, declaration);
675
    }
676

677
    static ExpStatement create(Loc loc, Expression exp)
678
    {
679 1
        return new ExpStatement(loc, exp);
680
    }
681

682
    override Statement syntaxCopy()
683
    {
684 1
        return new ExpStatement(loc, exp ? exp.syntaxCopy() : null);
685
    }
686

687
    override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
688
    {
689
        //printf("ExpStatement::scopeCode()\n");
690

691 1
        *sentry = null;
692 1
        *sexception = null;
693 1
        *sfinally = null;
694

695 1
        if (exp && exp.op == TOK.declaration)
696
        {
697 1
            auto de = cast(DeclarationExp)exp;
698 1
            auto v = de.declaration.isVarDeclaration();
699 1
            if (v && !v.isDataseg())
700
            {
701 1
                if (v.needsScopeDtor())
702
                {
703 1
                    *sfinally = new DtorExpStatement(loc, v.edtor, v);
704 1
                    v.storage_class |= STC.nodtor; // don't add in dtor again
705
                }
706
            }
707
        }
708 1
        return this;
709
    }
710

711
    override final Statements* flatten(Scope* sc)
712
    {
713
        /* https://issues.dlang.org/show_bug.cgi?id=14243
714
         * expand template mixin in statement scope
715
         * to handle variable destructors.
716
         */
717 1
        if (exp && exp.op == TOK.declaration)
718
        {
719 1
            Dsymbol d = (cast(DeclarationExp)exp).declaration;
720 1
            if (TemplateMixin tm = d.isTemplateMixin())
721
            {
722 1
                Expression e = exp.expressionSemantic(sc);
723 1
                if (e.op == TOK.error || tm.errors)
724
                {
725 1
                    auto a = new Statements();
726 1
                    a.push(new ErrorStatement());
727 1
                    return a;
728
                }
729 1
                assert(tm.members);
730

731 1
                Statement s = toStatement(tm);
732
                version (none)
733
                {
734
                    OutBuffer buf;
735
                    buf.doindent = 1;
736
                    HdrGenState hgs;
737
                    hgs.hdrgen = true;
738
                    toCBuffer(s, &buf, &hgs);
739
                    printf("tm ==> s = %s\n", buf.peekChars());
740
                }
741 1
                auto a = new Statements();
742 1
                a.push(s);
743 1
                return a;
744
            }
745
        }
746 1
        return null;
747
    }
748

749
    override void accept(Visitor v)
750
    {
751 1
        v.visit(this);
752
    }
753
}
754

755
/***********************************************************
756
 */
757
extern (C++) final class DtorExpStatement : ExpStatement
758
{
759
    // Wraps an expression that is the destruction of 'var'
760
    VarDeclaration var;
761

762 1
    extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var)
763
    {
764 1
        super(loc, exp, STMT.DtorExp);
765 1
        this.var = var;
766
    }
767

768
    override Statement syntaxCopy()
769
    {
770 0
        return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var);
771
    }
772

773
    override void accept(Visitor v)
774
    {
775 1
        v.visit(this);
776
    }
777
}
778

779
/***********************************************************
780
 * https://dlang.org/spec/statement.html#mixin-statement
781
 */
782
extern (C++) final class CompileStatement : Statement
783
{
784
    Expressions* exps;
785

786 1
    extern (D) this(const ref Loc loc, Expression exp)
787
    {
788 1
        Expressions* exps = new Expressions();
789 1
        exps.push(exp);
790 1
        this(loc, exps);
791
    }
792

793 1
    extern (D) this(const ref Loc loc, Expressions* exps)
794
    {
795 1
        super(loc, STMT.Compile);
796 1
        this.exps = exps;
797
    }
798

799
    override Statement syntaxCopy()
800
    {
801 1
        return new CompileStatement(loc, Expression.arraySyntaxCopy(exps));
802
    }
803

804
    private Statements* compileIt(Scope* sc)
805
    {
806
        //printf("CompileStatement::compileIt() %s\n", exp.toChars());
807

808
        auto errorStatements()
809
        {
810 1
            auto a = new Statements();
811 1
            a.push(new ErrorStatement());
812 1
            return a;
813
        }
814

815

816 1
        OutBuffer buf;
817 1
        if (expressionsToString(buf, sc, exps))
818 1
            return errorStatements();
819

820 1
        const errors = global.errors;
821 1
        const len = buf.length;
822 1
        buf.writeByte(0);
823 1
        const str = buf.extractSlice()[0 .. len];
824 1
        scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
825 1
        p.nextToken();
826

827 1
        auto a = new Statements();
828 1
        while (p.token.value != TOK.endOfFile)
829
        {
830 1
            Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
831 1
            if (!s || global.errors != errors)
832 1
                return errorStatements();
833 1
            a.push(s);
834
        }
835 1
        return a;
836
    }
837

838
    override Statements* flatten(Scope* sc)
839
    {
840
        //printf("CompileStatement::flatten() %s\n", exp.toChars());
841 1
        return compileIt(sc);
842
    }
843

844
    override void accept(Visitor v)
845
    {
846 1
        v.visit(this);
847
    }
848
}
849

850
/***********************************************************
851
 */
852
extern (C++) class CompoundStatement : Statement
853
{
854
    Statements* statements;
855

856
    /**
857
     * Construct a `CompoundStatement` using an already existing
858
     * array of `Statement`s
859
     *
860
     * Params:
861
     *   loc = Instantiation information
862
     *   statements   = An array of `Statement`s, that will referenced by this class
863
     */
864 1
    final extern (D) this(const ref Loc loc, Statements* statements)
865
    {
866 1
        super(loc, STMT.Compound);
867 1
        this.statements = statements;
868
    }
869

870 1
    final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt)
871
    {
872 1
        super(loc, stmt);
873 1
        this.statements = statements;
874
    }
875

876
    /**
877
     * Construct a `CompoundStatement` from an array of `Statement`s
878
     *
879
     * Params:
880
     *   loc = Instantiation information
881
     *   sts   = A variadic array of `Statement`s, that will copied in this class
882
     *         The entries themselves will not be copied.
883
     */
884 1
    final extern (D) this(const ref Loc loc, Statement[] sts...)
885
    {
886 1
        super(loc, STMT.Compound);
887 1
        statements = new Statements();
888 1
        statements.reserve(sts.length);
889 1
        foreach (s; sts)
890 1
            statements.push(s);
891
    }
892

893
    static CompoundStatement create(Loc loc, Statement s1, Statement s2)
894
    {
895 1
        return new CompoundStatement(loc, s1, s2);
896
    }
897

898
    override Statement syntaxCopy()
899
    {
900 1
        return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements));
901
    }
902

903
    override Statements* flatten(Scope* sc)
904
    {
905 1
        return statements;
906
    }
907

908
    override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
909
    {
910 1
        foreach (s; *statements)
911
        {
912 1
            if (s)
913
            {
914 1
                if (inout rs = s.endsWithReturnStatement())
915 1
                    return rs;
916
            }
917
        }
918 1
        return null;
919
    }
920

921
    override final inout(Statement) last() inout nothrow pure
922
    {
923 1
        Statement s = null;
924 1
        for (size_t i = statements.dim; i; --i)
925
        {
926 1
            s = cast(Statement)(*statements)[i - 1];
927 1
            if (s)
928
            {
929 1
                s = cast(Statement)s.last();
930 1
                if (s)
931 1
                    break;
932
            }
933
        }
934 1
        return cast(inout)s;
935
    }
936

937
    override void accept(Visitor v)
938
    {
939 1
        v.visit(this);
940
    }
941
}
942

943
/***********************************************************
944
 */
945
extern (C++) final class CompoundDeclarationStatement : CompoundStatement
946
{
947 1
    extern (D) this(const ref Loc loc, Statements* statements)
948
    {
949 1
        super(loc, statements, STMT.CompoundDeclaration);
950
    }
951

952
    override Statement syntaxCopy()
953
    {
954 1
        auto a = new Statements(statements.dim);
955 1
        foreach (i, s; *statements)
956
        {
957 1
            (*a)[i] = s ? s.syntaxCopy() : null;
958
        }
959 1
        return new CompoundDeclarationStatement(loc, a);
960
    }
961

962
    override void accept(Visitor v)
963
    {
964 1
        v.visit(this);
965
    }
966
}
967

968
/***********************************************************
969
 * The purpose of this is so that continue will go to the next
970
 * of the statements, and break will go to the end of the statements.
971
 */
972
extern (C++) final class UnrolledLoopStatement : Statement
973
{
974
    Statements* statements;
975

976 1
    extern (D) this(const ref Loc loc, Statements* statements)
977
    {
978 1
        super(loc, STMT.UnrolledLoop);
979 1
        this.statements = statements;
980
    }
981

982
    override Statement syntaxCopy()
983
    {
984 0
        auto a = new Statements(statements.dim);
985 0
        foreach (i, s; *statements)
986
        {
987 0
            (*a)[i] = s ? s.syntaxCopy() : null;
988
        }
989 0
        return new UnrolledLoopStatement(loc, a);
990
    }
991

992
    override bool hasBreak() const pure nothrow
993
    {
994 0
        return true;
995
    }
996

997
    override bool hasContinue() const pure nothrow
998
    {
999 0
        return true;
1000
    }
1001

1002
    override void accept(Visitor v)
1003
    {
1004 1
        v.visit(this);
1005
    }
1006
}
1007

1008
/***********************************************************
1009
 */
1010
extern (C++) class ScopeStatement : Statement
1011
{
1012
    Statement statement;
1013
    Loc endloc;                 // location of closing curly bracket
1014

1015 1
    extern (D) this(const ref Loc loc, Statement statement, Loc endloc)
1016
    {
1017 1
        super(loc, STMT.Scope);
1018 1
        this.statement = statement;
1019 1
        this.endloc = endloc;
1020
    }
1021
    override Statement syntaxCopy()
1022
    {
1023 1
        return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc);
1024
    }
1025

1026
    override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
1027
    {
1028 1
        if (statement)
1029 1
            return statement.endsWithReturnStatement();
1030 0
        return null;
1031
    }
1032

1033
    override bool hasBreak() const pure nothrow
1034
    {
1035
        //printf("ScopeStatement::hasBreak() %s\n", toChars());
1036 1
        return statement ? statement.hasBreak() : false;
1037
    }
1038

1039
    override bool hasContinue() const pure nothrow
1040
    {
1041 0
        return statement ? statement.hasContinue() : false;
1042
    }
1043

1044
    override void accept(Visitor v)
1045
    {
1046 1
        v.visit(this);
1047
    }
1048
}
1049

1050
/***********************************************************
1051
 * Statement whose symbol table contains foreach index variables in a
1052
 * local scope and forwards other members to the parent scope.  This
1053
 * wraps a statement.
1054
 *
1055
 * Also see: `dmd.attrib.ForwardingAttribDeclaration`
1056
 */
1057
extern (C++) final class ForwardingStatement : Statement
1058
{
1059
    /// The symbol containing the `static foreach` variables.
1060
    ForwardingScopeDsymbol sym = null;
1061
    /// The wrapped statement.
1062
    Statement statement;
1063

1064 1
    extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement)
1065
    {
1066 1
        super(loc, STMT.Forwarding);
1067 1
        this.sym = sym;
1068 1
        assert(statement);
1069 1
        this.statement = statement;
1070
    }
1071

1072 1
    extern (D) this(const ref Loc loc, Statement statement)
1073
    {
1074 1
        auto sym = new ForwardingScopeDsymbol(null);
1075 1
        sym.symtab = new DsymbolTable();
1076 1
        this(loc, sym, statement);
1077
    }
1078

1079
    override Statement syntaxCopy()
1080
    {
1081 0
        return new ForwardingStatement(loc, statement.syntaxCopy());
1082
    }
1083

1084
    /***********************
1085
     * ForwardingStatements are distributed over the flattened
1086
     * sequence of statements. This prevents flattening to be
1087
     * "blocked" by a ForwardingStatement and is necessary, for
1088
     * example, to support generating scope guards with `static
1089
     * foreach`:
1090
     *
1091
     *     static foreach(i; 0 .. 10) scope(exit) writeln(i);
1092
     *     writeln("this is printed first");
1093
     *     // then, it prints 10, 9, 8, 7, ...
1094
     */
1095

1096
    override Statements* flatten(Scope* sc)
1097
    {
1098 1
        if (!statement)
1099
        {
1100 0
            return null;
1101
        }
1102 1
        sc = sc.push(sym);
1103 1
        auto a = statement.flatten(sc);
1104 1
        sc = sc.pop();
1105 1
        if (!a)
1106
        {
1107 1
            return a;
1108
        }
1109 1
        auto b = new Statements(a.dim);
1110 1
        foreach (i, s; *a)
1111
        {
1112 1
            (*b)[i] = s ? new ForwardingStatement(s.loc, sym, s) : null;
1113
        }
1114 1
        return b;
1115
    }
1116

1117
    override void accept(Visitor v)
1118
    {
1119 1
        v.visit(this);
1120
    }
1121
}
1122

1123

1124
/***********************************************************
1125
 * https://dlang.org/spec/statement.html#while-statement
1126
 */
1127
extern (C++) final class WhileStatement : Statement
1128
{
1129
    Expression condition;
1130
    Statement _body;
1131
    Loc endloc;             // location of closing curly bracket
1132

1133 1
    extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc)
1134
    {
1135 1
        super(loc, STMT.While);
1136 1
        this.condition = condition;
1137 1
        this._body = _body;
1138 1
        this.endloc = endloc;
1139
    }
1140

1141
    override Statement syntaxCopy()
1142
    {
1143 1
        return new WhileStatement(loc,
1144
            condition.syntaxCopy(),
1145 1
            _body ? _body.syntaxCopy() : null,
1146
            endloc);
1147
    }
1148

1149
    override bool hasBreak() const pure nothrow
1150
    {
1151 1
        return true;
1152
    }
1153

1154
    override bool hasContinue() const pure nothrow
1155
    {
1156 1
        return true;
1157
    }
1158

1159
    override void accept(Visitor v)
1160
    {
1161 1
        v.visit(this);
1162
    }
1163
}
1164

1165
/***********************************************************
1166
 * https://dlang.org/spec/statement.html#do-statement
1167
 */
1168
extern (C++) final class DoStatement : Statement
1169
{
1170
    Statement _body;
1171
    Expression condition;
1172
    Loc endloc;                 // location of ';' after while
1173

1174 1
    extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc)
1175
    {
1176 1
        super(loc, STMT.Do);
1177 1
        this._body = _body;
1178 1
        this.condition = condition;
1179 1
        this.endloc = endloc;
1180
    }
1181

1182
    override Statement syntaxCopy()
1183
    {
1184 1
        return new DoStatement(loc,
1185 1
            _body ? _body.syntaxCopy() : null,
1186
            condition.syntaxCopy(),
1187
            endloc);
1188
    }
1189

1190
    override bool hasBreak() const pure nothrow
1191
    {
1192 1
        return true;
1193
    }
1194

1195
    override bool hasContinue() const pure nothrow
1196
    {
1197 0
        return true;
1198
    }
1199

1200
    override void accept(Visitor v)
1201
    {
1202 1
        v.visit(this);
1203
    }
1204
}
1205

1206
/***********************************************************
1207
 * https://dlang.org/spec/statement.html#for-statement
1208
 */
1209
extern (C++) final class ForStatement : Statement
1210
{
1211
    Statement _init;
1212
    Expression condition;
1213
    Expression increment;
1214
    Statement _body;
1215
    Loc endloc;             // location of closing curly bracket
1216

1217
    // When wrapped in try/finally clauses, this points to the outermost one,
1218
    // which may have an associated label. Internal break/continue statements
1219
    // treat that label as referring to this loop.
1220
    Statement relatedLabeled;
1221

1222 1
    extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc)
1223
    {
1224 1
        super(loc, STMT.For);
1225 1
        this._init = _init;
1226 1
        this.condition = condition;
1227 1
        this.increment = increment;
1228 1
        this._body = _body;
1229 1
        this.endloc = endloc;
1230
    }
1231

1232
    override Statement syntaxCopy()
1233
    {
1234 1
        return new ForStatement(loc,
1235 1
            _init ? _init.syntaxCopy() : null,
1236 1
            condition ? condition.syntaxCopy() : null,
1237 1
            increment ? increment.syntaxCopy() : null,
1238
            _body.syntaxCopy(),
1239
            endloc);
1240
    }
1241

1242
    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
1243
    {
1244
        //printf("ForStatement::scopeCode()\n");
1245 1
        Statement.scopeCode(sc, sentry, sexception, sfinally);
1246 1
        return this;
1247
    }
1248

1249
    override Statement getRelatedLabeled()
1250
    {
1251 1
        return relatedLabeled ? relatedLabeled : this;
1252
    }
1253

1254
    override bool hasBreak() const pure nothrow
1255
    {
1256
        //printf("ForStatement::hasBreak()\n");
1257 1
        return true;
1258
    }
1259

1260
    override bool hasContinue() const pure nothrow
1261
    {
1262 1
        return true;
1263
    }
1264

1265
    override void accept(Visitor v)
1266
    {
1267 1
        v.visit(this);
1268
    }
1269
}
1270

1271
/***********************************************************
1272
 * https://dlang.org/spec/statement.html#foreach-statement
1273
 */
1274
extern (C++) final class ForeachStatement : Statement
1275
{
1276
    TOK op;                     // TOK.foreach_ or TOK.foreach_reverse_
1277
    Parameters* parameters;     // array of Parameters, one for each ForeachType
1278
    Expression aggr;            // ForeachAggregate
1279
    Statement _body;            // NoScopeNonEmptyStatement
1280
    Loc endloc;                 // location of closing curly bracket
1281

1282
    VarDeclaration key;
1283
    VarDeclaration value;
1284

1285
    FuncDeclaration func;       // function we're lexically in
1286

1287
    Statements* cases;          // put breaks, continues, gotos and returns here
1288
    ScopeStatements* gotos;     // forward referenced goto's go here
1289

1290 1
    extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc)
1291
    {
1292 1
        super(loc, STMT.Foreach);
1293 1
        this.op = op;
1294 1
        this.parameters = parameters;
1295 1
        this.aggr = aggr;
1296 1
        this._body = _body;
1297 1
        this.endloc = endloc;
1298
    }
1299

1300
    override Statement syntaxCopy()
1301
    {
1302 1
        return new ForeachStatement(loc, op,
1303
            Parameter.arraySyntaxCopy(parameters),
1304
            aggr.syntaxCopy(),
1305 1
            _body ? _body.syntaxCopy() : null,
1306
            endloc);
1307
    }
1308

1309
    override bool hasBreak() const pure nothrow
1310
    {
1311 1
        return true;
1312
    }
1313

1314
    override bool hasContinue() const pure nothrow
1315
    {
1316 1
        return true;
1317
    }
1318

1319
    override void accept(Visitor v)
1320
    {
1321 1
        v.visit(this);
1322
    }
1323
}
1324

1325
/***********************************************************
1326
 * https://dlang.org/spec/statement.html#foreach-range-statement
1327
 */
1328
extern (C++) final class ForeachRangeStatement : Statement
1329
{
1330
    TOK op;                 // TOK.foreach_ or TOK.foreach_reverse_
1331
    Parameter prm;          // loop index variable
1332
    Expression lwr;
1333
    Expression upr;
1334
    Statement _body;
1335
    Loc endloc;             // location of closing curly bracket
1336

1337
    VarDeclaration key;
1338

1339 1
    extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc)
1340
    {
1341 1
        super(loc, STMT.ForeachRange);
1342 1
        this.op = op;
1343 1
        this.prm = prm;
1344 1
        this.lwr = lwr;
1345 1
        this.upr = upr;
1346 1
        this._body = _body;
1347 1
        this.endloc = endloc;
1348
    }
1349

1350
    override Statement syntaxCopy()
1351
    {
1352 1
        return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
1353
    }
1354

1355
    override bool hasBreak() const pure nothrow
1356
    {
1357 1
        return true;
1358
    }
1359

1360
    override bool hasContinue() const pure nothrow
1361
    {
1362 1
        return true;
1363
    }
1364

1365
    override void accept(Visitor v)
1366
    {
1367 1
        v.visit(this);
1368
    }
1369
}
1370

1371
/***********************************************************
1372
 * https://dlang.org/spec/statement.html#if-statement
1373
 */
1374
extern (C++) final class IfStatement : Statement
1375
{
1376
    Parameter prm;
1377
    Expression condition;
1378
    Statement ifbody;
1379
    Statement elsebody;
1380
    VarDeclaration match;   // for MatchExpression results
1381
    Loc endloc;                 // location of closing curly bracket
1382

1383 1
    extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc)
1384
    {
1385 1
        super(loc, STMT.If);
1386 1
        this.prm = prm;
1387 1
        this.condition = condition;
1388 1
        this.ifbody = ifbody;
1389 1
        this.elsebody = elsebody;
1390 1
        this.endloc = endloc;
1391
    }
1392

1393
    override Statement syntaxCopy()
1394
    {
1395 1
        return new IfStatement(loc,
1396 1
            prm ? prm.syntaxCopy() : null,
1397
            condition.syntaxCopy(),
1398 1
            ifbody ? ifbody.syntaxCopy() : null,
1399 1
            elsebody ? elsebody.syntaxCopy() : null,
1400
            endloc);
1401
    }
1402

1403
    override void accept(Visitor v)
1404
    {
1405 1
        v.visit(this);
1406
    }
1407
}
1408

1409
/***********************************************************
1410
 * https://dlang.org/spec/version.html#ConditionalStatement
1411
 */
1412
extern (C++) final class ConditionalStatement : Statement
1413
{
1414
    Condition condition;
1415
    Statement ifbody;
1416
    Statement elsebody;
1417

1418 1
    extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody)
1419
    {
1420 1
        super(loc, STMT.Conditional);
1421 1
        this.condition = condition;
1422 1
        this.ifbody = ifbody;
1423 1
        this.elsebody = elsebody;
1424
    }
1425

1426
    override Statement syntaxCopy()
1427
    {
1428 1
        return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null);
1429
    }
1430

1431
    override Statements* flatten(Scope* sc)
1432
    {
1433 1
        Statement s;
1434

1435
        //printf("ConditionalStatement::flatten()\n");
1436 1
        if (condition.include(sc))
1437
        {
1438 1
            DebugCondition dc = condition.isDebugCondition();
1439 1
            if (dc)
1440
            {
1441 1
                s = new DebugStatement(loc, ifbody);
1442 1
                debugThrowWalker(ifbody);
1443
            }
1444
            else
1445 1
                s = ifbody;
1446
        }
1447
        else
1448 1
            s = elsebody;
1449

1450 1
        auto a = new Statements();
1451 1
        a.push(s);
1452 1
        return a;
1453
    }
1454

1455
    override void accept(Visitor v)
1456
    {
1457 1
        v.visit(this);
1458
    }
1459
}
1460

1461
/**
1462
Marks all occurring ThrowStatements as internalThrows.
1463
This is intended to be called from a DebugStatement as it allows
1464
to mark all its nodes as nothrow.
1465

1466
Params:
1467
    s = AST Node to traverse
1468
*/
1469
private void debugThrowWalker(Statement s)
1470
{
1471

1472
    extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor
1473
    {
1474
        alias visit = SemanticTimeTransitiveVisitor.visit;
1475
    public:
1476

1477
        override void visit(ThrowStatement s)
1478
        {
1479 1
            s.internalThrow = true;
1480
        }
1481

1482
        override void visit(CallExp s)
1483
        {
1484 1
            s.inDebugStatement = true;
1485
        }
1486
    }
1487

1488 1
    scope walker = new DebugWalker();
1489 1
    s.accept(walker);
1490
}
1491

1492
/***********************************************************
1493
 * https://dlang.org/spec/version.html#StaticForeachStatement
1494
 * Static foreach statements, like:
1495
 *      void main()
1496
 *      {
1497
 *           static foreach(i; 0 .. 10)
1498
 *           {
1499
 *               pragma(msg, i);
1500
 *           }
1501
 *      }
1502
 */
1503
extern (C++) final class StaticForeachStatement : Statement
1504
{
1505
    StaticForeach sfe;
1506

1507 1
    extern (D) this(const ref Loc loc, StaticForeach sfe)
1508
    {
1509 1
        super(loc, STMT.StaticForeach);
1510 1
        this.sfe = sfe;
1511
    }
1512

1513
    override Statement syntaxCopy()
1514
    {
1515 1
        return new StaticForeachStatement(loc, sfe.syntaxCopy());
1516
    }
1517

1518
    override Statements* flatten(Scope* sc)
1519
    {
1520 1
        sfe.prepare(sc);
1521 1
        if (sfe.ready())
1522
        {
1523
            import dmd.statementsem;
1524 1
            auto s = makeTupleForeach!(true, false)(sc, sfe.aggrfe, sfe.needExpansion);
1525 1
            auto result = s.flatten(sc);
1526 1
            if (result)
1527
            {
1528 1
                return result;
1529
            }
1530 1
            result = new Statements();
1531 1
            result.push(s);
1532 1
            return result;
1533
        }
1534
        else
1535
        {
1536 1
            auto result = new Statements();
1537 1
            result.push(new ErrorStatement());
1538 1
            return result;
1539
        }
1540
    }
1541

1542
    override void accept(Visitor v)
1543
    {
1544 0
        v.visit(this);
1545
    }
1546
}
1547

1548
/***********************************************************
1549
 * https://dlang.org/spec/statement.html#pragma-statement
1550
 */
1551
extern (C++) final class PragmaStatement : Statement
1552
{
1553
    const Identifier ident;
1554
    Expressions* args;      // array of Expression's
1555
    Statement _body;
1556

1557 1
    extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body)
1558
    {
1559 1
        super(loc, STMT.Pragma);
1560 1
        this.ident = ident;
1561 1
        this.args = args;
1562 1
        this._body = _body;
1563
    }
1564

1565
    override Statement syntaxCopy()
1566
    {
1567 1
        return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null);
1568
    }
1569

1570
    override void accept(Visitor v)
1571
    {
1572 1
        v.visit(this);
1573
    }
1574
}
1575

1576
/***********************************************************
1577
 * https://dlang.org/spec/version.html#StaticAssert
1578
 */
1579
extern (C++) final class StaticAssertStatement : Statement
1580
{
1581
    StaticAssert sa;
1582

1583 1
    extern (D) this(StaticAssert sa)
1584
    {
1585 1
        super(sa.loc, STMT.StaticAssert);
1586 1
        this.sa = sa;
1587
    }
1588

1589
    override Statement syntaxCopy()
1590
    {
1591 1
        return new StaticAssertStatement(cast(StaticAssert)sa.syntaxCopy(null));
1592
    }
1593

1594
    override void accept(Visitor v)
1595
    {
1596 1
        v.visit(this);
1597
    }
1598
}
1599

1600
/***********************************************************
1601
 * https://dlang.org/spec/statement.html#switch-statement
1602
 */
1603
extern (C++) final class SwitchStatement : Statement
1604
{
1605
    Expression condition;           /// switch(condition)
1606
    Statement _body;                ///
1607
    bool isFinal;                   /// https://dlang.org/spec/statement.html#final-switch-statement
1608

1609
    DefaultStatement sdefault;      /// default:
1610
    Statement tryBody;              /// set to TryCatchStatement or TryFinallyStatement if in _body portion
1611
    TryFinallyStatement tf;         /// set if in the 'finally' block of a TryFinallyStatement
1612
    GotoCaseStatements gotoCases;   /// array of unresolved GotoCaseStatement's
1613
    CaseStatements* cases;          /// array of CaseStatement's
1614
    int hasNoDefault;               /// !=0 if no default statement
1615
    int hasVars;                    /// !=0 if has variable case values
1616
    VarDeclaration lastVar;         /// last observed variable declaration in this statement
1617

1618 1
    extern (D) this(const ref Loc loc, Expression condition, Statement _body, bool isFinal)
1619
    {
1620 1
        super(loc, STMT.Switch);
1621 1
        this.condition = condition;
1622 1
        this._body = _body;
1623 1
        this.isFinal = isFinal;
1624
    }
1625

1626
    override Statement syntaxCopy()
1627
    {
1628 1
        return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal);
1629
    }
1630

1631
    override bool hasBreak() const pure nothrow
1632
    {
1633 1
        return true;
1634
    }
1635

1636
    /************************************
1637
     * Returns:
1638
     *  true if error
1639
     */
1640
    extern (D) bool checkLabel()
1641
    {
1642
        /*
1643
         * Checks the scope of a label for existing variable declaration.
1644
         * Params:
1645
         *   vd = last variable declared before this case/default label
1646
         * Returns: `true` if the variables declared in this label would be skipped.
1647
         */
1648
        bool checkVar(VarDeclaration vd)
1649
        {
1650 1
            for (auto v = vd; v && v != lastVar; v = v.lastVar)
1651
            {
1652 1
                if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp)) || v._init.isVoidInitializer())
1653 1
                    continue;
1654 1
                if (vd.ident == Id.withSym)
1655 1
                    error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars());
1656
                else
1657 1
                    error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars());
1658 1
                return true;
1659
            }
1660 1
            return false;
1661
        }
1662

1663
        enum error = true;
1664

1665 1
        if (sdefault && checkVar(sdefault.lastVar))
1666 1
            return !error; // return error once fully deprecated
1667

1668 1
        foreach (scase; *cases)
1669
        {
1670 1
            if (scase && checkVar(scase.lastVar))
1671 1
                return !error; // return error once fully deprecated
1672
        }
1673 1
        return !error;
1674
    }
1675

1676
    override void accept(Visitor v)
1677
    {
1678 1
        v.visit(this);
1679
    }
1680
}
1681

1682
/***********************************************************
1683
 * https://dlang.org/spec/statement.html#CaseStatement
1684
 */
1685
extern (C++) final class CaseStatement : Statement
1686
{
1687
    Expression exp;
1688
    Statement statement;
1689

1690
    int index;              // which case it is (since we sort this)
1691
    VarDeclaration lastVar;
1692
    void* extra;            // for use by Statement_toIR()
1693

1694 1
    extern (D) this(const ref Loc loc, Expression exp, Statement statement)
1695
    {
1696 1
        super(loc, STMT.Case);
1697 1
        this.exp = exp;
1698 1
        this.statement = statement;
1699
    }
1700

1701
    override Statement syntaxCopy()
1702
    {
1703 1
        return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy());
1704
    }
1705

1706
    override void accept(Visitor v)
1707
    {
1708 1
        v.visit(this);
1709
    }
1710
}
1711

1712
/***********************************************************
1713
 * https://dlang.org/spec/statement.html#CaseRangeStatement
1714
 */
1715
extern (C++) final class CaseRangeStatement : Statement
1716
{
1717
    Expression first;
1718
    Expression last;
1719
    Statement statement;
1720

1721 1
    extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement)
1722
    {
1723 1
        super(loc, STMT.CaseRange);
1724 1
        this.first = first;
1725 1
        this.last = last;
1726 1
        this.statement = statement;
1727
    }
1728

1729
    override Statement syntaxCopy()
1730
    {
1731 1
        return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy());
1732
    }
1733

1734
    override void accept(Visitor v)
1735
    {
1736 1
        v.visit(this);
1737
    }
1738
}
1739

1740
/***********************************************************
1741
 * https://dlang.org/spec/statement.html#DefaultStatement
1742
 */
1743
extern (C++) final class DefaultStatement : Statement
1744
{
1745
    Statement statement;
1746

1747
    VarDeclaration lastVar;
1748

1749 1
    extern (D) this(const ref Loc loc, Statement statement)
1750
    {
1751 1
        super(loc, STMT.Default);
1752 1
        this.statement = statement;
1753
    }
1754

1755
    override Statement syntaxCopy()
1756
    {
1757 1
        return new DefaultStatement(loc, statement.syntaxCopy());
1758
    }
1759

1760
    override void accept(Visitor v)
1761
    {
1762 1
        v.visit(this);
1763
    }
1764
}
1765

1766
/***********************************************************
1767
 * https://dlang.org/spec/statement.html#GotoStatement
1768
 */
1769
extern (C++) final class GotoDefaultStatement : Statement
1770
{
1771
    SwitchStatement sw;
1772

1773 1
    extern (D) this(const ref Loc loc)
1774
    {
1775 1
        super(loc, STMT.GotoDefault);
1776
    }
1777

1778
    override Statement syntaxCopy()
1779
    {
1780 1
        return new GotoDefaultStatement(loc);
1781
    }
1782

1783
    override void accept(Visitor v)
1784
    {
1785 1
        v.visit(this);
1786
    }
1787
}
1788

1789
/***********************************************************
1790
 * https://dlang.org/spec/statement.html#GotoStatement
1791
 */
1792
extern (C++) final class GotoCaseStatement : Statement
1793
{
1794
    Expression exp;     // null, or which case to goto
1795

1796
    CaseStatement cs;   // case statement it resolves to
1797

1798 1
    extern (D) this(const ref Loc loc, Expression exp)
1799
    {
1800 1
        super(loc, STMT.GotoCase);
1801 1
        this.exp = exp;
1802
    }
1803

1804
    override Statement syntaxCopy()
1805
    {
1806 1
        return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null);
1807
    }
1808

1809
    override void accept(Visitor v)
1810
    {
1811 1
        v.visit(this);
1812
    }
1813
}
1814

1815
/***********************************************************
1816
 */
1817
extern (C++) final class SwitchErrorStatement : Statement
1818
{
1819
    Expression exp;
1820

1821 0
    extern (D) this(const ref Loc loc)
1822
    {
1823 0
        super(loc, STMT.SwitchError);
1824
    }
1825

1826 1
    final extern (D) this(const ref Loc loc, Expression exp)
1827
    {
1828 1
        super(loc, STMT.SwitchError);
1829 1
        this.exp = exp;
1830
    }
1831

1832
    override void accept(Visitor v)
1833
    {
1834 1
        v.visit(this);
1835
    }
1836
}
1837

1838
/***********************************************************
1839
 * https://dlang.org/spec/statement.html#return-statement
1840
 */
1841
extern (C++) final class ReturnStatement : Statement
1842
{
1843
    Expression exp;
1844
    size_t caseDim;
1845

1846 1
    extern (D) this(const ref Loc loc, Expression exp)
1847
    {
1848 1
        super(loc, STMT.Return);
1849 1
        this.exp = exp;
1850
    }
1851

1852
    override Statement syntaxCopy()
1853
    {
1854 1
        return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null);
1855
    }
1856

1857
    override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
1858
    {
1859 1
        return this;
1860
    }
1861

1862
    override void accept(Visitor v)
1863
    {
1864 1
        v.visit(this);
1865
    }
1866
}
1867

1868
/***********************************************************
1869
 * https://dlang.org/spec/statement.html#break-statement
1870
 */
1871
extern (C++) final class BreakStatement : Statement
1872
{
1873
    Identifier ident;
1874

1875 1
    extern (D) this(const ref Loc loc, Identifier ident)
1876
    {
1877 1
        super(loc, STMT.Break);
1878 1
        this.ident = ident;
1879
    }
1880

1881
    override Statement syntaxCopy()
1882
    {
1883 1
        return new BreakStatement(loc, ident);
1884
    }
1885

1886
    override void accept(Visitor v)
1887
    {
1888 1
        v.visit(this);
1889
    }
1890
}
1891

1892
/***********************************************************
1893
 * https://dlang.org/spec/statement.html#continue-statement
1894
 */
1895
extern (C++) final class ContinueStatement : Statement
1896
{
1897
    Identifier ident;
1898

1899 1
    extern (D) this(const ref Loc loc, Identifier ident)
1900
    {
1901 1
        super(loc, STMT.Continue);
1902 1
        this.ident = ident;
1903
    }
1904

1905
    override Statement syntaxCopy()
1906
    {
1907 1
        return new ContinueStatement(loc, ident);
1908
    }
1909

1910
    override void accept(Visitor v)
1911
    {
1912 1
        v.visit(this);
1913
    }
1914
}
1915

1916
/***********************************************************
1917
 * https://dlang.org/spec/statement.html#SynchronizedStatement
1918
 */
1919
extern (C++) final class SynchronizedStatement : Statement
1920
{
1921
    Expression exp;
1922
    Statement _body;
1923

1924 1
    extern (D) this(const ref Loc loc, Expression exp, Statement _body)
1925
    {
1926 1
        super(loc, STMT.Synchronized);
1927 1
        this.exp = exp;
1928 1
        this._body = _body;
1929
    }
1930

1931
    override Statement syntaxCopy()
1932
    {
1933 0
        return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null);
1934
    }
1935

1936
    override bool hasBreak() const pure nothrow
1937
    {
1938 0
        return false; //true;
1939
    }
1940

1941
    override bool hasContinue() const pure nothrow
1942
    {
1943 0
        return false; //true;
1944
    }
1945

1946
    override void accept(Visitor v)
1947
    {
1948 1
        v.visit(this);
1949
    }
1950
}
1951

1952
/***********************************************************
1953
 * https://dlang.org/spec/statement.html#with-statement
1954
 */
1955
extern (C++) final class WithStatement : Statement
1956
{
1957
    Expression exp;
1958
    Statement _body;
1959
    VarDeclaration wthis;
1960
    Loc endloc;
1961

1962 1
    extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc)
1963
    {
1964 1
        super(loc, STMT.With);
1965 1
        this.exp = exp;
1966 1
        this._body = _body;
1967 1
        this.endloc = endloc;
1968
    }
1969

1970
    override Statement syntaxCopy()
1971
    {
1972 1
        return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
1973
    }
1974

1975
    override void accept(Visitor v)
1976
    {
1977 1
        v.visit(this);
1978
    }
1979
}
1980

1981
/***********************************************************
1982
 * https://dlang.org/spec/statement.html#try-statement
1983
 */
1984
extern (C++) final class TryCatchStatement : Statement
1985
{
1986
    Statement _body;
1987
    Catches* catches;
1988

1989
    Statement tryBody;   /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
1990

1991 1
    extern (D) this(const ref Loc loc, Statement _body, Catches* catches)
1992
    {
1993 1
        super(loc, STMT.TryCatch);
1994 1
        this._body = _body;
1995 1
        this.catches = catches;
1996
    }
1997

1998
    override Statement syntaxCopy()
1999
    {
2000 1
        auto a = new Catches(catches.dim);
2001 1
        foreach (i, c; *catches)
2002
        {
2003 1
            (*a)[i] = c.syntaxCopy();
2004
        }
2005 1
        return new TryCatchStatement(loc, _body.syntaxCopy(), a);
2006
    }
2007

2008
    override bool hasBreak() const pure nothrow
2009
    {
2010 0
        return false;
2011
    }
2012

2013
    override void accept(Visitor v)
2014
    {
2015 1
        v.visit(this);
2016
    }
2017
}
2018

2019
/***********************************************************
2020
 * https://dlang.org/spec/statement.html#Catch
2021
 */
2022
extern (C++) final class Catch : RootObject
2023
{
2024
    const Loc loc;
2025
    Type type;
2026
    Identifier ident;
2027
    Statement handler;
2028

2029
    VarDeclaration var;
2030
    bool errors;                // set if semantic processing errors
2031

2032
    // was generated by the compiler, wasn't present in source code
2033
    bool internalCatch;
2034

2035 1
    extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler)
2036
    {
2037
        //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars());
2038 1
        this.loc = loc;
2039 1
        this.type = type;
2040 1
        this.ident = ident;
2041 1
        this.handler = handler;
2042
    }
2043

2044
    Catch syntaxCopy()
2045
    {
2046 1
        auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null));
2047 1
        c.internalCatch = internalCatch;
2048 1
        return c;
2049
    }
2050
}
2051

2052
/***********************************************************
2053
 * https://dlang.org/spec/statement.html#try-statement
2054
 */
2055
extern (C++) final class TryFinallyStatement : Statement
2056
{
2057
    Statement _body;
2058
    Statement finalbody;
2059

2060
    Statement tryBody;   /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
2061
    bool bodyFallsThru;  /// true if _body falls through to finally
2062

2063 1
    extern (D) this(const ref Loc loc, Statement _body, Statement finalbody)
2064
    {
2065 1
        super(loc, STMT.TryFinally);
2066 1
        this._body = _body;
2067 1
        this.finalbody = finalbody;
2068 1
        this.bodyFallsThru = true;      // assume true until statementSemantic()
2069
    }
2070

2071
    static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody)
2072
    {
2073 1
        return new TryFinallyStatement(loc, _body, finalbody);
2074
    }
2075

2076
    override Statement syntaxCopy()
2077
    {
2078 1
        return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy());
2079
    }
2080

2081
    override bool hasBreak() const pure nothrow
2082
    {
2083 0
        return false; //true;
2084
    }
2085

2086
    override bool hasContinue() const pure nothrow
2087
    {
2088 0
        return false; //true;
2089
    }
2090

2091
    override void accept(Visitor v)
2092
    {
2093 1
        v.visit(this);
2094
    }
2095
}
2096

2097
/***********************************************************
2098
 * https://dlang.org/spec/statement.html#scope-guard-statement
2099
 */
2100
extern (C++) final class ScopeGuardStatement : Statement
2101
{
2102
    TOK tok;
2103
    Statement statement;
2104

2105 1
    extern (D) this(const ref Loc loc, TOK tok, Statement statement)
2106
    {
2107 1
        super(loc, STMT.ScopeGuard);
2108 1
        this.tok = tok;
2109 1
        this.statement = statement;
2110
    }
2111

2112
    override Statement syntaxCopy()
2113
    {
2114 1
        return new ScopeGuardStatement(loc, tok, statement.syntaxCopy());
2115
    }
2116

2117
    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
2118
    {
2119
        //printf("ScopeGuardStatement::scopeCode()\n");
2120 1
        *sentry = null;
2121 1
        *sexception = null;
2122 1
        *sfinally = null;
2123

2124 1
        Statement s = new PeelStatement(statement);
2125

2126 1
        switch (tok)
2127
        {
2128 1
        case TOK.onScopeExit:
2129 1
            *sfinally = s;
2130 1
            break;
2131

2132 1
        case TOK.onScopeFailure:
2133 1
            *sexception = s;
2134 1
            break;
2135

2136 1
        case TOK.onScopeSuccess:
2137
            {
2138
                /* Create:
2139
                 *  sentry:   bool x = false;
2140
                 *  sexception:    x = true;
2141
                 *  sfinally: if (!x) statement;
2142
                 */
2143 1
                auto v = copyToTemp(0, "__os", IntegerExp.createBool(false));
2144 1
                v.dsymbolSemantic(sc);
2145 1
                *sentry = new ExpStatement(loc, v);
2146

2147 1
                Expression e = IntegerExp.createBool(true);
2148 1
                e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e);
2149 1
                *sexception = new ExpStatement(Loc.initial, e);
2150

2151 1
                e = new VarExp(Loc.initial, v);
2152 1
                e = new NotExp(Loc.initial, e);
2153 1
                *sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial);
2154

2155 1
                break;
2156
            }
2157 0
        default:
2158 0
            assert(0);
2159
        }
2160 1
        return null;
2161
    }
2162

2163
    override void accept(Visitor v)
2164
    {
2165 1
        v.visit(this);
2166
    }
2167
}
2168

2169
/***********************************************************
2170
 * https://dlang.org/spec/statement.html#throw-statement
2171
 */
2172
extern (C++) final class ThrowStatement : Statement
2173
{
2174
    Expression exp;
2175

2176
    // was generated by the compiler, wasn't present in source code
2177
    bool internalThrow;
2178

2179 1
    extern (D) this(const ref Loc loc, Expression exp)
2180
    {
2181 1
        super(loc, STMT.Throw);
2182 1
        this.exp = exp;
2183
    }
2184

2185
    override Statement syntaxCopy()
2186
    {
2187 1
        auto s = new ThrowStatement(loc, exp.syntaxCopy());
2188 1
        s.internalThrow = internalThrow;
2189 1
        return s;
2190
    }
2191

2192
    override void accept(Visitor v)
2193
    {
2194 1
        v.visit(this);
2195
    }
2196
}
2197

2198
/***********************************************************
2199
 */
2200
extern (C++) final class DebugStatement : Statement
2201
{
2202
    Statement statement;
2203

2204 1
    extern (D) this(const ref Loc loc, Statement statement)
2205
    {
2206 1
        super(loc, STMT.Debug);
2207 1
        this.statement = statement;
2208
    }
2209

2210
    override Statement syntaxCopy()
2211
    {
2212 0
        return new DebugStatement(loc, statement ? statement.syntaxCopy() : null);
2213
    }
2214

2215
    override Statements* flatten(Scope* sc)
2216
    {
2217 1
        Statements* a = statement ? statement.flatten(sc) : null;
2218 1
        if (a)
2219
        {
2220 1
            foreach (ref s; *a)
2221
            {
2222 1
                s = new DebugStatement(loc, s);
2223
            }
2224
        }
2225 1
        return a;
2226
    }
2227

2228
    override void accept(Visitor v)
2229
    {
2230 1
        v.visit(this);
2231
    }
2232
}
2233

2234
/***********************************************************
2235
 * https://dlang.org/spec/statement.html#goto-statement
2236
 */
2237
extern (C++) final class GotoStatement : Statement
2238
{
2239
    Identifier ident;
2240
    LabelDsymbol label;
2241
    Statement tryBody;              /// set to TryCatchStatement or TryFinallyStatement if in _body portion
2242
    TryFinallyStatement tf;
2243
    ScopeGuardStatement os;
2244
    VarDeclaration lastVar;
2245

2246 1
    extern (D) this(const ref Loc loc, Identifier ident)
2247
    {
2248 1
        super(loc, STMT.Goto);
2249 1
        this.ident = ident;
2250
    }
2251

2252
    override Statement syntaxCopy()
2253
    {
2254 1
        return new GotoStatement(loc, ident);
2255
    }
2256

2257
    extern (D) bool checkLabel()
2258
    {
2259 1
        if (!label.statement)
2260 1
            return true;        // error should have been issued for this already
2261

2262 1
        if (label.statement.os != os)
2263
        {
2264 1
            if (os && os.tok == TOK.onScopeFailure && !label.statement.os)
2265
            {
2266
                // Jump out from scope(failure) block is allowed.
2267
            }
2268
            else
2269
            {
2270 1
                if (label.statement.os)
2271 1
                    error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok));
2272
                else
2273 1
                    error("cannot `goto` out of `%s` block", Token.toChars(os.tok));
2274 1
                return true;
2275
            }
2276
        }
2277

2278 1
        if (label.statement.tf != tf)
2279
        {
2280 1
            error("cannot `goto` in or out of `finally` block");
2281 1
            return true;
2282
        }
2283

2284 1
        Statement stbnext;
2285 1
        for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext)
2286
        {
2287 1
            if (!stb)
2288
            {
2289 1
                error("cannot `goto` into `try` block");
2290 1
                return true;
2291
            }
2292 1
            if (auto stf = stb.isTryFinallyStatement())
2293 1
                stbnext = stf.tryBody;
2294 0
            else if (auto stc = stb.isTryCatchStatement())
2295 0
                stbnext = stc.tryBody;
2296
            else
2297 0
                assert(0);
2298
        }
2299

2300 1
        VarDeclaration vd = label.statement.lastVar;
2301 1
        if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest))
2302 1
            return false;
2303

2304 1
        VarDeclaration last = lastVar;
2305 1
        while (last && last != vd)
2306 1
            last = last.lastVar;
2307 1
        if (last == vd)
2308
        {
2309
            // All good, the label's scope has no variables
2310
        }
2311 1
        else if (vd.storage_class & STC.exptemp)
2312
        {
2313
            // Lifetime ends at end of expression, so no issue with skipping the statement
2314
        }
2315 1
        else if (vd.ident == Id.withSym)
2316
        {
2317 1
            error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars());
2318 1
            return true;
2319
        }
2320
        else
2321
        {
2322 1
            error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars());
2323 1
            return true;
2324
        }
2325

2326 1
        return false;
2327
    }
2328

2329
    override void accept(Visitor v)
2330
    {
2331 1
        v.visit(this);
2332
    }
2333
}
2334

2335
/***********************************************************
2336
 * https://dlang.org/spec/statement.html#LabeledStatement
2337
 */
2338
extern (C++) final class LabelStatement : Statement
2339
{
2340
    Identifier ident;
2341
    Statement statement;
2342

2343
    Statement tryBody;              /// set to TryCatchStatement or TryFinallyStatement if in _body portion
2344
    TryFinallyStatement tf;
2345
    ScopeGuardStatement os;
2346
    VarDeclaration lastVar;
2347
    Statement gotoTarget;       // interpret
2348
    void* extra;                // used by Statement_toIR()
2349
    bool breaks;                // someone did a 'break ident'
2350

2351 1
    extern (D) this(const ref Loc loc, Identifier ident, Statement statement)
2352
    {
2353 1
        super(loc, STMT.Label);
2354 1
        this.ident = ident;
2355 1
        this.statement = statement;
2356
    }
2357

2358
    override Statement syntaxCopy()
2359
    {
2360 1
        return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null);
2361
    }
2362

2363
    override Statements* flatten(Scope* sc)
2364
    {
2365 1
        Statements* a = null;
2366 1
        if (statement)
2367
        {
2368 1
            a = statement.flatten(sc);
2369 1
            if (a)
2370
            {
2371 1
                if (!a.dim)
2372
                {
2373 1
                    a.push(new ExpStatement(loc, cast(Expression)null));
2374
                }
2375

2376
                // reuse 'this' LabelStatement
2377 1
                this.statement = (*a)[0];
2378 1
                (*a)[0] = this;
2379
            }
2380
        }
2381 1
        return a;
2382
    }
2383

2384
    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexit, Statement* sfinally)
2385
    {
2386
        //printf("LabelStatement::scopeCode()\n");
2387 1
        if (statement)
2388 1
            statement = statement.scopeCode(sc, sentry, sexit, sfinally);
2389
        else
2390
        {
2391 1
            *sentry = null;
2392 1
            *sexit = null;
2393 1
            *sfinally = null;
2394
        }
2395 1
        return this;
2396
    }
2397

2398
    override void accept(Visitor v)
2399
    {
2400 1
        v.visit(this);
2401
    }
2402
}
2403

2404
/***********************************************************
2405
 */
2406
extern (C++) final class LabelDsymbol : Dsymbol
2407
{
2408
    LabelStatement statement;
2409

2410
    bool deleted;           // set if rewritten to return in foreach delegate
2411
    bool iasm;              // set if used by inline assembler
2412

2413 1
    extern (D) this(Identifier ident)
2414
    {
2415 1
        super(ident);
2416
    }
2417

2418
    static LabelDsymbol create(Identifier ident)
2419
    {
2420 1
        return new LabelDsymbol(ident);
2421
    }
2422

2423
    // is this a LabelDsymbol()?
2424
    override LabelDsymbol isLabel()
2425
    {
2426 1
        return this;
2427
    }
2428

2429
    override void accept(Visitor v)
2430
    {
2431 0
        v.visit(this);
2432
    }
2433
}
2434

2435
/***********************************************************
2436
 * https://dlang.org/spec/statement.html#asm
2437
 */
2438
extern (C++) class AsmStatement : Statement
2439
{
2440
    Token* tokens;
2441

2442 1
    extern (D) this(const ref Loc loc, Token* tokens)
2443
    {
2444 1
        super(loc, STMT.Asm);
2445 1
        this.tokens = tokens;
2446
    }
2447

2448 1
    extern (D) this(const ref Loc loc, Token* tokens, STMT stmt)
2449
    {
2450 1
        super(loc, stmt);
2451 1
        this.tokens = tokens;
2452
    }
2453

2454
    override Statement syntaxCopy()
2455
    {
2456 1
        return new AsmStatement(loc, tokens);
2457
    }
2458

2459
    override void accept(Visitor v)
2460
    {
2461 1
        v.visit(this);
2462
    }
2463
}
2464

2465
/***********************************************************
2466
 * https://dlang.org/spec/iasm.html
2467
 */
2468
extern (C++) final class InlineAsmStatement : AsmStatement
2469
{
2470
    code* asmcode;
2471
    uint asmalign;  // alignment of this statement
2472
    uint regs;      // mask of registers modified (must match regm_t in back end)
2473
    bool refparam;  // true if function parameter is referenced
2474
    bool naked;     // true if function is to be naked
2475

2476 1
    extern (D) this(const ref Loc loc, Token* tokens)
2477
    {
2478 1
        super(loc, tokens, STMT.InlineAsm);
2479
    }
2480

2481
    override Statement syntaxCopy()
2482
    {
2483 0
        return new InlineAsmStatement(loc, tokens);
2484
    }
2485

2486
    override void accept(Visitor v)
2487
    {
2488 1
        v.visit(this);
2489
    }
2490
}
2491

2492
/***********************************************************
2493
 * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
2494
 * Assembler instructions with D expression operands.
2495
 */
2496
extern (C++) final class GccAsmStatement : AsmStatement
2497
{
2498
    StorageClass stc;           // attributes of the asm {} block
2499
    Expression insn;            // string expression that is the template for assembler code
2500
    Expressions* args;          // input and output operands of the statement
2501
    uint outputargs;            // of the operands in 'args', the number of output operands
2502
    Identifiers* names;         // list of symbolic names for the operands
2503
    Expressions* constraints;   // list of string constants specifying constraints on operands
2504
    Expressions* clobbers;      // list of string constants specifying clobbers and scratch registers
2505
    Identifiers* labels;        // list of goto labels
2506
    GotoStatements* gotos;      // of the goto labels, the equivalent statements they represent
2507

2508 0
    extern (D) this(const ref Loc loc, Token* tokens)
2509
    {
2510 0
        super(loc, tokens, STMT.GccAsm);
2511
    }
2512

2513
    override Statement syntaxCopy()
2514
    {
2515 0
        return new GccAsmStatement(loc, tokens);
2516
    }
2517

2518
    override void accept(Visitor v)
2519
    {
2520 0
        v.visit(this);
2521
    }
2522
}
2523

2524
/***********************************************************
2525
 * a complete asm {} block
2526
 */
2527
extern (C++) final class CompoundAsmStatement : CompoundStatement
2528
{
2529
    StorageClass stc; // postfix attributes like nothrow/pure/@trusted
2530

2531 1
    extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc)
2532
    {
2533 1
        super(loc, statements, STMT.CompoundAsm);
2534 1
        this.stc = stc;
2535
    }
2536

2537
    override CompoundAsmStatement syntaxCopy()
2538
    {
2539 1
        auto a = new Statements(statements.dim);
2540 1
        foreach (i, s; *statements)
2541
        {
2542 1
            (*a)[i] = s ? s.syntaxCopy() : null;
2543
        }
2544 1
        return new CompoundAsmStatement(loc, a, stc);
2545
    }
2546

2547
    override Statements* flatten(Scope* sc)
2548
    {
2549 1
        return null;
2550
    }
2551

2552
    override void accept(Visitor v)
2553
    {
2554 1
        v.visit(this);
2555
    }
2556
}
2557

2558
/***********************************************************
2559
 * https://dlang.org/spec/module.html#ImportDeclaration
2560
 */
2561
extern (C++) final class ImportStatement : Statement
2562
{
2563
    Dsymbols* imports;      // Array of Import's
2564

2565 1
    extern (D) this(const ref Loc loc, Dsymbols* imports)
2566
    {
2567 1
        super(loc, STMT.Import);
2568 1
        this.imports = imports;
2569
    }
2570

2571
    override Statement syntaxCopy()
2572
    {
2573 1
        auto m = new Dsymbols(imports.dim);
2574 1
        foreach (i, s; *imports)
2575
        {
2576 1
            (*m)[i] = s.syntaxCopy(null);
2577
        }
2578 1
        return new ImportStatement(loc, m);
2579
    }
2580

2581
    override void accept(Visitor v)
2582
    {
2583 1
        v.visit(this);
2584
    }
2585
}

Read our documentation on viewing source code .

Loading