1
/**
2
 * Performs the semantic3 stage, which deals with function bodies.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_semantic3.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic3.d
10
 */
11

12
module dmd.semantic3;
13

14
import core.stdc.stdio;
15
import core.stdc.string;
16

17
import dmd.aggregate;
18
import dmd.aliasthis;
19
import dmd.arraytypes;
20
import dmd.astcodegen;
21
import dmd.attrib;
22
import dmd.blockexit;
23
import dmd.clone;
24
import dmd.ctorflow;
25
import dmd.dcast;
26
import dmd.dclass;
27
import dmd.declaration;
28
import dmd.denum;
29
import dmd.dimport;
30
import dmd.dinterpret;
31
import dmd.dmodule;
32
import dmd.dscope;
33
import dmd.dstruct;
34
import dmd.dsymbol;
35
import dmd.dsymbolsem;
36
import dmd.dtemplate;
37
import dmd.dversion;
38
import dmd.errors;
39
import dmd.escape;
40
import dmd.expression;
41
import dmd.expressionsem;
42
import dmd.func;
43
import dmd.globals;
44
import dmd.id;
45
import dmd.identifier;
46
import dmd.init;
47
import dmd.initsem;
48
import dmd.hdrgen;
49
import dmd.mtype;
50
import dmd.nogc;
51
import dmd.nspace;
52
import dmd.ob;
53
import dmd.objc;
54
import dmd.opover;
55
import dmd.parse;
56
import dmd.root.filename;
57
import dmd.root.outbuffer;
58
import dmd.root.rmem;
59
import dmd.root.rootobject;
60
import dmd.sideeffect;
61
import dmd.statementsem;
62
import dmd.staticassert;
63
import dmd.tokens;
64
import dmd.utf;
65
import dmd.semantic2;
66
import dmd.statement;
67
import dmd.target;
68
import dmd.templateparamsem;
69
import dmd.typesem;
70
import dmd.visitor;
71

72
enum LOG = false;
73

74

75
/*************************************
76
 * Does semantic analysis on function bodies.
77
 */
78
extern(C++) void semantic3(Dsymbol dsym, Scope* sc)
79
{
80 1
    scope v = new Semantic3Visitor(sc);
81 1
    dsym.accept(v);
82
}
83

