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