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