84
private extern(C++) final class Semantic3Visitor : Visitor
85
{
86
    alias visit = Visitor.visit;
87

88
    Scope* sc;
89 1
    this(Scope* sc)
90
    {
91 1
        this.sc = sc;
92
    }
93

94
    override void visit(Dsymbol) {}
95

96
    override void visit(TemplateInstance tempinst)
97
    {
98
        static if (LOG)
99
        {
100
            printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", tempinst.toChars(), tempinst.semanticRun);
101
        }
102
        //if (toChars()[0] == 'D') *(char*)0=0;
103 1
        if (tempinst.semanticRun >= PASS.semantic3)
104 1
            return;
105 1
        tempinst.semanticRun = PASS.semantic3;
106 1
        if (!tempinst.errors && tempinst.members)
107
        {
108 1
            TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
109 1
            assert(tempdecl);
110

111 1
            sc = tempdecl._scope;
112 1
            sc = sc.push(tempinst.argsym);
113 1
            sc = sc.push(tempinst);
114 1
            sc.tinst = tempinst;
115 1
            sc.minst = tempinst.minst;
116

117 1
            int needGagging = (tempinst.gagged && !global.gag);
118 1
            uint olderrors = global.errors;
119 1
            int oldGaggedErrors = -1; // dead-store to prevent spurious warning
120
            /* If this is a gagged instantiation, gag errors.
121
             * Future optimisation: If the results are actually needed, errors
122
             * would already be gagged, so we don't really need to run semantic
123
             * on the members.
124
             */
125 1
            if (needGagging)
126 1
                oldGaggedErrors = global.startGagging();
127

128 1
            for (size_t i = 0; i < tempinst.members.dim; i++)
129
            {
130 1
                Dsymbol s = (*tempinst.members)[i];
131 1
                s.semantic3(sc);
132 1
                if (tempinst.gagged && global.errors != olderrors)
133 1
                    break;
134
            }
135

136 1
            if (global.errors != olderrors)
137
            {
138 1
                if (!tempinst.errors)
139
                {
140 1
                    if (!tempdecl.literal)
141 1
                        tempinst.error(tempinst.loc, "error instantiating");
142 1
                    if (tempinst.tinst)
143 1
                        tempinst.tinst.printInstantiationTrace();
144
                }
145 1
                tempinst.errors = true;
146
            }
147 1
            if (needGagging)
148 1
                global.endGagging(oldGaggedErrors);
149

150 1
            sc = sc.pop();
151 1
            sc.pop();
152
        }
153
    }
154

155
    override void visit(TemplateMixin tmix)
156
    {
157 1
        if (tmix.semanticRun >= PASS.semantic3)
158 1
            return;
159 1
        tmix.semanticRun = PASS.semantic3;
160
        static if (LOG)
161
        {
162
            printf("TemplateMixin.semantic3('%s')\n", tmix.toChars());
163
        }
164 1
        if (tmix.members)
165
        {
166 1
            sc = sc.push(tmix.argsym);
167 1
            sc = sc.push(tmix);
168 1
            for (size_t i = 0; i < tmix.members.dim; i++)
169
            {
170 1
                Dsymbol s = (*tmix.members)[i];
171 1
                s.semantic3(sc);
172
            }
173 1
            sc = sc.pop();
174 1
            sc.pop();
175
        }
176
    }
177

178
    override void visit(Module mod)
179
    {
180
        //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
181 1
        if (mod.semanticRun != PASS.semantic2done)
182 0
            return;
183 1
        mod.semanticRun = PASS.semantic3;
184
        // Note that modules get their own scope, from scratch.
185
        // This is so regardless of where in the syntax a module
186
        // gets imported, it is unaffected by context.
187 1
        Scope* sc = Scope.createGlobal(mod); // create root scope
188
        //printf("Module = %p\n", sc.scopesym);
189
        // Pass 3 semantic routines: do initializers and function bodies
190 1
        for (size_t i = 0; i < mod.members.dim; i++)
191
        {
192 1
            Dsymbol s = (*mod.members)[i];
193
            //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
194 1
            s.semantic3(sc);
195

196 1
            mod.runDeferredSemantic2();
197
        }
198 1
        if (mod.userAttribDecl)
199
        {
200 1
            mod.userAttribDecl.semantic3(sc);
201
        }
202 1
        sc = sc.pop();
203 1
        sc.pop();
204 1
        mod.semanticRun = PASS.semantic3done;
205
    }
206

207
    override void visit(FuncDeclaration funcdecl)
208
    {
209
        /* Determine if function should add `return 0;`
210
         */
211
        bool addReturn0()
212
        {
213 1
            TypeFunction f = cast(TypeFunction)funcdecl.type;
214

215 1
            return f.next.ty == Tvoid &&
216 1
                (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain());
217
        }
218

219 1
        VarDeclaration _arguments = null;
220

221 1
        if (!funcdecl.parent)
222
        {
223 0
            if (global.errors)
224 0
                return;
225
            //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
226 0
            assert(0);
227
        }
228 1
        if (funcdecl.errors || isError(funcdecl.parent))
229
        {
230 1
            funcdecl.errors = true;
231 1
            return;
232
        }
233
        //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), funcdecl, sc, funcdecl.loc.toChars());
234
        //fflush(stdout);
235
        //printf("storage class = x%x %x\n", sc.stc, storage_class);
236
        //{ static int x; if (++x == 2) *(char*)0=0; }
237
        //printf("\tlinkage = %d\n", sc.linkage);
238

239 1
        if (funcdecl.ident == Id.assign && !funcdecl.inuse)
240
        {
241 1
            if (funcdecl.storage_class & STC.inference)
242
            {
243
                /* https://issues.dlang.org/show_bug.cgi?id=15044
244
                 * For generated opAssign function, any errors
245
                 * from its body need to be gagged.
246
                 */
247 1
                uint oldErrors = global.startGagging();
248 1
                ++funcdecl.inuse;
249 1
                funcdecl.semantic3(sc);
250 1
                --funcdecl.inuse;
251 1
                if (global.endGagging(oldErrors))   // if errors happened
252
                {
253
                    // Disable generated opAssign, because some members forbid identity assignment.
254 1
                    funcdecl.storage_class |= STC.disable;
255 1
                    funcdecl.fbody = null;   // remove fbody which contains the error
256 1
                    funcdecl.semantic3Errors = false;
257
                }
258 1
                return;
259
            }
260
        }
261

262
        //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
263 1
        if (funcdecl.semanticRun >= PASS.semantic3)
264 1
            return;
265 1
        funcdecl.semanticRun = PASS.semantic3;
266 1
        funcdecl.semantic3Errors = false;
267

268 1
        if (!funcdecl.type || funcdecl.type.ty != Tfunction)
269 1
            return;
270 1
        TypeFunction f = cast(TypeFunction)funcdecl.type;
271 1
        if (!funcdecl.inferRetType && f.next.ty == Terror)
272 0
            return;
273

274 1
        if (!funcdecl.fbody && funcdecl.inferRetType && !f.next)
275
        {
276 1
            funcdecl.error("has no function body with return type inference");
277 1
            return;
278
        }
279

280 1
        uint oldErrors = global.errors;
281 1
        auto fds = FuncDeclSem3(funcdecl,sc);
282

283 1
        fds.checkInContractOverrides();
284

285
        // Remember whether we need to generate an 'out' contract.
286 1
        immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl);
287

288 1
        if (funcdecl.fbody || funcdecl.frequires || needEnsure)
289
        {
290
            /* Symbol table into which we place parameters and nested functions,
291
             * solely to diagnose name collisions.
292
             */
293 1
            funcdecl.localsymtab = new DsymbolTable();
294

295
            // Establish function scope
296 1
            auto ss = new ScopeDsymbol(funcdecl.loc, null);
297
            // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
298 1
            for (auto scx = sc; ; scx = scx.enclosing)
299
            {
300 1
                if (scx.scopesym)
301
                {
302 1
                    ss.parent = scx.scopesym;
303 1
                    break;
304
                }
305
            }
306 1
            ss.endlinnum = funcdecl.endloc.linnum;
307 1
            Scope* sc2 = sc.push(ss);
308 1
            sc2.func = funcdecl;
309 1
            sc2.parent = funcdecl;
310 1
            sc2.ctorflow.callSuper = CSX.none;
311 1
            sc2.sbreak = null;
312 1
            sc2.scontinue = null;
313 1
            sc2.sw = null;
314 1
            sc2.fes = funcdecl.fes;
315 1
            sc2.linkage = LINK.d;
316 1
            sc2.stc &= STCFlowThruFunction;
317 1
            sc2.protection = Prot(Prot.Kind.public_);
318 1
            sc2.explicitProtection = 0;
319 1
            sc2.aligndecl = null;
320 1
            if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
321 1
                sc2.flags = sc.flags & ~SCOPE.contract;
322 1
            sc2.flags &= ~SCOPE.compile;
323 1
            sc2.tf = null;
324 1
            sc2.os = null;
325 1
            sc2.inLoop = false;
326 1
            sc2.userAttribDecl = null;
327 1
            if (sc2.intypeof == 1)
328 1
                sc2.intypeof = 2;
329 1
            sc2.ctorflow.fieldinit = null;
330

331
            /* Note: When a lambda is defined immediately under aggregate member
332
             * scope, it should be contextless due to prevent interior pointers.
333
             * e.g.
334
             *      // dg points 'this' - it's interior pointer
335
             *      class C { int x; void delegate() dg = (){ this.x = 1; }; }
336
             *
337
             * However, lambdas could be used inside typeof, in order to check
338
             * some expressions validity at compile time. For such case the lambda
339
             * body can access aggregate instance members.
340
             * e.g.
341
             *      class C { int x; static assert(is(typeof({ this.x = 1; }))); }
342
             *
343
             * To properly accept it, mark these lambdas as member functions.
344
             */
345 1
            if (auto fld = funcdecl.isFuncLiteralDeclaration())
346
            {
347 1
                if (auto ad = funcdecl.isMember2())
348
                {
349 1
                    if (!sc.intypeof)
350
                    {
351 1
                        if (fld.tok == TOK.delegate_)
352 1
                            funcdecl.error("cannot be %s members", ad.kind());
353
                        else
354 1
                            fld.tok = TOK.function_;
355
                    }
356
                    else
357
                    {
358 1
                        if (fld.tok != TOK.function_)
359 1
                            fld.tok = TOK.delegate_;
360
                    }
361
                }
362
            }
363

364 1
            funcdecl.declareThis(sc2);
365

366
            //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
367
            //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars());
368

369
            // Declare hidden variable _arguments[] and _argptr
370 1
            if (f.parameterList.varargs == VarArg.variadic)
371
            {
372 1
                if (f.linkage == LINK.d)
373
                {
374
                    // Variadic arguments depend on Typeinfo being defined.
375 1
                    if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist)
376
                    {
377 1
                        if (!global.params.useTypeInfo)
378 1
                            funcdecl.error("D-style variadic functions cannot be used with -betterC");
379 1
                        else if (!Type.typeinfotypelist)
380 1
                            funcdecl.error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
381
                        else
382 1
                            funcdecl.error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
383 1
                        fatal();
384
                    }
385

386
                    // Declare _arguments[]
387 1
                    funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
388 1
                    funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
389 1
                    funcdecl.v_arguments.dsymbolSemantic(sc2);
390 1
                    sc2.insert(funcdecl.v_arguments);
391 1
                    funcdecl.v_arguments.parent = funcdecl;
392

393
                    //Type t = Type.dtypeinfo.type.constOf().arrayOf();
394 1
                    Type t = Type.dtypeinfo.type.arrayOf();
395 1
                    _arguments = new VarDeclaration(funcdecl.loc, t, Id._arguments, null);
396 1
                    _arguments.storage_class |= STC.temp;
397 1
                    _arguments.dsymbolSemantic(sc2);
398 1
                    sc2.insert(_arguments);
399 1
                    _arguments.parent = funcdecl;
400
                }
401 1
                if (f.linkage == LINK.d || f.parameterList.length)
402
                {
403
                    // Declare _argptr
404 1
                    Type t = target.va_listType(funcdecl.loc, sc);
405
                    // Init is handled in FuncDeclaration_toObjFile
406 1
                    funcdecl.v_argptr = new VarDeclaration(funcdecl.loc, t, Id._argptr, new VoidInitializer(funcdecl.loc));
407 1
                    funcdecl.v_argptr.storage_class |= STC.temp;
408 1
                    funcdecl.v_argptr.dsymbolSemantic(sc2);
409 1
                    sc2.insert(funcdecl.v_argptr);
410 1
                    funcdecl.v_argptr.parent = funcdecl;
411
                }
412
            }
413

414
            /* Declare all the function parameters as variables
415
             * and install them in parameters[]
416
             */
417 1
            if (const nparams = f.parameterList.length)
418
            {
419
                /* parameters[] has all the tuples removed, as the back end
420
                 * doesn't know about tuples
421
                 */
422 1
                funcdecl.parameters = new VarDeclarations();
423 1
                funcdecl.parameters.reserve(nparams);
424 1
                foreach (i, fparam; f.parameterList)
425
                {
426 1
                    Identifier id = fparam.ident;
427 1
                    StorageClass stc = 0;
428 1
                    if (!id)
429
                    {
430
                        /* Generate identifier for un-named parameter,
431
                         * because we need it later on.
432
                         */
433 1
                        fparam.ident = id = Identifier.generateId("_param_", i);
434 1
                        stc |= STC.temp;
435
                    }
436 1
                    Type vtype = fparam.type;
437 1
                    auto v = new VarDeclaration(funcdecl.loc, vtype, id, null);
438
                    //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
439 1
                    stc |= STC.parameter;
440 1
                    if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
441
                    {
442 1
                        stc |= STC.variadic;
443 1
                        auto vtypeb = vtype.toBasetype();
444 1
                        if (vtypeb.ty == Tarray)
445
                        {
446
                            /* Since it'll be pointing into the stack for the array
447
                             * contents, it needs to be `scope`
448
                             */
449 1
                            stc |= STC.scope_;
450
                        }
451
                    }
452

453 1
                    if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_))
454 1
                        stc |= STC.maybescope;
455

456 1
                    stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
457 1
                    v.storage_class = stc;
458 1
                    v.dsymbolSemantic(sc2);
459 1
                    if (!sc2.insert(v))
460
                    {
461 1
                        funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
462 1
                        funcdecl.errors = true;
463
                    }
464
                    else
465 1
                        funcdecl.parameters.push(v);
466 1
                    funcdecl.localsymtab.insert(v);
467 1
                    v.parent = funcdecl;
468 1
                    if (fparam.userAttribDecl)
469 1
                        v.userAttribDecl = fparam.userAttribDecl;
470
                }
