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     scope v = new Semantic3Visitor(sc);
81     dsym.accept(v);
82 }
83 
84 private extern(C++) final class Semantic3Visitor : Visitor
85 {
86     alias visit = Visitor.visit;
87 
88     Scope* sc;
89     this(Scope* sc)
90     {
91         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         if (tempinst.semanticRun >= PASS.semantic3)
104             return;
105         tempinst.semanticRun = PASS.semantic3;
106         if (!tempinst.errors && tempinst.members)
107         {
108             TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
109             assert(tempdecl);
110 
111             sc = tempdecl._scope;
112             sc = sc.push(tempinst.argsym);
113             sc = sc.push(tempinst);
114             sc.tinst = tempinst;
115             sc.minst = tempinst.minst;
116 
117             int needGagging = (tempinst.gagged && !global.gag);
118             uint olderrors = global.errors;
119             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             if (needGagging)
126                 oldGaggedErrors = global.startGagging();
127 
128             for (size_t i = 0; i < tempinst.members.dim; i++)
129             {
130                 Dsymbol s = (*tempinst.members)[i];
131                 s.semantic3(sc);
132                 if (tempinst.gagged && global.errors != olderrors)
133                     break;
134             }
135 
136             if (global.errors != olderrors)
137             {
138                 if (!tempinst.errors)
139                 {
140                     if (!tempdecl.literal)
141                         tempinst.error(tempinst.loc, "error instantiating");
142                     if (tempinst.tinst)
143                         tempinst.tinst.printInstantiationTrace();
144                 }
145                 tempinst.errors = true;
146             }
147             if (needGagging)
148                 global.endGagging(oldGaggedErrors);
149 
150             sc = sc.pop();
151             sc.pop();
152         }
153     }
154 
155     override void visit(TemplateMixin tmix)
156     {
157         if (tmix.semanticRun >= PASS.semantic3)
158             return;
159         tmix.semanticRun = PASS.semantic3;
160         static if (LOG)
161         {
162             printf("TemplateMixin.semantic3('%s')\n", tmix.toChars());
163         }
164         if (tmix.members)
165         {
166             sc = sc.push(tmix.argsym);
167             sc = sc.push(tmix);
168             for (size_t i = 0; i < tmix.members.dim; i++)
169             {
170                 Dsymbol s = (*tmix.members)[i];
171                 s.semantic3(sc);
172             }
173             sc = sc.pop();
174             sc.pop();
175         }
176     }
177 
178     override void visit(Module mod)
179     {
180         //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
181         if (mod.semanticRun != PASS.semantic2done)
182             return;
183         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         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         for (size_t i = 0; i < mod.members.dim; i++)
191         {
192             Dsymbol s = (*mod.members)[i];
193             //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
194             s.semantic3(sc);
195 
196             mod.runDeferredSemantic2();
197         }
198         if (mod.userAttribDecl)
199         {
200             mod.userAttribDecl.semantic3(sc);
201         }
202         sc = sc.pop();
203         sc.pop();
204         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             TypeFunction f = cast(TypeFunction)funcdecl.type;
214 
215             return f.next.ty == Tvoid &&
216                 (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain());
217         }
218 
219         VarDeclaration _arguments = null;
220 
221         if (!funcdecl.parent)
222         {
223             if (global.errors)
224                 return;
225             //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
226             assert(0);
227         }
228         if (funcdecl.errors || isError(funcdecl.parent))
229         {
230             funcdecl.errors = true;
231             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         if (funcdecl.ident == Id.assign && !funcdecl.inuse)
240         {
241             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                 uint oldErrors = global.startGagging();
248                 ++funcdecl.inuse;
249                 funcdecl.semantic3(sc);
250                 --funcdecl.inuse;
251                 if (global.endGagging(oldErrors))   // if errors happened
252                 {
253                     // Disable generated opAssign, because some members forbid identity assignment.
254                     funcdecl.storage_class |= STC.disable;
255                     funcdecl.fbody = null;   // remove fbody which contains the error
256                     funcdecl.semantic3Errors = false;
257                 }
258                 return;
259             }
260         }
261 
262         //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
263         if (funcdecl.semanticRun >= PASS.semantic3)
264             return;
265         funcdecl.semanticRun = PASS.semantic3;
266         funcdecl.semantic3Errors = false;
267 
268         if (!funcdecl.type || funcdecl.type.ty != Tfunction)
269             return;
270         TypeFunction f = cast(TypeFunction)funcdecl.type;
271         if (!funcdecl.inferRetType && f.next.ty == Terror)
272             return;
273 
274         if (!funcdecl.fbody && funcdecl.inferRetType && !f.next)
275         {
276             funcdecl.error("has no function body with return type inference");
277             return;
278         }
279 
280         uint oldErrors = global.errors;
281         auto fds = FuncDeclSem3(funcdecl,sc);
282 
283         fds.checkInContractOverrides();
284 
285         // Remember whether we need to generate an 'out' contract.
286         immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl);
287 
288         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             funcdecl.localsymtab = new DsymbolTable();
294 
295             // Establish function scope
296             auto ss = new ScopeDsymbol(funcdecl.loc, null);
297             // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
298             for (auto scx = sc; ; scx = scx.enclosing)
299             {
300                 if (scx.scopesym)
301                 {
302                     ss.parent = scx.scopesym;
303                     break;
304                 }
305             }
306             ss.endlinnum = funcdecl.endloc.linnum;
307             Scope* sc2 = sc.push(ss);
308             sc2.func = funcdecl;
309             sc2.parent = funcdecl;
310             sc2.ctorflow.callSuper = CSX.none;
311             sc2.sbreak = null;
312             sc2.scontinue = null;
313             sc2.sw = null;
314             sc2.fes = funcdecl.fes;
315             sc2.linkage = LINK.d;
316             sc2.stc &= STCFlowThruFunction;
317             sc2.protection = Prot(Prot.Kind.public_);
318             sc2.explicitProtection = 0;
319             sc2.aligndecl = null;
320             if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
321                 sc2.flags = sc.flags & ~SCOPE.contract;
322             sc2.flags &= ~SCOPE.compile;
323             sc2.tf = null;
324             sc2.os = null;
325             sc2.inLoop = false;
326             sc2.userAttribDecl = null;
327             if (sc2.intypeof == 1)
328                 sc2.intypeof = 2;
329             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             if (auto fld = funcdecl.isFuncLiteralDeclaration())
346             {
347                 if (auto ad = funcdecl.isMember2())
348                 {
349                     if (!sc.intypeof)
350                     {
351                         if (fld.tok == TOK.delegate_)
352                             funcdecl.error("cannot be %s members", ad.kind());
353                         else
354                             fld.tok = TOK.function_;
355                     }
356                     else
357                     {
358                         if (fld.tok != TOK.function_)
359                             fld.tok = TOK.delegate_;
360                     }
361                 }
362             }
363 
364             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             if (f.parameterList.varargs == VarArg.variadic)
371             {
372                 if (f.linkage == LINK.d)
373                 {
374                     // Variadic arguments depend on Typeinfo being defined.
375                     if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist)
376                     {
377                         if (!global.params.useTypeInfo)
378                             funcdecl.error("D-style variadic functions cannot be used with -betterC");
379                         else if (!Type.typeinfotypelist)
380                             funcdecl.error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
381                         else
382                             funcdecl.error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
383                         fatal();
384                     }
385 
386                     // Declare _arguments[]
387                     funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
388                     funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
389                     funcdecl.v_arguments.dsymbolSemantic(sc2);
390                     sc2.insert(funcdecl.v_arguments);
391                     funcdecl.v_arguments.parent = funcdecl;
392 
393                     //Type t = Type.dtypeinfo.type.constOf().arrayOf();
394                     Type t = Type.dtypeinfo.type.arrayOf();
395                     _arguments = new VarDeclaration(funcdecl.loc, t, Id._arguments, null);
396                     _arguments.storage_class |= STC.temp;
397                     _arguments.dsymbolSemantic(sc2);
398                     sc2.insert(_arguments);
399                     _arguments.parent = funcdecl;
400                 }
401                 if (f.linkage == LINK.d || f.parameterList.length)
402                 {
403                     // Declare _argptr
404                     Type t = Type.tvalist;
405                     // Init is handled in FuncDeclaration_toObjFile
406                     funcdecl.v_argptr = new VarDeclaration(funcdecl.loc, t, Id._argptr, new VoidInitializer(funcdecl.loc));
407                     funcdecl.v_argptr.storage_class |= STC.temp;
408                     funcdecl.v_argptr.dsymbolSemantic(sc2);
409                     sc2.insert(funcdecl.v_argptr);
410                     funcdecl.v_argptr.parent = funcdecl;
411                 }
412             }
413 
414             /* Declare all the function parameters as variables
415              * and install them in parameters[]
416              */
417             size_t nparams = f.parameterList.length;
418             if (nparams)
419             {
420                 /* parameters[] has all the tuples removed, as the back end
421                  * doesn't know about tuples
422                  */
423                 funcdecl.parameters = new VarDeclarations();
424                 funcdecl.parameters.reserve(nparams);
425                 for (size_t i = 0; i < nparams; i++)
426                 {
427                     Parameter fparam = f.parameterList[i];
428                     Identifier id = fparam.ident;
429                     StorageClass stc = 0;
430                     if (!id)
431                     {
432                         /* Generate identifier for un-named parameter,
433                          * because we need it later on.
434                          */
435                         fparam.ident = id = Identifier.generateId("_param_", i);
436                         stc |= STC.temp;
437                     }
438                     Type vtype = fparam.type;
439                     auto v = new VarDeclaration(funcdecl.loc, vtype, id, null);
440                     //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
441                     stc |= STC.parameter;
442                     if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
443                     {
444                         stc |= STC.variadic;
445                         auto vtypeb = vtype.toBasetype();
446                         if (vtypeb.ty == Tarray)
447                         {
448                             /* Since it'll be pointing into the stack for the array
449                              * contents, it needs to be `scope`
450                              */
451                             stc |= STC.scope_;
452                         }
453                     }
454 
455                     if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_))
456                         stc |= STC.maybescope;
457 
458                     stc |= fparam.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
459                     v.storage_class = stc;
460                     v.dsymbolSemantic(sc2);
461                     if (!sc2.insert(v))
462                     {
463                         funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
464                         funcdecl.errors = true;
465                     }
466                     else
467                         funcdecl.parameters.push(v);
468                     funcdecl.localsymtab.insert(v);
469                     v.parent = funcdecl;
470                     if (fparam.userAttribDecl)
471                         v.userAttribDecl = fparam.userAttribDecl;
472                 }
473             }
474 
475             // Declare the tuple symbols and put them in the symbol table,
476             // but not in parameters[].
477             if (f.parameterList.parameters)
478             foreach (fparam; *f.parameterList.parameters)
479             {
480                 if (!fparam.ident)
481                     continue; // never used, so ignore
482                 // expand any tuples
483                 if (fparam.type.ty != Ttuple)
484                     continue;
485 
486                 TypeTuple t = cast(TypeTuple)fparam.type;
487                 size_t dim = Parameter.dim(t.arguments);
488                 auto exps = new Objects(dim);
489                 foreach (j; 0 .. dim)
490                 {
491                     Parameter narg = Parameter.getNth(t.arguments, j);
492                     assert(narg.ident);
493                     VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
494                     assert(v);
495                     (*exps)[j] = new VarExp(v.loc, v);
496                 }
497                 assert(fparam.ident);
498                 auto v = new TupleDeclaration(funcdecl.loc, fparam.ident, exps);
499                 //printf("declaring tuple %s\n", v.toChars());
500                 v.isexp = true;
501                 if (!sc2.insert(v))
502                     funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
503                 funcdecl.localsymtab.insert(v);
504                 v.parent = funcdecl;
505             }
506 
507             // Precondition invariant
508             Statement fpreinv = null;
509             if (funcdecl.addPreInvariant())
510             {
511                 Expression e = addInvariant(funcdecl.loc, sc, funcdecl.isThis(), funcdecl.vthis);
512                 if (e)
513                     fpreinv = new ExpStatement(Loc.initial, e);
514             }
515 
516             // Postcondition invariant
517             Statement fpostinv = null;
518             if (funcdecl.addPostInvariant())
519             {
520                 Expression e = addInvariant(funcdecl.loc, sc, funcdecl.isThis(), funcdecl.vthis);
521                 if (e)
522                     fpostinv = new ExpStatement(Loc.initial, e);
523             }
524 
525             // Pre/Postcondition contract
526             if (!funcdecl.fbody)
527                 funcdecl.buildEnsureRequire();
528 
529             Scope* scout = null;
530             if (needEnsure || funcdecl.addPostInvariant())
531             {
532                 /* https://issues.dlang.org/show_bug.cgi?id=3657
533                  * Set the correct end line number for fensure scope.
534                  */
535                 uint fensure_endlin = funcdecl.endloc.linnum;
536                 if (funcdecl.fensure)
537                     if (auto s = funcdecl.fensure.isScopeStatement())
538                         fensure_endlin = s.endloc.linnum;
539 
540                 if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
541                 {
542                     funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
543                 }
544 
545                 // scope of out contract (need for vresult.semantic)
546                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
547                 sym.parent = sc2.scopesym;
548                 sym.endlinnum = fensure_endlin;
549                 scout = sc2.push(sym);
550             }
551 
552             if (funcdecl.fbody)
553             {
554                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
555                 sym.parent = sc2.scopesym;
556                 sym.endlinnum = funcdecl.endloc.linnum;
557                 sc2 = sc2.push(sym);
558 
559                 auto ad2 = funcdecl.isMemberLocal();
560 
561                 /* If this is a class constructor
562                  */
563                 if (ad2 && funcdecl.isCtorDeclaration())
564                 {
565                     sc2.ctorflow.allocFieldinit(ad2.fields.dim);
566                     foreach (v; ad2.fields)
567                     {
568                         v.ctorinit = 0;
569                     }
570                 }
571 
572                 if (!funcdecl.inferRetType && !target.isReturnOnStack(f, funcdecl.needThis()))
573                     funcdecl.nrvo_can = 0;
574 
575                 bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_));
576 
577                 funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2);
578                 if (!funcdecl.fbody)
579                     funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
580 
581                 if (funcdecl.naked)
582                 {
583                     fpreinv = null;         // can't accommodate with no stack frame
584                     fpostinv = null;
585                 }
586 
587                 assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref));
588                 f = cast(TypeFunction)funcdecl.type;
589 
590                 if (funcdecl.inferRetType)
591                 {
592                     // If no return type inferred yet, then infer a void
593                     if (!f.next)
594                         f.next = Type.tvoid;
595                     if (f.checkRetType(funcdecl.loc))
596                         funcdecl.fbody = new ErrorStatement();
597                 }
598                 if (global.params.vcomplex && f.next !is null)
599                     f.next.checkComplexTransition(funcdecl.loc, sc);
600 
601                 if (funcdecl.returns && !funcdecl.fbody.isErrorStatement())
602                 {
603                     for (size_t i = 0; i < funcdecl.returns.dim;)
604                     {
605                         Expression exp = (*funcdecl.returns)[i].exp;
606                         if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult)
607                         {
608                             if (addReturn0())
609                                 exp.type = Type.tint32;
610                             else
611                                 exp.type = f.next;
612                             // Remove `return vresult;` from returns
613                             funcdecl.returns.remove(i);
614                             continue;
615                         }
616                         if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
617                             f.isref = false;
618                         i++;
619                     }
620                 }
621                 if (f.isref) // Function returns a reference
622                 {
623                     if (funcdecl.storage_class & STC.auto_)
624                         funcdecl.storage_class &= ~STC.auto_;
625                 }
626 
627                 // handle NRVO
628                 if (!target.isReturnOnStack(f, funcdecl.needThis()) || funcdecl.checkNrvo())
629                     funcdecl.nrvo_can = 0;
630 
631                 if (funcdecl.fbody.isErrorStatement())
632                 {
633                 }
634                 else if (funcdecl.isStaticCtorDeclaration())
635                 {
636                     /* It's a static constructor. Ensure that all
637                      * ctor consts were initialized.
638                      */
639                     ScopeDsymbol pd = funcdecl.toParent().isScopeDsymbol();
640                     for (size_t i = 0; i < pd.members.dim; i++)
641                     {
642                         Dsymbol s = (*pd.members)[i];
643                         s.checkCtorConstInit();
644                     }
645                 }
646                 else if (ad2 && funcdecl.isCtorDeclaration())
647                 {
648                     ClassDeclaration cd = ad2.isClassDeclaration();
649 
650                     // Verify that all the ctorinit fields got initialized
651                     if (!(sc2.ctorflow.callSuper & CSX.this_ctor))
652                     {
653                         foreach (i, v; ad2.fields)
654                         {
655                             if (v.isThisDeclaration())
656                                 continue;
657                             if (v.ctorinit == 0)
658                             {
659                                 /* Current bugs in the flow analysis:
660                                  * 1. union members should not produce error messages even if
661                                  *    not assigned to
662                                  * 2. structs should recognize delegating opAssign calls as well
663                                  *    as delegating calls to other constructors
664                                  */
665                                 if (v.isCtorinit() && !v.type.isMutable() && cd)
666                                     funcdecl.error("missing initializer for %s field `%s`", MODtoChars(v.type.mod), v.toChars());
667                                 else if (v.storage_class & STC.nodefaultctor)
668                                     error(funcdecl.loc, "field `%s` must be initialized in constructor", v.toChars());
669                                 else if (v.type.needsNested())
670                                     error(funcdecl.loc, "field `%s` must be initialized in constructor, because it is nested struct", v.toChars());
671                             }
672                             else
673                             {
674                                 bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
675                                 if (mustInit && !(sc2.ctorflow.fieldinit[i].csx & CSX.this_ctor))
676                                 {
677                                     funcdecl.error("field `%s` must be initialized but skipped", v.toChars());
678                                 }
679                             }
680                         }
681                     }
682                     sc2.ctorflow.freeFieldinit();
683 
684                     if (cd && !(sc2.ctorflow.callSuper & CSX.any_ctor) && cd.baseClass && cd.baseClass.ctor)
685                     {
686                         sc2.ctorflow.callSuper = CSX.none;
687 
688                         // Insert implicit super() at start of fbody
689                         Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod);
690                         FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, null, FuncResolveFlag.quiet);
691                         if (!fd)
692                         {
693                             funcdecl.error("no match for implicit `super()` call in constructor");
694                         }
695                         else if (fd.storage_class & STC.disable)
696                         {
697                             funcdecl.error("cannot call `super()` implicitly because it is annotated with `@disable`");
698                         }
699                         else
700                         {
701                             Expression e1 = new SuperExp(Loc.initial);
702                             Expression e = new CallExp(Loc.initial, e1);
703                             e = e.expressionSemantic(sc2);
704                             Statement s = new ExpStatement(Loc.initial, e);
705                             funcdecl.fbody = new CompoundStatement(Loc.initial, s, funcdecl.fbody);
706                         }
707                     }
708                     //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
709                 }
710 
711                 /* https://issues.dlang.org/show_bug.cgi?id=17502
712                  * Wait until after the return type has been inferred before
713                  * generating the contracts for this function, and merging contracts
714                  * from overrides.
715                  *
716                  * https://issues.dlang.org/show_bug.cgi?id=17893
717                  * However should take care to generate this before inferered
718                  * function attributes are applied, such as 'nothrow'.
719                  *
720                  * This was originally at the end of the first semantic pass, but
721                  * required a fix-up to be done here for the '__result' variable
722                  * type of __ensure() inside auto functions, but this didn't work
723                  * if the out parameter was implicit.
724                  */
725                 funcdecl.buildEnsureRequire();
726 
727                 // Check for errors related to 'nothrow'.
728                 const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow);
729                 if (f.isnothrow && blockexit & BE.throw_)
730                     error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
731 
732                 if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
733                 {
734                     /* Disable optimization on Win32 due to
735                      * https://issues.dlang.org/show_bug.cgi?id=17997
736                      */
737 //                    if (!global.params.isWindows || global.params.is64bit)
738                         funcdecl.eh_none = true;         // don't generate unwind tables for this function
739                 }
740 
741                 if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
742                 {
743                     if (funcdecl.type == f)
744                         f = cast(TypeFunction)f.copy();
745                     f.isnothrow = !(blockexit & BE.throw_);
746                 }
747 
748                 if (funcdecl.fbody.isErrorStatement())
749                 {
750                 }
751                 else if (ad2 && funcdecl.isCtorDeclaration())
752                 {
753                     /* Append:
754                      *  return this;
755                      * to function body
756                      */
757                     if (blockexit & BE.fallthru)
758                     {
759                         Statement s = new ReturnStatement(funcdecl.loc, null);
760                         s = s.statementSemantic(sc2);
761                         funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
762                         funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
763                     }
764                 }
765                 else if (funcdecl.fes)
766                 {
767                     // For foreach(){} body, append a return 0;
768                     if (blockexit & BE.fallthru)
769                     {
770                         Expression e = IntegerExp.literal!0;
771                         Statement s = new ReturnStatement(Loc.initial, e);
772                         funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
773                         funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
774                     }
775                     assert(!funcdecl.returnLabel);
776                 }
777                 else
778                 {
779                     const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
780                     if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm)
781                     {
782                         Expression e;
783                         if (!funcdecl.hasReturnExp)
784                             funcdecl.error("has no `return` statement, but is expected to return a value of type `%s`", f.next.toChars());
785                         else
786                             funcdecl.error("no `return exp;` or `assert(0);` at end of function");
787                         if (global.params.useAssert == CHECKENABLE.on && !global.params.useInline)
788                         {
789                             /* Add an assert(0, msg); where the missing return
790                              * should be.
791                              */
792                             e = new AssertExp(funcdecl.endloc, IntegerExp.literal!0, new StringExp(funcdecl.loc, "missing return expression"));
793                         }
794                         else
795                             e = new HaltExp(funcdecl.endloc);
796                         e = new CommaExp(Loc.initial, e, f.next.defaultInit(Loc.initial));
797                         e = e.expressionSemantic(sc2);
798                         Statement s = new ExpStatement(Loc.initial, e);
799                         funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
800                     }
801                 }
802 
803                 if (funcdecl.returns)
804                 {
805                     bool implicit0 = addReturn0();
806                     Type tret = implicit0 ? Type.tint32 : f.next;
807                     assert(tret.ty != Tvoid);
808                     if (funcdecl.vresult || funcdecl.returnLabel)
809                         funcdecl.buildResultVar(scout ? scout : sc2, tret);
810 
811                     /* Cannot move this loop into NrvoWalker, because
812                      * returns[i] may be in the nested delegate for foreach-body.
813                      */
814                     for (size_t i = 0; i < funcdecl.returns.dim; i++)
815                     {
816                         ReturnStatement rs = (*funcdecl.returns)[i];
817                         Expression exp = rs.exp;
818                         if (exp.op == TOK.error)
819                             continue;
820                         if (tret.ty == Terror)
821                         {
822                             // https://issues.dlang.org/show_bug.cgi?id=13702
823                             exp = checkGC(sc2, exp);
824                             continue;
825                         }
826 
827                         /* If the expression in the return statement (exp) cannot be implicitly
828                          * converted to the return type (tret) of the function and if the
829                          * type of the expression is type isolated, then it may be possible
830                          * that a promotion to `immutable` or `inout` (through a cast) will
831                          * match the return type.
832                          */
833                         if (!exp.implicitConvTo(tret) && funcdecl.isTypeIsolated(exp.type))
834                         {
835                             /* https://issues.dlang.org/show_bug.cgi?id=20073
836                              *
837                              * The problem is that if the type of the returned expression (exp.type)
838                              * is an aggregated declaration with an alias this, the alias this may be
839                              * used for the conversion testing without it being an isolated type.
840                              *
841                              * To make sure this does not happen, we can test here the implicit conversion
842                              * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
843                              * The implicit conversion with alias this is taken care of later.
844                              */
845                             AggregateDeclaration aggDecl = isAggregate(exp.type);
846                             TypeStruct tstruct;
847                             TypeClass tclass;
848                             bool hasAliasThis;
849                             if (aggDecl && aggDecl.aliasthis)
850                             {
851                                 hasAliasThis = true;
852                                 tclass = exp.type.isTypeClass();
853                                 if (!tclass)
854                                     tstruct = exp.type.isTypeStruct();
855                                 assert(tclass || tstruct);
856                             }
857                             if (hasAliasThis)
858                             {
859                                 if (tclass)
860                                 {
861                                     if ((cast(TypeClass)(exp.type.immutableOf())).implicitConvToWithoutAliasThis(tret))
862                                         exp = exp.castTo(sc2, exp.type.immutableOf());
863                                     else if ((cast(TypeClass)(exp.type.wildOf())).implicitConvToWithoutAliasThis(tret))
864                                         exp = exp.castTo(sc2, exp.type.wildOf());
865                                 }
866                                 else
867                                 {
868                                     if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
869                                         exp = exp.castTo(sc2, exp.type.immutableOf());
870                                     else if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
871                                         exp = exp.castTo(sc2, exp.type.wildOf());
872                                 }
873                             }
874                             else
875                             {
876                                 if (exp.type.immutableOf().implicitConvTo(tret))
877                                     exp = exp.castTo(sc2, exp.type.immutableOf());
878                                 else if (exp.type.wildOf().implicitConvTo(tret))
879                                     exp = exp.castTo(sc2, exp.type.wildOf());
880                             }
881                         }
882 
883                         const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
884                         // if a copy constructor is present, the return type conversion will be handled by it
885                         if (!(hasCopyCtor && exp.isLvalue()))
886                             exp = exp.implicitCastTo(sc2, tret);
887 
888                         if (f.isref)
889                         {
890                             // Function returns a reference
891                             exp = exp.toLvalue(sc2, exp);
892                             checkReturnEscapeRef(sc2, exp, false);
893                         }
894                         else
895                         {
896                             exp = exp.optimize(WANTvalue);
897 
898                             /* https://issues.dlang.org/show_bug.cgi?id=10789
899                              * If NRVO is not possible, all returned lvalues should call their postblits.
900                              */
901                             if (!funcdecl.nrvo_can)
902                                 exp = doCopyOrMove(sc2, exp, f.next);
903 
904                             if (tret.hasPointers())
905                                 checkReturnEscape(sc2, exp, false);
906                         }
907 
908                         exp = checkGC(sc2, exp);
909 
910                         if (funcdecl.vresult)
911                         {
912                             // Create: return vresult = exp;
913                             exp = new BlitExp(rs.loc, funcdecl.vresult, exp);
914                             exp.type = funcdecl.vresult.type;
915 
916                             if (rs.caseDim)
917                                 exp = Expression.combine(exp, new IntegerExp(rs.caseDim));
918                         }
919                         else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf()))
920                         {
921                             exp = exp.implicitCastTo(sc2, funcdecl.tintro.nextOf());
922                         }
923                         rs.exp = exp;
924                     }
925                 }
926                 if (funcdecl.nrvo_var || funcdecl.returnLabel)
927                 {
928                     scope NrvoWalker nw = new NrvoWalker();
929                     nw.fd = funcdecl;
930                     nw.sc = sc2;
931                     nw.visitStmt(funcdecl.fbody);
932                 }
933 
934                 sc2 = sc2.pop();
935             }
936 
937             funcdecl.frequire = funcdecl.mergeFrequire(funcdecl.frequire, funcdecl.fdrequireParams);
938             funcdecl.fensure = funcdecl.mergeFensure(funcdecl.fensure, Id.result, funcdecl.fdensureParams);
939 
940             Statement freq = funcdecl.frequire;
941             Statement fens = funcdecl.fensure;
942 
943             /* Do the semantic analysis on the [in] preconditions and
944              * [out] postconditions.
945              */
946             if (freq)
947             {
948                 /* frequire is composed of the [in] contracts
949                  */
950                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
951                 sym.parent = sc2.scopesym;
952                 sym.endlinnum = funcdecl.endloc.linnum;
953                 sc2 = sc2.push(sym);
954                 sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
955 
956                 // BUG: need to error if accessing out parameters
957                 // BUG: need to disallow returns and throws
958                 // BUG: verify that all in and ref parameters are read
959                 freq = freq.statementSemantic(sc2);
960                 freq.blockExit(funcdecl, false);
961 
962                 funcdecl.eh_none = false;
963 
964                 sc2 = sc2.pop();
965 
966                 if (global.params.useIn == CHECKENABLE.off)
967                     freq = null;
968             }
969             if (fens)
970             {
971                 /* fensure is composed of the [out] contracts
972                  */
973                 if (f.next.ty == Tvoid && funcdecl.fensures)
974                 {
975                     foreach (e; *funcdecl.fensures)
976                     {
977                         if (e.id)
978                         {
979                             funcdecl.error(e.ensure.loc, "`void` functions have no result");
980                             //fens = null;
981                         }
982                     }
983                 }
984 
985                 sc2 = scout; //push
986                 sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
987 
988                 // BUG: need to disallow returns and throws
989 
990                 if (funcdecl.fensure && f.next.ty != Tvoid)
991                     funcdecl.buildResultVar(scout, f.next);
992 
993                 fens = fens.statementSemantic(sc2);
994                 fens.blockExit(funcdecl, false);
995 
996                 funcdecl.eh_none = false;
997 
998                 sc2 = sc2.pop();
999 
1000                 if (global.params.useOut == CHECKENABLE.off)
1001                     fens = null;
1002             }
1003             if (funcdecl.fbody && funcdecl.fbody.isErrorStatement())
1004             {
1005             }
1006             else
1007             {
1008                 auto a = new Statements();
1009                 // Merge in initialization of 'out' parameters
1010                 if (funcdecl.parameters)
1011                 {
1012                     for (size_t i = 0; i < funcdecl.parameters.dim; i++)
1013                     {
1014                         VarDeclaration v = (*funcdecl.parameters)[i];
1015                         if (v.storage_class & STC.out_)
1016                         {
1017                             if (!v._init)
1018                             {
1019                                 v.error("Zero-length `out` parameters are not allowed.");
1020                                 return;
1021                             }
1022                             ExpInitializer ie = v._init.isExpInitializer();
1023                             assert(ie);
1024                             if (auto iec = ie.exp.isConstructExp())
1025                             {
1026                                 // construction occurred in parameter processing
1027                                 auto ec = new AssignExp(iec.loc, iec.e1, iec.e2);
1028                                 ec.type = iec.type;
1029                                 ie.exp = ec;
1030                             }
1031                             a.push(new ExpStatement(Loc.initial, ie.exp));
1032                         }
1033                     }
1034                 }
1035 
1036                 if (_arguments)
1037                 {
1038                     /* Advance to elements[] member of TypeInfo_Tuple with:
1039                      *  _arguments = v_arguments.elements;
1040                      */
1041                     Expression e = new VarExp(Loc.initial, funcdecl.v_arguments);
1042                     e = new DotIdExp(Loc.initial, e, Id.elements);
1043                     e = new ConstructExp(Loc.initial, _arguments, e);
1044                     e = e.expressionSemantic(sc2);
1045 
1046                     _arguments._init = new ExpInitializer(Loc.initial, e);
1047                     auto de = new DeclarationExp(Loc.initial, _arguments);
1048                     a.push(new ExpStatement(Loc.initial, de));
1049                 }
1050 
1051                 // Merge contracts together with body into one compound statement
1052 
1053                 if (freq || fpreinv)
1054                 {
1055                     if (!freq)
1056                         freq = fpreinv;
1057                     else if (fpreinv)
1058                         freq = new CompoundStatement(Loc.initial, freq, fpreinv);
1059 
1060                     a.push(freq);
1061                 }
1062 
1063                 if (funcdecl.fbody)
1064                     a.push(funcdecl.fbody);
1065 
1066                 if (fens || fpostinv)
1067                 {
1068                     if (!fens)
1069                         fens = fpostinv;
1070                     else if (fpostinv)
1071                         fens = new CompoundStatement(Loc.initial, fpostinv, fens);
1072 
1073                     auto ls = new LabelStatement(Loc.initial, Id.returnLabel, fens);
1074                     funcdecl.returnLabel.statement = ls;
1075                     a.push(funcdecl.returnLabel.statement);
1076 
1077                     if (f.next.ty != Tvoid && funcdecl.vresult)
1078                     {
1079                         // Create: return vresult;
1080                         Expression e = new VarExp(Loc.initial, funcdecl.vresult);
1081                         if (funcdecl.tintro)
1082                         {
1083                             e = e.implicitCastTo(sc, funcdecl.tintro.nextOf());
1084                             e = e.expressionSemantic(sc);
1085                         }
1086                         auto s = new ReturnStatement(Loc.initial, e);
1087                         a.push(s);
1088                     }
1089                 }
1090                 if (addReturn0())
1091                 {
1092                     // Add a return 0; statement
1093                     Statement s = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
1094                     a.push(s);
1095                 }
1096 
1097                 Statement sbody = new CompoundStatement(Loc.initial, a);
1098 
1099                 /* Append destructor calls for parameters as finally blocks.
1100                  */
1101                 if (funcdecl.parameters)
1102                 {
1103                     foreach (v; *funcdecl.parameters)
1104                     {
1105                         if (v.storage_class & (STC.ref_ | STC.out_ | STC.lazy_))
1106                             continue;
1107                         if (v.needsScopeDtor())
1108                         {
1109                             // same with ExpStatement.scopeCode()
1110                             Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
1111                             v.storage_class |= STC.nodtor;
1112 
1113                             s = s.statementSemantic(sc2);
1114 
1115                             bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
1116                             const blockexit = s.blockExit(funcdecl, isnothrow);
1117                             if (blockexit & BE.throw_)
1118                                 funcdecl.eh_none = false;
1119                             if (f.isnothrow && isnothrow && blockexit & BE.throw_)
1120                                 error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
1121                             if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_)
1122                                 f.isnothrow = false;
1123 
1124                             if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru)
1125                                 sbody = new CompoundStatement(Loc.initial, sbody, s);
1126                             else
1127                                 sbody = new TryFinallyStatement(Loc.initial, sbody, s);
1128                         }
1129                     }
1130                 }
1131                 // from this point on all possible 'throwers' are checked
1132                 funcdecl.flags &= ~FUNCFLAG.nothrowInprocess;
1133 
1134                 if (funcdecl.isSynchronized())
1135                 {
1136                     /* Wrap the entire function body in a synchronized statement
1137                      */
1138                     ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
1139                     if (cd)
1140                     {
1141                         if (!global.params.is64bit && global.params.isWindows && !funcdecl.isStatic() && !sbody.usesEH() && !global.params.trace)
1142                         {
1143                             /* The back end uses the "jmonitor" hack for syncing;
1144                              * no need to do the sync at this level.
1145                              */
1146                         }
1147                         else
1148                         {
1149                             Expression vsync;
1150                             if (funcdecl.isStatic())
1151                             {
1152                                 // The monitor is in the ClassInfo
1153                                 vsync = new DotIdExp(funcdecl.loc, symbolToExp(cd, funcdecl.loc, sc2, false), Id.classinfo);
1154                             }
1155                             else
1156                             {
1157                                 // 'this' is the monitor
1158                                 vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
1159                                 if (funcdecl.isThis2)
1160                                 {
1161                                     vsync = new PtrExp(funcdecl.loc, vsync);
1162                                     vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
1163                                 }
1164                             }
1165                             sbody = new PeelStatement(sbody); // don't redo semantic()
1166                             sbody = new SynchronizedStatement(funcdecl.loc, vsync, sbody);
1167                             sbody = sbody.statementSemantic(sc2);
1168                         }
1169                     }
1170                     else
1171                     {
1172                         funcdecl.error("synchronized function `%s` must be a member of a class", funcdecl.toChars());
1173                     }
1174                 }
1175 
1176                 // If declaration has no body, don't set sbody to prevent incorrect codegen.
1177                 if (funcdecl.fbody || funcdecl.allowsContractWithoutBody())
1178                     funcdecl.fbody = sbody;
1179             }
1180 
1181             // Check for undefined labels
1182             if (funcdecl.labtab)
1183                 foreach (keyValue; funcdecl.labtab.tab.asRange)
1184                 {
1185                     //printf("  KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1186                     LabelDsymbol label = cast(LabelDsymbol)keyValue.value;
1187                     if (!label.statement && (!label.deleted || label.iasm))
1188                     {
1189                         funcdecl.error("label `%s` is undefined", label.toChars());
1190                     }
1191                 }
1192 
1193             // Fix up forward-referenced gotos
1194             if (funcdecl.gotos)
1195             {
1196                 for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
1197                 {
1198                     (*funcdecl.gotos)[i].checkLabel();
1199                 }
1200             }
1201 
1202             if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
1203                 funcdecl.error("naked assembly functions with contracts are not supported");
1204 
1205             sc2.ctorflow.callSuper = CSX.none;
1206             sc2.pop();
1207         }
1208 
1209         if (funcdecl.checkClosure())
1210         {
1211             // We should be setting errors here instead of relying on the global error count.
1212             //errors = true;
1213         }
1214 
1215         /* If function survived being marked as impure, then it is pure
1216          */
1217         if (funcdecl.flags & FUNCFLAG.purityInprocess)
1218         {
1219             funcdecl.flags &= ~FUNCFLAG.purityInprocess;
1220             if (funcdecl.type == f)
1221                 f = cast(TypeFunction)f.copy();
1222             f.purity = PURE.fwdref;
1223         }
1224 
1225         if (funcdecl.flags & FUNCFLAG.safetyInprocess)
1226         {
1227             funcdecl.flags &= ~FUNCFLAG.safetyInprocess;
1228             if (funcdecl.type == f)
1229                 f = cast(TypeFunction)f.copy();
1230             f.trust = TRUST.safe;
1231         }
1232 
1233         if (funcdecl.flags & FUNCFLAG.nogcInprocess)
1234         {
1235             funcdecl.flags &= ~FUNCFLAG.nogcInprocess;
1236             if (funcdecl.type == f)
1237                 f = cast(TypeFunction)f.copy();
1238             f.isnogc = true;
1239         }
1240 
1241         if (funcdecl.flags & FUNCFLAG.returnInprocess)
1242         {
1243             funcdecl.flags &= ~FUNCFLAG.returnInprocess;
1244             if (funcdecl.storage_class & STC.return_)
1245             {
1246                 if (funcdecl.type == f)
1247                     f = cast(TypeFunction)f.copy();
1248                 f.isreturn = true;
1249                 if (funcdecl.storage_class & STC.returninferred)
1250                     f.isreturninferred = true;
1251             }
1252         }
1253 
1254         funcdecl.flags &= ~FUNCFLAG.inferScope;
1255 
1256         // Eliminate maybescope's
1257         {
1258             // Create and fill array[] with maybe candidates from the `this` and the parameters
1259             VarDeclaration[] array = void;
1260 
1261             VarDeclaration[10] tmp = void;
1262             size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0);
1263             if (dim <= tmp.length)
1264                 array = tmp[0 .. dim];
1265             else
1266             {
1267                 auto ptr = cast(VarDeclaration*)mem.xmalloc(dim * VarDeclaration.sizeof);
1268                 array = ptr[0 .. dim];
1269             }
1270             size_t n = 0;
1271             if (funcdecl.vthis)
1272                 array[n++] = funcdecl.vthis;
1273             if (funcdecl.parameters)
1274             {
1275                 foreach (v; *funcdecl.parameters)
1276                 {
1277                     array[n++] = v;
1278                 }
1279             }
1280 
1281             eliminateMaybeScopes(array[0 .. n]);
1282 
1283             if (dim > tmp.length)
1284                 mem.xfree(array.ptr);
1285         }
1286 
1287         // Infer STC.scope_
1288         if (funcdecl.parameters && !funcdecl.errors)
1289         {
1290             size_t nfparams = f.parameterList.length;
1291             assert(nfparams == funcdecl.parameters.dim);
1292             foreach (u, v; *funcdecl.parameters)
1293             {
1294                 if (v.storage_class & STC.maybescope)
1295                 {
1296                     //printf("Inferring scope for %s\n", v.toChars());
1297                     Parameter p = f.parameterList[u];
1298                     notMaybeScope(v);
1299                     v.storage_class |= STC.scope_ | STC.scopeinferred;
1300                     p.storageClass |= STC.scope_ | STC.scopeinferred;
1301                     assert(!(p.storageClass & STC.maybescope));
1302                 }
1303             }
1304         }
1305 
1306         if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope)
1307         {
1308             notMaybeScope(funcdecl.vthis);
1309             funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred;
1310             f.isscope = true;
1311             f.isscopeinferred = true;
1312         }
1313 
1314         // reset deco to apply inference result to mangled name
1315         if (f != funcdecl.type)
1316             f.deco = null;
1317 
1318         // Do semantic type AFTER pure/nothrow inference.
1319         if (!f.deco && funcdecl.ident != Id.xopEquals && funcdecl.ident != Id.xopCmp)
1320         {
1321             sc = sc.push();
1322             if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1323                 sc.flags |= SCOPE.ctor;
1324             sc.stc = 0;
1325             sc.linkage = funcdecl.linkage; // https://issues.dlang.org/show_bug.cgi?id=8496
1326             funcdecl.type = f.typeSemantic(funcdecl.loc, sc);
1327             sc = sc.pop();
1328         }
1329 
1330         // Do live analysis
1331         if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
1332             funcdecl.type.isTypeFunction().islive)
1333         {
1334             oblive(funcdecl);
1335         }
1336 
1337         /* If this function had instantiated with gagging, error reproduction will be
1338          * done by TemplateInstance::semantic.
1339          * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1340          */
1341         funcdecl.semanticRun = PASS.semantic3done;
1342         funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
1343         if (funcdecl.type.ty == Terror)
1344             funcdecl.errors = true;
1345         //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
1346         //fflush(stdout);
1347     }
1348 
1349     override void visit(CtorDeclaration ctor)
1350     {
1351         //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1352         if (ctor.semanticRun >= PASS.semantic3)
1353             return;
1354 
1355         /* If any of the fields of the aggregate have a destructor, add
1356          *   scope (failure) { this.fieldDtor(); }
1357          * as the first statement. It is not necessary to add it after
1358          * each initialization of a field, because destruction of .init constructed
1359          * structs should be benign.
1360          * https://issues.dlang.org/show_bug.cgi?id=14246
1361          */
1362         AggregateDeclaration ad = ctor.isMemberDecl();
1363         if (ad && ad.fieldDtor && global.params.dtorFields)
1364         {
1365             /* Generate:
1366              *   this.fieldDtor()
1367              */
1368             Expression e = new ThisExp(ctor.loc);
1369             e.type = ad.type.mutableOf();
1370             e = new DotVarExp(ctor.loc, e, ad.fieldDtor, false);
1371             e = new CallExp(ctor.loc, e);
1372             auto sexp = new ExpStatement(ctor.loc, e);
1373             auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
1374 
1375             version (all)
1376             {
1377                 /* Generate:
1378                  *   try { ctor.fbody; }
1379                  *   catch (Exception __o)
1380                  *   { this.fieldDtor(); throw __o; }
1381                  * This differs from the alternate scope(failure) version in that an Exception
1382                  * is caught rather than a Throwable. This enables the optimization whereby
1383                  * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1384                  * applies to Exception.)
1385                  */
1386                 Identifier id = Identifier.generateId("__o");
1387                 auto ts = new ThrowStatement(ctor.loc, new IdentifierExp(ctor.loc, id));
1388                 auto handler = new CompoundStatement(ctor.loc, ss, ts);
1389 
1390                 auto catches = new Catches();
1391                 auto ctch = new Catch(ctor.loc, getException(), id, handler);
1392                 catches.push(ctch);
1393 
1394                 ctor.fbody = new TryCatchStatement(ctor.loc, ctor.fbody, catches);
1395             }
1396             else
1397             {
1398                 /* Generate:
1399                  *   scope (failure) { this.fieldDtor(); }
1400                  * Hopefully we can use this version someday when scope(failure) catches
1401                  * Exception instead of Throwable.
1402                  */
1403                 auto s = new ScopeGuardStatement(ctor.loc, TOK.onScopeFailure, ss);
1404                 ctor.fbody = new CompoundStatement(ctor.loc, s, ctor.fbody);
1405             }
1406         }
1407         visit(cast(FuncDeclaration)ctor);
1408     }
1409 
1410 
1411     override void visit(Nspace ns)
1412     {
1413         if (ns.semanticRun >= PASS.semantic3)
1414             return;
1415         ns.semanticRun = PASS.semantic3;
1416         static if (LOG)
1417         {
1418             printf("Nspace::semantic3('%s')\n", ns.toChars());
1419         }
1420         if (ns.members)
1421         {
1422             sc = sc.push(ns);
1423             sc.linkage = LINK.cpp;
1424             foreach (s; *ns.members)
1425             {
1426                 s.semantic3(sc);
1427             }
1428             sc.pop();
1429         }
1430     }
1431 
1432     override void visit(AttribDeclaration ad)
1433     {
1434         Dsymbols* d = ad.include(sc);
1435         if (d)
1436         {
1437             Scope* sc2 = ad.newScope(sc);
1438             for (size_t i = 0; i < d.dim; i++)
1439             {
1440                 Dsymbol s = (*d)[i];
1441                 s.semantic3(sc2);
1442             }
1443             if (sc2 != sc)
1444                 sc2.pop();
1445         }
1446     }
1447 
1448     override void visit(AggregateDeclaration ad)
1449     {
1450         //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1451         if (!ad.members)
1452             return;
1453 
1454         StructDeclaration sd = ad.isStructDeclaration();
1455         if (!sc) // from runDeferredSemantic3 for TypeInfo generation
1456         {
1457             assert(sd);
1458             sd.semanticTypeInfoMembers();
1459             return;
1460         }
1461 
1462         auto sc2 = ad.newScope(sc);
1463 
1464         for (size_t i = 0; i < ad.members.dim; i++)
1465         {
1466             Dsymbol s = (*ad.members)[i];
1467             s.semantic3(sc2);
1468         }
1469 
1470         sc2.pop();
1471 
1472         // don't do it for unused deprecated types
1473         // or error ypes
1474         if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror))
1475         {
1476             // Evaluate: RTinfo!type
1477             auto tiargs = new Objects();
1478             tiargs.push(ad.type);
1479             auto ti = new TemplateInstance(ad.loc, Type.rtinfo, tiargs);
1480 
1481             Scope* sc3 = ti.tempdecl._scope.startCTFE();
1482             sc3.tinst = sc.tinst;
1483             sc3.minst = sc.minst;
1484             if (ad.isDeprecated())
1485                 sc3.stc |= STC.deprecated_;
1486 
1487             ti.dsymbolSemantic(sc3);
1488             ti.semantic2(sc3);
1489             ti.semantic3(sc3);
1490             auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false);
1491 
1492             sc3.endCTFE();
1493 
1494             e = e.ctfeInterpret();
1495             ad.getRTInfo = e;
1496         }
1497         if (sd)
1498             sd.semanticTypeInfoMembers();
1499         ad.semanticRun = PASS.semantic3done;
1500     }
1501 }
1502 
1503 private struct FuncDeclSem3
1504 {
1505     // The FuncDeclaration subject to Semantic analysis
1506     FuncDeclaration funcdecl;
1507 
1508     // Scope of analysis
1509     Scope* sc;
1510     this(FuncDeclaration fd,Scope* s)
1511     {
1512         funcdecl = fd;
1513         sc = s;
1514     }
1515 
1516     /* Checks that the overriden functions (if any) have in contracts if
1517      * funcdecl has an in contract.
1518      */
1519     void checkInContractOverrides()
1520     {
1521         if (funcdecl.frequires)
1522         {
1523             for (size_t i = 0; i < funcdecl.foverrides.dim; i++)
1524             {
1525                 FuncDeclaration fdv = funcdecl.foverrides[i];
1526                 if (fdv.fbody && !fdv.frequires)
1527                 {
1528                     funcdecl.error("cannot have an in contract when overridden function `%s` does not have an in contract", fdv.toPrettyChars());
1529                     break;
1530                 }
1531             }
1532         }
1533     }
1534 }