471
            }
472

473
            // Declare the tuple symbols and put them in the symbol table,
474
            // but not in parameters[].
475 1
            if (f.parameterList.parameters)
476 1
            foreach (fparam; *f.parameterList.parameters)
477
            {
478 1
                if (!fparam.ident)
479 1
                    continue; // never used, so ignore
480
                // expand any tuples
481 1
                if (fparam.type.ty != Ttuple)
482 1
                    continue;
483

484 1
                TypeTuple t = cast(TypeTuple)fparam.type;
485 1
                size_t dim = Parameter.dim(t.arguments);
486 1
                auto exps = new Objects(dim);
487 1
                foreach (j; 0 .. dim)
488
                {
489 1
                    Parameter narg = Parameter.getNth(t.arguments, j);
490 1
                    assert(narg.ident);
491 1
                    VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
492 1
                    assert(v);
493 1
                    (*exps)[j] = new VarExp(v.loc, v);
494
                }
495 1
                assert(fparam.ident);
496 1
                auto v = new TupleDeclaration(funcdecl.loc, fparam.ident, exps);
497
                //printf("declaring tuple %s\n", v.toChars());
498 1
                v.isexp = true;
499 1
                if (!sc2.insert(v))
500 0
                    funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
501 1
                funcdecl.localsymtab.insert(v);
502 1
                v.parent = funcdecl;
503
            }
504

505
            // Precondition invariant
506 1
            Statement fpreinv = null;
507 1
            if (funcdecl.addPreInvariant())
508
            {
509 1
                Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
510 1
                if (e)
511 1
                    fpreinv = new ExpStatement(Loc.initial, e);
512
            }
513

514
            // Postcondition invariant
515 1
            Statement fpostinv = null;
516 1
            if (funcdecl.addPostInvariant())
517
            {
518 1
                Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
519 1
                if (e)
520 1
                    fpostinv = new ExpStatement(Loc.initial, e);
521
            }
522

523
            // Pre/Postcondition contract
524 1
            if (!funcdecl.fbody)
525 1
                funcdecl.buildEnsureRequire();
526

527 1
            Scope* scout = null;
528 1
            if (needEnsure || funcdecl.addPostInvariant())
529
            {
530
                /* https://issues.dlang.org/show_bug.cgi?id=3657
531
                 * Set the correct end line number for fensure scope.
532
                 */
533 1
                uint fensure_endlin = funcdecl.endloc.linnum;
534 1
                if (funcdecl.fensure)
535 1
                    if (auto s = funcdecl.fensure.isScopeStatement())
536 0
                        fensure_endlin = s.endloc.linnum;
537

538 1
                if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
539
                {
540 1
                    funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
541
                }
542

543
                // scope of out contract (need for vresult.semantic)
544 1
                auto sym = new ScopeDsymbol(funcdecl.loc, null);
545 1
                sym.parent = sc2.scopesym;
546 1
                sym.endlinnum = fensure_endlin;
547 1
                scout = sc2.push(sym);
548
            }
549

550 1
            if (funcdecl.fbody)
551
            {
552 1
                auto sym = new ScopeDsymbol(funcdecl.loc, null);
553 1
                sym.parent = sc2.scopesym;
554 1
                sym.endlinnum = funcdecl.endloc.linnum;
555 1
                sc2 = sc2.push(sym);
556

557 1
                auto ad2 = funcdecl.isMemberLocal();
558

559
                /* If this is a class constructor
560
                 */
561 1
                if (ad2 && funcdecl.isCtorDeclaration())
562
                {
563 1
                    sc2.ctorflow.allocFieldinit(ad2.fields.dim);
564 1
                    foreach (v; ad2.fields)
565
                    {
566 1
                        v.ctorinit = 0;
567
                    }
568
                }
569

570 1
                if (!funcdecl.inferRetType && !target.isReturnOnStack(f, funcdecl.needThis()))
571 1
                    funcdecl.nrvo_can = 0;
572

573 1
                bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_));
574

575 1
                funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2);
576 1
                if (!funcdecl.fbody)
577 1
                    funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
578

579 1
                if (funcdecl.naked)
580
                {
581 1
                    fpreinv = null;         // can't accommodate with no stack frame
582 1
                    fpostinv = null;
583
                }
584

585 1
                assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref));
586 1
                f = cast(TypeFunction)funcdecl.type;
587

588 1
                if (funcdecl.inferRetType)
589
                {
590
                    // If no return type inferred yet, then infer a void
591 1
                    if (!f.next)
592 1
                        f.next = Type.tvoid;
593 1
                    if (f.checkRetType(funcdecl.loc))
594 1
                        funcdecl.fbody = new ErrorStatement();
595
                }
596 1
                if (global.params.vcomplex && f.next !is null)
597 1
                    f.next.checkComplexTransition(funcdecl.loc, sc);
598

599 1
                if (funcdecl.returns && !funcdecl.fbody.isErrorStatement())
600
                {
601 1
                    for (size_t i = 0; i < funcdecl.returns.dim;)
602
                    {
603 1
                        Expression exp = (*funcdecl.returns)[i].exp;
604 1
                        if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult)
605
                        {
606 1
                            if (addReturn0())
607 1
                                exp.type = Type.tint32;
608
                            else
609 1
                                exp.type = f.next;
610
                            // Remove `return vresult;` from returns
611 1
                            funcdecl.returns.remove(i);
612 1
                            continue;
613
                        }
614 1
                        if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
615 1
                            f.isref = false;
616 1
                        i++;
617
                    }
618
                }
619 1
                if (f.isref) // Function returns a reference
620
                {
621 1
                    if (funcdecl.storage_class & STC.auto_)
622 1
                        funcdecl.storage_class &= ~STC.auto_;
623
                }
624

625
                // handle NRVO
626 1
                if (!target.isReturnOnStack(f, funcdecl.needThis()) || funcdecl.checkNrvo())
627 1
                    funcdecl.nrvo_can = 0;
628

629 1
                if (funcdecl.fbody.isErrorStatement())
630
                {
631
                }
632 1
                else if (funcdecl.isStaticCtorDeclaration())
633
                {
634
                    /* It's a static constructor. Ensure that all
635
                     * ctor consts were initialized.
636
                     */
637 1
                    ScopeDsymbol pd = funcdecl.toParent().isScopeDsymbol();
638 1
                    for (size_t i = 0; i < pd.members.dim; i++)
639
                    {
640 1
                        Dsymbol s = (*pd.members)[i];
641 1
                        s.checkCtorConstInit();
642
                    }
643
                }
644 1
                else if (ad2 && funcdecl.isCtorDeclaration())
645
                {
646 1
                    ClassDeclaration cd = ad2.isClassDeclaration();
647

648
                    // Verify that all the ctorinit fields got initialized
649 1
                    if (!(sc2.ctorflow.callSuper & CSX.this_ctor))
650
                    {
651 1
                        foreach (i, v; ad2.fields)
652
                        {
653 1
                            if (v.isThisDeclaration())
654 1
                                continue;
655 1
                            if (v.ctorinit == 0)
656
                            {
657
                                /* Current bugs in the flow analysis:
658
                                 * 1. union members should not produce error messages even if
659
                                 *    not assigned to
660
                                 * 2. structs should recognize delegating opAssign calls as well
661
                                 *    as delegating calls to other constructors
662
                                 */
663 1
                                if (v.isCtorinit() && !v.type.isMutable() && cd)
664 1
                                    funcdecl.error("missing initializer for %s field `%s`", MODtoChars(v.type.mod), v.toChars());
665 1
                                else if (v.storage_class & STC.nodefaultctor)
666 1
                                    error(funcdecl.loc, "field `%s` must be initialized in constructor", v.toChars());
667 1
                                else if (v.type.needsNested())
668 1
                                    error(funcdecl.loc, "field `%s` must be initialized in constructor, because it is nested struct", v.toChars());
669
                            }
670
                            else
671
                            {
672 1
                                bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
673 1
                                if (mustInit && !(sc2.ctorflow.fieldinit[i].csx & CSX.this_ctor))
674
                                {
675 0
                                    funcdecl.error("field `%s` must be initialized but skipped", v.toChars());
676
                                }
677
                            }
678
                        }
679
                    }
680 1
                    sc2.ctorflow.freeFieldinit();
681

682 1
                    if (cd && !(sc2.ctorflow.callSuper & CSX.any_ctor) && cd.baseClass && cd.baseClass.ctor)
683
                    {
684 1
                        sc2.ctorflow.callSuper = CSX.none;
685

686
                        // Insert implicit super() at start of fbody
687 1
                        Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod);
688 1
                        FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, null, FuncResolveFlag.quiet);
689 1
                        if (!fd)
690
                        {
691 1
                            funcdecl.error("no match for implicit `super()` call in constructor");
692
                        }
693 1
                        else if (fd.storage_class & STC.disable)
694
                        {
695 1
                            funcdecl.error("cannot call `super()` implicitly because it is annotated with `@disable`");
696
                        }
697
                        else
698
                        {
699 1
                            Expression e1 = new SuperExp(Loc.initial);
700 1
                            Expression e = new CallExp(Loc.initial, e1);
701 1
                            e = e.expressionSemantic(sc2);
702 1
                            Statement s = new ExpStatement(Loc.initial, e);
703 1
                            funcdecl.fbody = new CompoundStatement(Loc.initial, s, funcdecl.fbody);
704
                        }
705
                    }
706
                    //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
707
                }
708

709
                /* https://issues.dlang.org/show_bug.cgi?id=17502
710
                 * Wait until after the return type has been inferred before
711
                 * generating the contracts for this function, and merging contracts
712
                 * from overrides.
713
                 *
714
                 * https://issues.dlang.org/show_bug.cgi?id=17893
715
                 * However should take care to generate this before inferered
716
                 * function attributes are applied, such as 'nothrow'.
717
                 *
718
                 * This was originally at the end of the first semantic pass, but
719
                 * required a fix-up to be done here for the '__result' variable
720
                 * type of __ensure() inside auto functions, but this didn't work
721
                 * if the out parameter was implicit.
722
                 */
723 1
                funcdecl.buildEnsureRequire();
724

725
                // Check for errors related to 'nothrow'.
726 1
                const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow);
727 1
                if (f.isnothrow && blockexit & BE.throw_)
728 1
                    error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
729

730 1
                if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
731
                {
732
                    /* Disable optimization on Win32 due to
733
                     * https://issues.dlang.org/show_bug.cgi?id=17997
734
                     */
735
//                    if (!global.params.isWindows || global.params.is64bit)
736 1
                        funcdecl.eh_none = true;         // don't generate unwind tables for this function
737
                }
738

739 1
                if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
740
                {
741 1
                    if (funcdecl.type == f)
742 1
                        f = cast(TypeFunction)f.copy();
743 1
                    f.isnothrow = !(blockexit & BE.throw_);
744
                }
745

746 1
                if (funcdecl.fbody.isErrorStatement())
747
                {
748
                }
749 1
                else if (ad2 && funcdecl.isCtorDeclaration())
750
                {
751
                    /* Append:
752
                     *  return this;
753
                     * to function body
754
                     */
755 1
                    if (blockexit & BE.fallthru)
756
                    {
757 1
                        Statement s = new ReturnStatement(funcdecl.loc, null);
758 1
                        s = s.statementSemantic(sc2);
759 1
                        funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
760 1
                        funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
761
                    }
762
                }
763 1
                else if (funcdecl.fes)
764
                {
765
                    // For foreach(){} body, append a return 0;
766 1
                    if (blockexit & BE.fallthru)
767
                    {
768 1
                        Expression e = IntegerExp.literal!0;
769 1
                        Statement s = new ReturnStatement(Loc.initial, e);
770 1
                        funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
771 1
                        funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
772
                    }
773 1
                    assert(!funcdecl.returnLabel);
774
                }
775
                else
776
                {
777 1
                    const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
778 1
                    if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm)
779
                    {
780 1
                        Expression e;
781 1
                        if (!funcdecl.hasReturnExp)
782 1
                            funcdecl.error("has no `return` statement, but is expected to return a value of type `%s`", f.next.toChars());
783
                        else
784 1
                            funcdecl.error("no `return exp;` or `assert(0);` at end of function");
785 1
                        if (global.params.useAssert == CHECKENABLE.on && !global.params.useInline)
786
                        {
787
                            /* Add an assert(0, msg); where the missing return
788
                             * should be.
789
                             */
790 1
                            e = new AssertExp(funcdecl.endloc, IntegerExp.literal!0, new StringExp(funcdecl.loc, "missing return expression"));
791
                        }
792
                        else
793 0
                            e = new HaltExp(funcdecl.endloc);
794 1
                        e = new CommaExp(Loc.initial, e, f.next.defaultInit(Loc.initial));
795 1
                        e = e.expressionSemantic(sc2);
796 1
                        Statement s = new ExpStatement(Loc.initial, e);
797 1
                        funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
798
                    }
799
                }
800

801 1
                if (funcdecl.returns)
802
                {
803 1
                    bool implicit0 = addReturn0();
804 1
                    Type tret = implicit0 ? Type.tint32 : f.next;
805 1
                    assert(tret.ty != Tvoid);
806 1
                    if (funcdecl.vresult || funcdecl.returnLabel)
807 1
                        funcdecl.buildResultVar(scout ? scout : sc2, tret);
808

809
                    /* Cannot move this loop into NrvoWalker, because
810
                     * returns[i] may be in the nested delegate for foreach-body.
811
                     */
812 1
                    for (size_t i = 0; i < funcdecl.returns.dim; i++)
813
                    {
814 1
                        ReturnStatement rs = (*funcdecl.returns)[i];
815 1
                        Expression exp = rs.exp;
816 1
                        if (exp.op == TOK.error)
817 1
                            continue;
818 1
                        if (tret.ty == Terror)
819
                        {
820
                            // https://issues.dlang.org/show_bug.cgi?id=13702
821 1
                            exp = checkGC(sc2, exp);
822 1
                            continue;
823
                        }
824

825
                        /* If the expression in the return statement (exp) cannot be implicitly
826
                         * converted to the return type (tret) of the function and if the
827
                         * type of the expression is type isolated, then it may be possible
828
                         * that a promotion to `immutable` or `inout` (through a cast) will
829
                         * match the return type.
830
                         */
831 1
                        if (!exp.implicitConvTo(tret) && funcdecl.isTypeIsolated(exp.type))
832
                        {
833
                            /* https://issues.dlang.org/show_bug.cgi?id=20073
834
                             *
835
                             * The problem is that if the type of the returned expression (exp.type)
836
                             * is an aggregated declaration with an alias this, the alias this may be
837
                             * used for the conversion testing without it being an isolated type.
838
                             *
839
                             * To make sure this does not happen, we can test here the implicit conversion
840
                             * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
841
                             * The implicit conversion with alias this is taken care of later.
842
                             */
843 1
                            AggregateDeclaration aggDecl = isAggregate(exp.type);
844 1
                            TypeStruct tstruct;
845 1
                            TypeClass tclass;
846 1
                            bool hasAliasThis;
847 1
                            if (aggDecl && aggDecl.aliasthis)
848
                            {
849 1
                                hasAliasThis = true;
850 1
                                tclass = exp.type.isTypeClass();
851 1
                                if (!tclass)
852 1
                                    tstruct = exp.type.isTypeStruct();
853 1
                                assert(tclass || tstruct);
854
                            }
855 1
                            if (hasAliasThis)
856
                            {
857 1
                                if (tclass)
858
                                {
859 0
                                    if ((cast(TypeClass)(exp.type.immutableOf())).implicitConvToWithoutAliasThis(tret))
860 0
                                        exp = exp.castTo(sc2, exp.type.immutableOf());
861 0
                                    else if ((cast(TypeClass)(exp.type.wildOf())).implicitConvToWithoutAliasThis(tret))
862 0
                                        exp = exp.castTo(sc2, exp.type.wildOf());
863
                                }
864
                                else
865
                                {
866 1
                                    if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
867 0
                                        exp = exp.castTo(sc2, exp.type.immutableOf());
868 1
                                    else if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
869 0
                                        exp = exp.castTo(sc2, exp.type.wildOf());
870
                                }
871
                            }
872
                            else
873
                            {
874 1
                                if (exp.type.immutableOf().implicitConvTo(tret))
875 1
                                    exp = exp.castTo(sc2, exp.type.immutableOf());
876 1
                                else if (exp.type.wildOf().implicitConvTo(tret))
877 1
                                    exp = exp.castTo(sc2, exp.type.wildOf());
878
                            }
879
                        }
880

881 1
                        const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
882
                        // if a copy constructor is present, the return type conversion will be handled by it
883 1
                        if (!(hasCopyCtor && exp.isLvalue()))
884 1
                            exp = exp.implicitCastTo(sc2, tret);
885

886 1
                        if (f.isref)
887
                        {
888
                            // Function returns a reference
889 1
                            exp = exp.toLvalue(sc2, exp);
890 1
                            checkReturnEscapeRef(sc2, exp, false);
891
                        }
892
                        else
893
                        {
894 1
                            exp = exp.optimize(WANTvalue);
895

896
                            /* https://issues.dlang.org/show_bug.cgi?id=10789
897
                             * If NRVO is not possible, all returned lvalues should call their postblits.
898
                             */
899 1
                            if (!funcdecl.nrvo_can)
900 1
                                exp = doCopyOrMove(sc2, exp, f.next);
901

902 1
                            if (tret.hasPointers())
903 1
                                checkReturnEscape(sc2, exp, false);
904
                        }
905

906 1
                        exp = checkGC(sc2, exp);
907

908 1
                        if (funcdecl.vresult)
909
                        {
910
                            // Create: return vresult = exp;
911 1
                            exp = new BlitExp(rs.loc, funcdecl.vresult, exp);
912 1
                            exp.type = funcdecl.vresult.type;
913

914 1
                            if (rs.caseDim)
915 1
                                exp = Expression.combine(exp, new IntegerExp(rs.caseDim));
916
                        }
917 1
                        else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf()))
918
                        {
919 1
                            exp = exp.implicitCastTo(sc2, funcdecl.tintro.nextOf());
920
                        }
921 1
                        rs.exp = exp;
922
                    }
923
                }
924 1
                if (funcdecl.nrvo_var || funcdecl.returnLabel)
925
                {
926 1
                    scope NrvoWalker nw = new NrvoWalker();
927 1
                    nw.fd = funcdecl;
928 1
                    nw.sc = sc2;
929 1
                    nw.visitStmt(funcdecl.fbody);
930
                }
931

932 1
                sc2 = sc2.pop();
933
            }
934

935 1
            funcdecl.frequire = funcdecl.mergeFrequire(funcdecl.frequire, funcdecl.fdrequireParams);
936 1
            funcdecl.fensure = funcdecl.mergeFensure(funcdecl.fensure, Id.result, funcdecl.fdensureParams);
937

938 1
            Statement freq = funcdecl.frequire;
939 1
            Statement fens = funcdecl.fensure;
940

941
            /* Do the semantic analysis on the [in] preconditions and
942
             * [out] postconditions.
943
             */
944 1
            if (freq)
945
            {
946
                /* frequire is composed of the [in] contracts
947
                 */
948 1
                auto sym = new ScopeDsymbol(funcdecl.loc, null);
949 1
                sym.parent = sc2.scopesym;
950 1
                sym.endlinnum = funcdecl.endloc.linnum;
951 1
                sc2 = sc2.push(sym);
952 1
                sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
953

954
                // BUG: need to error if accessing out parameters
955
                // BUG: need to disallow returns and throws
956
                // BUG: verify that all in and ref parameters are read
957 1
                freq = freq.statementSemantic(sc2);
958 1
                freq.blockExit(funcdecl, false);
959

960 1
                funcdecl.eh_none = false;
961

962 1
                sc2 = sc2.pop();
963

964 1
                if (global.params.useIn == CHECKENABLE.off)
965 1
                    freq = null;
966
            }
967 1
            if (fens)
968
            {
969
                /* fensure is composed of the [out] contracts
970
                 */
971 1
                if (f.next.ty == Tvoid && funcdecl.fensures)
972
                {
973 1
                    foreach (e; *funcdecl.fensures)
974
                    {
975 1
                        if (e.id)
976
                        {
977 1
                            funcdecl.error(e.ensure.loc, "`void` functions have no result");
978
                            //fens = null;
979
                        }
980
                    }
981
                }
982

983 1
                sc2 = scout; //push
984 1
                sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
985

986
                // BUG: need to disallow returns and throws
987

988 1
                if (funcdecl.fensure && f.next.ty != Tvoid)
989 1
                    funcdecl.buildResultVar(scout, f.next);
990

991 1
                fens = fens.statementSemantic(sc2);
992 1
                fens.blockExit(funcdecl, false);
993

994 1
                funcdecl.eh_none = false;
995

996 1
                sc2 = sc2.pop();
997

998 1
                if (global.params.useOut == CHECKENABLE.off)
999 1
                    fens = null;
1000
            }
1001 1
            if (funcdecl.fbody && funcdecl.fbody.isErrorStatement())
1002
            {
1003
            }
1004
            else
1005
            {
1006 1
                auto a = new Statements();
1007
                // Merge in initialization of 'out' parameters
1008 1
                if (funcdecl.parameters)
1009
                {
1010 1
                    for (size_t i = 0; i < funcdecl.parameters.dim; i++)
1011
                    {
1012 1
                        VarDeclaration v = (*funcdecl.parameters)[i];
1013 1
                        if (v.storage_class & STC.out_)
1014
                        {
1015 1
                            if (!v._init)
1016
                            {
1017 1
                                v.error("Zero-length `out` parameters are not allowed.");
1018 1
                                return;
1019
                            }
1020 1
                            ExpInitializer ie = v._init.isExpInitializer();
1021 1
                            assert(ie);
1022 1
                            if (auto iec = ie.exp.isConstructExp())
1023
                            {
1024
                                // construction occurred in parameter processing
1025 0
                                auto ec = new AssignExp(iec.loc, iec.e1, iec.e2);
1026 0
                                ec.type = iec.type;
1027 0
                                ie.exp = ec;
1028
                            }
1029 1
                            a.push(new ExpStatement(Loc.initial, ie.exp));
1030
                        }
1031
                    }
1032
                }
1033

1034 1
                if (_arguments)
1035
                {
1036
                    /* Advance to elements[] member of TypeInfo_Tuple with:
1037
                     *  _arguments = v_arguments.elements;
1038
                     */
1039 1
                    Expression e = new VarExp(Loc.initial, funcdecl.v_arguments);
1040 1
                    e = new DotIdExp(Loc.initial, e, Id.elements);
1041 1
                    e = new ConstructExp(Loc.initial, _arguments, e);
1042 1
                    e = e.expressionSemantic(sc2);
1043

1044 1
                    _arguments._init = new ExpInitializer(Loc.initial, e);
1045 1
                    auto de = new DeclarationExp(Loc.initial, _arguments);
1046 1
                    a.push(new ExpStatement(Loc.initial, de));
1047
                }
1048

1049
                // Merge contracts together with body into one compound statement
1050

1051 1
                if (freq || fpreinv)
1052
                {
1053 1
                    if (!freq)
1054 1
                        freq = fpreinv;
1055 1
                    else if (fpreinv)
1056 1
                        freq = new CompoundStatement(Loc.initial, freq, fpreinv);
1057

1058 1
                    a.push(freq);
1059
                }
1060

1061 1
                if (funcdecl.fbody)
1062 1
                    a.push(funcdecl.fbody);
1063

1064 1
                if (fens || fpostinv)
1065
                {
1066 1
                    if (!fens)
1067 1
                        fens = fpostinv;
1068 1
                    else if (fpostinv)
1069 1
                        fens = new CompoundStatement(Loc.initial, fpostinv, fens);
1070

1071 1
                    auto ls = new LabelStatement(Loc.initial, Id.returnLabel, fens);
1072 1
                    funcdecl.returnLabel.statement = ls;
1073 1
                    a.push(funcdecl.returnLabel.statement);
1074

1075 1
                    if (f.next.ty != Tvoid && funcdecl.vresult)
1076
                    {
1077
                        // Create: return vresult;
1078 1
                        Expression e = new VarExp(Loc.initial, funcdecl.vresult);
1079 1
                        if (funcdecl.tintro)
1080
                        {
1081 1
                            e = e.implicitCastTo(sc, funcdecl.tintro.nextOf());
1082 1
                            e = e.expressionSemantic(sc);
1083
                        }
1084 1
                        auto s = new ReturnStatement(Loc.initial, e);
1085 1
                        a.push(s);
1086
                    }
1087
                }
1088 1
                if (addReturn0())
1089
                {
1090
                    // Add a return 0; statement
1091 1
                    Statement s = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
1092 1
                    a.push(s);
1093
                }
1094

1095 1
                Statement sbody = new CompoundStatement(Loc.initial, a);
1096

1097
                /* Append destructor calls for parameters as finally blocks.
1098
                 */
1099 1
                if (funcdecl.parameters)
1100
                {
1101 1
                    foreach (v; *funcdecl.parameters)
1102
                    {
1103 1
                        if (v.storage_class & (STC.ref_ | STC.out_ | STC.lazy_))
1104 1
                            continue;
1105 1
                        if (v.needsScopeDtor())
1106
                        {
1107
                            // same with ExpStatement.scopeCode()
1108 1
                            Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
1109 1
                            v.storage_class |= STC.nodtor;
1110

1111 1
                            s = s.statementSemantic(sc2);
1112

1113 1
                            bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
1114 1
                            const blockexit = s.blockExit(funcdecl, isnothrow);
1115 1
                            if (blockexit & BE.throw_)
1116 1
                                funcdecl.eh_none = false;
1117 1
                            if (f.isnothrow && isnothrow && blockexit & BE.throw_)
1118 1
                                error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
1119 1
                            if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_)
1120 1
                                f.isnothrow = false;
1121

1122 1
                            if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru)
1123 1
                                sbody = new CompoundStatement(Loc.initial, sbody, s);
1124
                            else
1125 1
                                sbody = new TryFinallyStatement(Loc.initial, sbody, s);
1126
                        }
1127
                    }
1128
                }
1129
                // from this point on all possible 'throwers' are checked
1130 1
                funcdecl.flags &= ~FUNCFLAG.nothrowInprocess;
1131

1132 1
                if (funcdecl.isSynchronized())
1133
                {
1134
                    /* Wrap the entire function body in a synchronized statement
1135
                     */
1136 1
                    ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
1137 1
                    if (cd)
1138
                    {
1139 1
                        if (!global.params.is64bit && global.params.isWindows && !funcdecl.isStatic() && !sbody.usesEH() && !global.params.trace)
1140
                        {
1141
                            /* The back end uses the "jmonitor" hack for syncing;
1142
                             * no need to do the sync at this level.
1143
                             */
1144
                        }
1145
                        else
1146
                        {
1147 1
                            Expression vsync;
1148 1
                            if (funcdecl.isStatic())
1149
                            {
1150
                                // The monitor is in the ClassInfo
1151 1
                                vsync = new DotIdExp(funcdecl.loc, symbolToExp(cd, funcdecl.loc, sc2, false), Id.classinfo);
1152
                            }
1153
                            else
1154
                            {
1155
                                // 'this' is the monitor
1156 1
                                vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
1157 1
                                if (funcdecl.isThis2)
1158
                                {
1159 0
                                    vsync = new PtrExp(funcdecl.loc, vsync);
1160 0
                                    vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
1161
                                }
1162
                            }
1163 1
                            sbody = new PeelStatement(sbody); // don't redo semantic()
1164 1
                            sbody = new SynchronizedStatement(funcdecl.loc, vsync, sbody);
1165 1
                            sbody = sbody.statementSemantic(sc2);
1166
                        }
1167
                    }
1168
                    else
1169
                    {
1170 0
                        funcdecl.error("synchronized function `%s` must be a member of a class", funcdecl.toChars());
1171
                    }
1172
                }
1173

1174
                // If declaration has no body, don't set sbody to prevent incorrect codegen.
1175 1
                if (funcdecl.fbody || funcdecl.allowsContractWithoutBody())
1176 1
                    funcdecl.fbody = sbody;
1177
            }
1178

1179
            // Check for undefined labels
1180 1
            if (funcdecl.labtab)
1181 1
                foreach (keyValue; funcdecl.labtab.tab.asRange)
1182
                {
1183
                    //printf("  KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1184 1
                    LabelDsymbol label = cast(LabelDsymbol)keyValue.value;
1185 1
                    if (!label.statement && (!label.deleted || label.iasm))
1186
                    {
1187 1
                        funcdecl.error("label `%s` is undefined", label.toChars());
1188
                    }
1189
                }
1190

1191
            // Fix up forward-referenced gotos
1192 1
            if (funcdecl.gotos)
1193
            {
1194 1
                for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
1195
                {
1196 1
                    (*funcdecl.gotos)[i].checkLabel();
1197
                }
1198
            }
1199

1200 1
            if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
1201 1
                funcdecl.error("naked assembly functions with contracts are not supported");
1202

1203 1
            sc2.ctorflow.callSuper = CSX.none;
1204 1
            sc2.pop();
1205
        }
1206

1207 1
        if (funcdecl.checkClosure())
1208
        {
1209
            // We should be setting errors here instead of relying on the global error count.
1210
            //errors = true;
1211
        }
1212

1213
        /* If function survived being marked as impure, then it is pure
1214
         */
1215 1
        if (funcdecl.flags & FUNCFLAG.purityInprocess)
1216
        {
1217 1
            funcdecl.flags &= ~FUNCFLAG.purityInprocess;
1218 1
            if (funcdecl.type == f)
1219 1
                f = cast(TypeFunction)f.copy();
1220 1
            f.purity = PURE.fwdref;
1221
        }
1222

1223 1
        if (funcdecl.flags & FUNCFLAG.safetyInprocess)
1224
        {
1225 1
            funcdecl.flags &= ~FUNCFLAG.safetyInprocess;
1226 1
            if (funcdecl.type == f)
1227 1
                f = cast(TypeFunction)f.copy();
1228 1
            f.trust = TRUST.safe;
1229
        }
1230

1231 1
        if (funcdecl.flags & FUNCFLAG.nogcInprocess)
1232
        {
1233 1
            funcdecl.flags &= ~FUNCFLAG.nogcInprocess;
1234 1
            if (funcdecl.type == f)
1235 1
                f = cast(TypeFunction)f.copy();
1236 1
            f.isnogc = true;
1237
        }
1238

1239 1
        if (funcdecl.flags & FUNCFLAG.returnInprocess)
1240
        {
1241 1
            funcdecl.flags &= ~FUNCFLAG.returnInprocess;
1242 1
            if (funcdecl.storage_class & STC.return_)
1243
            {
1244 1
                if (funcdecl.type == f)
1245 0
                    f = cast(TypeFunction)f.copy();
1246 1
                f.isreturn = true;
1247 1
                if (funcdecl.storage_class & STC.returninferred)
1248 1
                    f.isreturninferred = true;
1249
            }
1250
        }
1251

1252 1
        funcdecl.flags &= ~FUNCFLAG.inferScope;
1253

1254
        // Eliminate maybescope's
1255
        {
1256
            // Create and fill array[] with maybe candidates from the `this` and the parameters
1257 1
            VarDeclaration[] array = void;
1258

1259 1
            VarDeclaration[10] tmp = void;
1260 1
            size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0);
1261 1
            if (dim <= tmp.length)
1262 1
                array = tmp[0 .. dim];
1263
            else
1264
            {
1265 1
                auto ptr = cast(VarDeclaration*)mem.xmalloc(dim * VarDeclaration.sizeof);
1266 1
                array = ptr[0 .. dim];
1267
            }
1268 1
            size_t n = 0;
1269 1
            if (funcdecl.vthis)
1270 1
                array[n++] = funcdecl.vthis;
1271 1
            if (funcdecl.parameters)
1272
            {
1273 1
                foreach (v; *funcdecl.parameters)
1274
                {
1275 1
                    array[n++] = v;
1276
                }
1277
            }
1278

1279 1
            eliminateMaybeScopes(array[0 .. n]);
1280

1281 1
            if (dim > tmp.length)
1282 1
                mem.xfree(array.ptr);
1283
        }
1284

1285
        // Infer STC.scope_
1286 1
        if (funcdecl.parameters && !funcdecl.errors)
1287
        {
1288 1
            assert(f.parameterList.length == funcdecl.parameters.dim);
1289 1
            foreach (u, p; f.parameterList)
1290
            {
1291 1
                auto v = (*funcdecl.parameters)[u];
1292 1
                if (v.storage_class & STC.maybescope)
1293
                {
1294
                    //printf("Inferring scope for %s\n", v.toChars());
1295 1
                    notMaybeScope(v);
1296 1
                    v.storage_class |= STC.scope_ | STC.scopeinferred;
1297 1
                    p.storageClass |= STC.scope_ | STC.scopeinferred;
1298 1
                    assert(!(p.storageClass & STC.maybescope));
1299
                }
1300
            }
1301
        }
1302

1303 1
        if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope)
1304
        {
1305 1
            notMaybeScope(funcdecl.vthis);
1306 1
            funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred;
1307 1
            f.isScopeQual = true;
1308 1
            f.isscopeinferred = true;
1309
        }
1310

1311
        // reset deco to apply inference result to mangled name
1312 1
        if (f != funcdecl.type)
1313 1
            f.deco = null;
1314

1315
        // Do semantic type AFTER pure/nothrow inference.
1316 1
        if (!f.deco && funcdecl.ident != Id.xopEquals && funcdecl.ident != Id.xopCmp)
1317
        {
1318 1
            sc = sc.push();
1319 1
            if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1320 1
                sc.flags |= SCOPE.ctor;
1321 1
            sc.stc = 0;
1322 1
            sc.linkage = funcdecl.linkage; // https://issues.dlang.org/show_bug.cgi?id=8496
1323 1
            funcdecl.type = f.typeSemantic(funcdecl.loc, sc);
1324 1
            sc = sc.pop();
1325
        }
1326

1327
        // Do live analysis
1328 1
        if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
1329 1
            funcdecl.type.isTypeFunction().islive)
1330
        {
1331 1
            oblive(funcdecl);
1332
        }
1333

1334
        /* If this function had instantiated with gagging, error reproduction will be
1335
         * done by TemplateInstance::semantic.
1336
         * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1337
         */
1338 1
        funcdecl.semanticRun = PASS.semantic3done;
1339 1
        funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
1340 1
        if (funcdecl.type.ty == Terror)
1341 1
            funcdecl.errors = true;
1342
        //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
1343
        //fflush(stdout);
1344
    }
1345

1346
    override void visit(CtorDeclaration ctor)
1347
    {
1348
        //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1349 1
        if (ctor.semanticRun >= PASS.semantic3)
1350 1
            return;
1351

1352
        /* If any of the fields of the aggregate have a destructor, add
1353
         *   scope (failure) { this.fieldDtor(); }
1354
         * as the first statement. It is not necessary to add it after
1355
         * each initialization of a field, because destruction of .init constructed
1356
         * structs should be benign.
1357
         * https://issues.dlang.org/show_bug.cgi?id=14246
1358
         */
1359 1
        AggregateDeclaration ad = ctor.isMemberDecl();
1360 1
        if (ad && ad.fieldDtor && global.params.dtorFields)
1361
        {
1362
            /* Generate:
1363
             *   this.fieldDtor()
1364
             */
1365 1
            Expression e = new ThisExp(ctor.loc);
1366 1
            e.type = ad.type.mutableOf();
1367 1
            e = new DotVarExp(ctor.loc, e, ad.fieldDtor, false);
1368 1
            e = new CallExp(ctor.loc, e);
1369 1
            auto sexp = new ExpStatement(ctor.loc, e);
1370 1
            auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
1371

1372
            version (all)
1373
            {
1374
                /* Generate:
1375
                 *   try { ctor.fbody; }
1376
                 *   catch (Exception __o)
1377
                 *   { this.fieldDtor(); throw __o; }
1378
                 * This differs from the alternate scope(failure) version in that an Exception
1379
                 * is caught rather than a Throwable. This enables the optimization whereby
1380
                 * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1381
                 * applies to Exception.)
1382
                 */
1383 1
                Identifier id = Identifier.generateId("__o");
1384 1
                auto ts = new ThrowStatement(ctor.loc, new IdentifierExp(ctor.loc, id));
1385 1
                auto handler = new CompoundStatement(ctor.loc, ss, ts);
1386

1387 1
                auto catches = new Catches();
1388 1
                auto ctch = new Catch(ctor.loc, getException(), id, handler);
1389 1
                catches.push(ctch);
1390

1391 1
                ctor.fbody = new TryCatchStatement(ctor.loc, ctor.fbody, catches);
1392
            }
1393
            else
1394
            {
1395
                /* Generate:
1396
                 *   scope (failure) { this.fieldDtor(); }
1397
                 * Hopefully we can use this version someday when scope(failure) catches
1398
                 * Exception instead of Throwable.
1399
                 */
1400
                auto s = new ScopeGuardStatement(ctor.loc, TOK.onScopeFailure, ss);
1401
                ctor.fbody = new CompoundStatement(ctor.loc, s, ctor.fbody);
1402
            }
1403
        }
1404 1
        visit(cast(FuncDeclaration)ctor);
1405
    }
1406

1407

1408
    override void visit(Nspace ns)
1409
    {
1410 1
        if (ns.semanticRun >= PASS.semantic3)
1411 0
            return;
1412 1
        ns.semanticRun = PASS.semantic3;
1413
        static if (LOG)
1414
        {
1415
            printf("Nspace::semantic3('%s')\n", ns.toChars());
1416
        }
1417 1
        if (ns.members)
1418
        {
1419 1
            sc = sc.push(ns);
1420 1
            sc.linkage = LINK.cpp;
1421 1
            foreach (s; *ns.members)
1422
            {
1423 1
                s.semantic3(sc);
1424
            }
1425 1
            sc.pop();
1426
        }
1427
    }
1428

1429
    override void visit(AttribDeclaration ad)
1430
    {
1431 1
        Dsymbols* d = ad.include(sc);
1432 1
        if (d)
1433
        {
1434 1
            Scope* sc2 = ad.newScope(sc);
1435 1
            for (size_t i = 0; i < d.dim; i++)
1436
            {
1437 1
                Dsymbol s = (*d)[i];
1438 1
                s.semantic3(sc2);
1439
            }
1440 1
            if (sc2 != sc)
1441 1
                sc2.pop();
1442
        }
1443
    }
1444

1445
    override void visit(AggregateDeclaration ad)
1446
    {
1447
        //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1448 1
        if (!ad.members)
1449 1
            return;
1450

1451 1
        StructDeclaration sd = ad.isStructDeclaration();
1452 1
        if (!sc) // from runDeferredSemantic3 for TypeInfo generation
1453
        {
1454 1
            assert(sd);
1455 1
            sd.semanticTypeInfoMembers();
1456 1
            return;
1457
        }
1458

1459 1
        auto sc2 = ad.newScope(sc);
1460

1461 1
        for (size_t i = 0; i < ad.members.dim; i++)
1462
        {
1463 1
            Dsymbol s = (*ad.members)[i];
1464 1
            s.semantic3(sc2);
1465
        }
1466

1467 1
        sc2.pop();
1468

1469
        // don't do it for unused deprecated types
1470
        // or error ypes
1471 1
        if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror))
1472
        {
1473
            // Evaluate: RTinfo!type
1474 1
            auto tiargs = new Objects();
1475 1
            tiargs.push(ad.type);
1476 1
            auto ti = Pool!TemplateInstance.make(ad.loc, Type.rtinfo, tiargs);
1477

1478 1
            Scope* sc3 = ti.tempdecl._scope.startCTFE();
1479 1
            sc3.tinst = sc.tinst;
1480 1
            sc3.minst = sc.minst;
1481 1
            if (ad.isDeprecated())
1482 1
                sc3.stc |= STC.deprecated_;
1483

1484 1
            ti.dsymbolSemantic(sc3);
1485 1
            ti.semantic2(sc3);
1486 1
            ti.semantic3(sc3);
1487 1
            auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false);
1488

1489 1
            sc3.endCTFE();
1490

1491 1
            e = e.ctfeInterpret();
1492 1
            ad.getRTInfo = e;
1493
        }
1494 1
        if (sd)
1495 1
            sd.semanticTypeInfoMembers();
1496 1
        ad.semanticRun = PASS.semantic3done;
1497
    }
1498
}
1499

1500
private struct FuncDeclSem3
1501
{
1502
    // The FuncDeclaration subject to Semantic analysis
1503
    FuncDeclaration funcdecl;
1504

1505
    // Scope of analysis
1506
    Scope* sc;
1507 1
    this(FuncDeclaration fd,Scope* s)
1508
    {
1509 1
        funcdecl = fd;
1510 1
        sc = s;
1511
    }
1512

1513
    /* Checks that the overriden functions (if any) have in contracts if
1514
     * funcdecl has an in contract.
1515
     */
1516
    void checkInContractOverrides()
1517
    {
1518 1
        if (funcdecl.frequires)
1519
        {
1520 1
            for (size_t i = 0; i < funcdecl.foverrides.dim; i++)
1521
            {
1522 1
                FuncDeclaration fdv = funcdecl.foverrides[i];
1523 1
                if (fdv.fbody && !fdv.frequires)
1524
                {
1525 1
                    funcdecl.error("cannot have an in contract when overridden function `%s` does not have an in contract", fdv.toPrettyChars());
1526 1
                    break;
1527
                }
1528
            }
1529
        }
1530
    }
1531
}

Read our documentation on viewing source code .

Loading