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.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 @safe
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                     .error(tempinst.loc, "%s `%s` error instantiating", tempinst.kind, tempinst.toPrettyChars);
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, global.errorSink); // 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             .error(funcdecl.loc, "%s `%s` has no function body with return type inference", funcdecl.kind, funcdecl.toPrettyChars);
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                             .error(funcdecl.loc, "%s `%s` cannot be %s members", funcdecl.kind, funcdecl.toPrettyChars, 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                 .deprecation(funcdecl.loc, "%s `%s` function requires a dual-context, which is deprecated", funcdecl.kind, funcdecl.toPrettyChars);
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                         {
416                             version (IN_GCC)
417                                 .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl.kind, funcdecl.toPrettyChars);
418                             else
419                                 .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars);
420                         }
421                         else if (!Type.typeinfotypelist)
422                             .error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
423                         else
424                             .error(funcdecl.loc, "%s `%s` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
425                         fatal();
426                     }
427 
428                     // Declare _arguments[]
429                     funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
430                     funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
431                     funcdecl.v_arguments.dsymbolSemantic(sc2);
432                     sc2.insert(funcdecl.v_arguments);
433                     funcdecl.v_arguments.parent = funcdecl;
434 
435                     //Type t = Type.dtypeinfo.type.constOf().arrayOf();
436                     Type t = Type.dtypeinfo.type.arrayOf();
437                     _arguments = new VarDeclaration(funcdecl.loc, t, Id._arguments, null);
438                     _arguments.storage_class |= STC.temp;
439                     _arguments.dsymbolSemantic(sc2);
440                     sc2.insert(_arguments);
441                     _arguments.parent = funcdecl;
442                 }
443                 if (f.linkage == LINK.d || f.parameterList.length)
444                 {
445                     // Declare _argptr
446                     Type t = target.va_listType(funcdecl.loc, sc);
447                     // Init is handled in FuncDeclaration_toObjFile
448                     funcdecl.v_argptr = new VarDeclaration(funcdecl.loc, t, Id._argptr, new VoidInitializer(funcdecl.loc));
449                     funcdecl.v_argptr.storage_class |= STC.temp;
450                     funcdecl.v_argptr.dsymbolSemantic(sc2);
451                     sc2.insert(funcdecl.v_argptr);
452                     funcdecl.v_argptr.parent = funcdecl;
453                 }
454             }
455 
456             /* Declare all the function parameters as variables
457              * and install them in parameters[]
458              */
459             if (const nparams = f.parameterList.length)
460             {
461                 /* parameters[] has all the tuples removed, as the back end
462                  * doesn't know about tuples
463                  */
464                 funcdecl.parameters = new VarDeclarations();
465                 funcdecl.parameters.reserve(nparams);
466                 foreach (i, fparam; f.parameterList)
467                 {
468                     Identifier id = fparam.ident;
469                     StorageClass stc = 0;
470                     if (!id)
471                     {
472                         /* Generate identifier for un-named parameter,
473                          * because we need it later on.
474                          */
475                         fparam.ident = id = Identifier.generateId("__param_", i);
476                         stc |= STC.temp;
477                     }
478                     Type vtype = fparam.type;
479                     auto v = new VarDeclaration(fparam.loc, vtype, id, null);
480                     //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
481                     stc |= STC.parameter;
482                     if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
483                     {
484                         stc |= STC.variadic;
485                     }
486 
487                     stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope | STC.register);
488                     v.storage_class = stc;
489                     v.dsymbolSemantic(sc2);
490                     if (!sc2.insert(v))
491                     {
492                         .error(funcdecl.loc, "%s `%s` parameter `%s.%s` is already defined", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.toChars(), v.toChars());
493                         funcdecl.errors = true;
494                     }
495                     else
496                         funcdecl.parameters.push(v);
497                     funcdecl.localsymtab.insert(v);
498                     v.parent = funcdecl;
499                     if (fparam.userAttribDecl)
500                         v.userAttribDecl = fparam.userAttribDecl;
501                 }
502             }
503 
504             // Declare the tuple symbols and put them in the symbol table,
505             // but not in parameters[].
506             if (f.parameterList.parameters)
507             foreach (fparam; *f.parameterList.parameters)
508             {
509                 if (!fparam.ident)
510                     continue; // never used, so ignore
511                 // expand any tuples
512                 if (fparam.type.ty != Ttuple)
513                     continue;
514 
515                 TypeTuple t = cast(TypeTuple)fparam.type;
516                 size_t dim = Parameter.dim(t.arguments);
517                 auto exps = new Objects(dim);
518                 foreach (j; 0 .. dim)
519                 {
520                     Parameter narg = Parameter.getNth(t.arguments, j);
521                     assert(narg.ident);
522                     VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
523                     assert(v);
524                     (*exps)[j] = new VarExp(v.loc, v);
525                 }
526                 assert(fparam.ident);
527                 auto v = new TupleDeclaration(funcdecl.loc, fparam.ident, exps);
528                 //printf("declaring tuple %s\n", v.toChars());
529                 v.isexp = true;
530                 if (!sc2.insert(v))
531                     .error(funcdecl.loc, "%s `%s` parameter `%s.%s` is already defined", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.toChars(), v.toChars());
532                 funcdecl.localsymtab.insert(v);
533                 v.parent = funcdecl;
534             }
535 
536             // Precondition invariant
537             Statement fpreinv = null;
538             if (funcdecl.addPreInvariant())
539             {
540                 Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
541                 if (e)
542                     fpreinv = new ExpStatement(Loc.initial, e);
543             }
544 
545             // Postcondition invariant
546             Statement fpostinv = null;
547             if (funcdecl.addPostInvariant())
548             {
549                 Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
550                 if (e)
551                     fpostinv = new ExpStatement(Loc.initial, e);
552             }
553 
554             // Pre/Postcondition contract
555             if (!funcdecl.fbody)
556                 funcdecl.buildEnsureRequire();
557 
558             Scope* scout = null;
559             if (needEnsure || funcdecl.addPostInvariant())
560             {
561                 /* https://issues.dlang.org/show_bug.cgi?id=3657
562                  * Set the correct end line number for fensure scope.
563                  */
564                 uint fensure_endlin = funcdecl.endloc.linnum;
565                 if (funcdecl.fensure)
566                     if (auto s = funcdecl.fensure.isScopeStatement())
567                         fensure_endlin = s.endloc.linnum;
568 
569                 if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
570                 {
571                     funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
572                 }
573 
574                 // scope of out contract (need for vresult.semantic)
575                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
576                 sym.parent = sc2.scopesym;
577                 sym.endlinnum = fensure_endlin;
578                 scout = sc2.push(sym);
579             }
580 
581             if (funcdecl.fbody)
582             {
583                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
584                 sym.parent = sc2.scopesym;
585                 sym.endlinnum = funcdecl.endloc.linnum;
586                 sc2 = sc2.push(sym);
587 
588                 auto ad2 = funcdecl.isMemberLocal();
589 
590                 /* If this is a class constructor
591                  */
592                 if (ad2 && funcdecl.isCtorDeclaration())
593                 {
594                     sc2.ctorflow.allocFieldinit(ad2.fields.length);
595                     foreach (v; ad2.fields)
596                     {
597                         v.ctorinit = 0;
598                     }
599                 }
600 
601                 bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_));
602 
603                 funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2);
604                 if (!funcdecl.fbody)
605                     funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
606 
607                 if (funcdecl.isNaked())
608                 {
609                     fpreinv = null;         // can't accommodate with no stack frame
610                     fpostinv = null;
611                 }
612 
613                 assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref));
614                 f = cast(TypeFunction)funcdecl.type;
615 
616                 if (funcdecl.inferRetType)
617                 {
618                     // If no return type inferred yet, then infer a void
619                     if (!f.next)
620                         f.next = Type.tvoid;
621                     if (f.checkRetType(funcdecl.loc))
622                         funcdecl.fbody = new ErrorStatement();
623                     else
624                         funcdecl.checkMain(); // Check main() parameters and return type
625                 }
626 
627                 if (f.next !is null)
628                     f.next.checkComplexTransition(funcdecl.loc, sc);
629 
630                 if (funcdecl.returns && !funcdecl.fbody.isErrorStatement())
631                 {
632                     for (size_t i = 0; i < funcdecl.returns.length;)
633                     {
634                         Expression exp = (*funcdecl.returns)[i].exp;
635                         if (exp.op == EXP.variable && (cast(VarExp)exp).var == funcdecl.vresult)
636                         {
637                             if (addReturn0())
638                                 exp.type = Type.tint32;
639                             else
640                                 exp.type = f.next;
641                             // Remove `return vresult;` from returns
642                             funcdecl.returns.remove(i);
643                             continue;
644                         }
645                         if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
646                             f.isref = false;
647                         i++;
648                     }
649                 }
650                 if (f.isref) // Function returns a reference
651                 {
652                     if (funcdecl.storage_class & STC.auto_)
653                         funcdecl.storage_class &= ~STC.auto_;
654                 }
655 
656                 // handle NRVO
657                 if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
658                     funcdecl.isNRVO = false;
659 
660                 if (funcdecl.fbody.isErrorStatement())
661                 {
662                 }
663                 else if (funcdecl.isStaticCtorDeclaration())
664                 {
665                     /* It's a static constructor. Ensure that all
666                      * ctor consts were initialized.
667                      */
668                     ScopeDsymbol pd = funcdecl.toParent().isScopeDsymbol();
669                     for (size_t i = 0; i < pd.members.length; i++)
670                     {
671                         Dsymbol s = (*pd.members)[i];
672                         s.checkCtorConstInit();
673                     }
674                 }
675                 else if (ad2 && funcdecl.isCtorDeclaration())
676                 {
677                     ClassDeclaration cd = ad2.isClassDeclaration();
678 
679                     // Verify that all the ctorinit fields got initialized
680                     if (!(sc2.ctorflow.callSuper & CSX.this_ctor))
681                     {
682                         foreach (i, v; ad2.fields)
683                         {
684                             if (v.isThisDeclaration())
685                                 continue;
686                             if (v.ctorinit == 0)
687                             {
688                                 /* Current bugs in the flow analysis:
689                                  * 1. union members should not produce error messages even if
690                                  *    not assigned to
691                                  * 2. structs should recognize delegating opAssign calls as well
692                                  *    as delegating calls to other constructors
693                                  */
694                                 if (v.isCtorinit() && !v.type.isMutable() && cd)
695                                     .error(funcdecl.loc, "%s `%s` missing initializer for %s field `%s`", funcdecl.kind, funcdecl.toPrettyChars, MODtoChars(v.type.mod), v.toChars());
696                                 else if (v.storage_class & STC.nodefaultctor)
697                                     error(funcdecl.loc, "field `%s` must be initialized in constructor", v.toChars());
698                                 else if (v.type.needsNested())
699                                     error(funcdecl.loc, "field `%s` must be initialized in constructor, because it is nested struct", v.toChars());
700                             }
701                             else
702                             {
703                                 bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
704                                 if (mustInit && !(sc2.ctorflow.fieldinit[i].csx & CSX.this_ctor))
705                                 {
706                                     .error(funcdecl.loc, "%s `%s` field `%s` must be initialized but skipped", funcdecl.kind, funcdecl.toPrettyChars, v.toChars());
707                                 }
708                             }
709                         }
710                     }
711                     sc2.ctorflow.freeFieldinit();
712 
713                     if (cd && !(sc2.ctorflow.callSuper & (CSX.any_ctor | CSX.halt)) && cd.baseClass && cd.baseClass.ctor)
714                     {
715                         sc2.ctorflow.callSuper = CSX.none;
716 
717                         // Insert implicit super() at start of fbody
718                         Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod);
719                         FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, ArgumentList(), FuncResolveFlag.quiet);
720                         if (!fd)
721                         {
722                             .error(funcdecl.loc, "%s `%s` no match for implicit `super()` call in constructor", funcdecl.kind, funcdecl.toPrettyChars);
723                         }
724                         else if (fd.storage_class & STC.disable)
725                         {
726                             .error(funcdecl.loc, "%s `%s` cannot call `super()` implicitly because it is annotated with `@disable`", funcdecl.kind, funcdecl.toPrettyChars);
727                         }
728                         else
729                         {
730                             Expression e1 = new SuperExp(Loc.initial);
731                             Expression e = new CallExp(Loc.initial, e1);
732                             e = e.expressionSemantic(sc2);
733                             Statement s = new ExpStatement(Loc.initial, e);
734                             funcdecl.fbody = new CompoundStatement(Loc.initial, s, funcdecl.fbody);
735                         }
736                     }
737                     //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
738                 }
739 
740                 /* https://issues.dlang.org/show_bug.cgi?id=17502
741                  * Wait until after the return type has been inferred before
742                  * generating the contracts for this function, and merging contracts
743                  * from overrides.
744                  *
745                  * https://issues.dlang.org/show_bug.cgi?id=17893
746                  * However should take care to generate this before inferered
747                  * function attributes are applied, such as 'nothrow'.
748                  *
749                  * This was originally at the end of the first semantic pass, but
750                  * required a fix-up to be done here for the '__result' variable
751                  * type of __ensure() inside auto functions, but this didn't work
752                  * if the out parameter was implicit.
753                  */
754                 funcdecl.buildEnsureRequire();
755 
756                 // Check for errors related to 'nothrow'.
757                 const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null);
758                 if (f.isnothrow && blockexit & BE.throw_)
759                     error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
760 
761                 if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.hasCatches))
762                 {
763                     /* Don't generate unwind tables for this function
764                      * https://issues.dlang.org/show_bug.cgi?id=17997
765                      */
766                     funcdecl.hasNoEH = true;
767                 }
768 
769                 if (funcdecl.nothrowInprocess)
770                 {
771                     if (funcdecl.type == f)
772                         f = cast(TypeFunction)f.copy();
773                     f.isnothrow = !(blockexit & BE.throw_);
774                 }
775 
776                 if (funcdecl.fbody.isErrorStatement())
777                 {
778                 }
779                 else if (ad2 && funcdecl.isCtorDeclaration())
780                 {
781                     /* Append:
782                      *  return this;
783                      * to function body
784                      */
785                     if (blockexit & BE.fallthru)
786                     {
787                         Statement s = new ReturnStatement(funcdecl.loc, null);
788                         s = s.statementSemantic(sc2);
789                         funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
790                         funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
791                     }
792                 }
793                 else if (funcdecl.fes)
794                 {
795                     // For foreach(){} body, append a return 0;
796                     if (blockexit & BE.fallthru)
797                     {
798                         Expression e = IntegerExp.literal!0;
799                         Statement s = new ReturnStatement(Loc.initial, e);
800                         funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
801                         funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
802                     }
803                     assert(!funcdecl.returnLabel);
804                 }
805                 else if (f.next.toBasetype().ty == Tnoreturn)
806                 {
807                     // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
808                     if (blockexit & BE.fallthru)
809                     {
810                         .error(funcdecl.loc, "%s `%s` is typed as `%s` but does return", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
811                         funcdecl.loc.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
812                     }
813                 }
814                 else
815                 {
816                     const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
817                     if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm && !(sc.flags & SCOPE.Cfile))
818                     {
819                         if (!funcdecl.hasReturnExp)
820                             .error(funcdecl.loc, "%s `%s` has no `return` statement, but is expected to return a value of type `%s`", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
821                         else
822                             .error(funcdecl.loc, "%s `%s` no `return exp;` or `assert(0);` at end of function", funcdecl.kind, funcdecl.toPrettyChars);
823                     }
824                 }
825 
826                 if (funcdecl.returns)
827                 {
828                     bool implicit0 = addReturn0();
829                     Type tret = implicit0 ? Type.tint32 : f.next;
830                     assert(tret.ty != Tvoid);
831                     if (funcdecl.vresult || funcdecl.returnLabel)
832                         funcdecl.buildResultVar(scout ? scout : sc2, tret);
833 
834                     /* Cannot move this loop into NrvoWalker, because
835                      * returns[i] may be in the nested delegate for foreach-body.
836                      */
837                     for (size_t i = 0; i < funcdecl.returns.length; i++)
838                     {
839                         ReturnStatement rs = (*funcdecl.returns)[i];
840                         Expression exp = rs.exp;
841                         if (exp.op == EXP.error)
842                             continue;
843                         if (tret.ty == Terror)
844                         {
845                             // https://issues.dlang.org/show_bug.cgi?id=13702
846                             exp = checkGC(sc2, exp);
847                             continue;
848                         }
849 
850                         /* If the expression in the return statement (exp) cannot be implicitly
851                          * converted to the return type (tret) of the function and if the
852                          * type of the expression is type isolated, then it may be possible
853                          * that a promotion to `immutable` or `inout` (through a cast) will
854                          * match the return type.
855                          */
856                         if (!exp.implicitConvTo(tret) && funcdecl.isTypeIsolated(exp.type))
857                         {
858                             /* https://issues.dlang.org/show_bug.cgi?id=20073
859                              *
860                              * The problem is that if the type of the returned expression (exp.type)
861                              * is an aggregated declaration with an alias this, the alias this may be
862                              * used for the conversion testing without it being an isolated type.
863                              *
864                              * To make sure this does not happen, we can test here the implicit conversion
865                              * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
866                              * The implicit conversion with alias this is taken care of later.
867                              */
868                             AggregateDeclaration aggDecl = isAggregate(exp.type);
869                             TypeStruct tstruct;
870                             TypeClass tclass;
871                             bool hasAliasThis;
872                             if (aggDecl && aggDecl.aliasthis)
873                             {
874                                 hasAliasThis = true;
875                                 tclass = exp.type.isTypeClass();
876                                 if (!tclass)
877                                     tstruct = exp.type.isTypeStruct();
878                                 assert(tclass || tstruct);
879                             }
880                             if (hasAliasThis)
881                             {
882                                 if (tclass)
883                                 {
884                                     if ((cast(TypeClass)(exp.type.immutableOf())).implicitConvToWithoutAliasThis(tret))
885                                         exp = exp.castTo(sc2, exp.type.immutableOf());
886                                     else if ((cast(TypeClass)(exp.type.wildOf())).implicitConvToWithoutAliasThis(tret))
887                                         exp = exp.castTo(sc2, exp.type.wildOf());
888                                 }
889                                 else
890                                 {
891                                     if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
892                                         exp = exp.castTo(sc2, exp.type.immutableOf());
893                                     else if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
894                                         exp = exp.castTo(sc2, exp.type.wildOf());
895                                 }
896                             }
897                             else
898                             {
899                                 if (exp.type.immutableOf().implicitConvTo(tret))
900                                     exp = exp.castTo(sc2, exp.type.immutableOf());
901                                 else if (exp.type.wildOf().implicitConvTo(tret))
902                                     exp = exp.castTo(sc2, exp.type.wildOf());
903                             }
904                         }
905 
906                         const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
907                         // if a copy constructor is present, the return type conversion will be handled by it
908                         if (!(hasCopyCtor && exp.isLvalue()))
909                         {
910                             if (f.isref && !MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
911                                 error(exp.loc, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
912                                       exp.toChars(), exp.type.toChars(), tret.toChars());
913                             else
914                                 exp = exp.implicitCastTo(sc2, tret);
915                         }
916 
917                         if (f.isref)
918                         {
919                             // Function returns a reference
920                             exp = exp.toLvalue(sc2, exp);
921                             checkReturnEscapeRef(sc2, exp, false);
922                             exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
923                         }
924                         else
925                         {
926                             exp = exp.optimize(WANTvalue);
927 
928                             /* https://issues.dlang.org/show_bug.cgi?id=10789
929                              * If NRVO is not possible, all returned lvalues should call their postblits.
930                              */
931                             if (!funcdecl.isNRVO())
932                                 exp = doCopyOrMove(sc2, exp, f.next);
933 
934                             if (tret.hasPointers())
935                                 checkReturnEscape(sc2, exp, false);
936                         }
937 
938                         exp = checkGC(sc2, exp);
939 
940                         if (funcdecl.vresult)
941                         {
942                             // Create: return vresult = exp;
943                             exp = new BlitExp(rs.loc, funcdecl.vresult, exp);
944                             exp.type = funcdecl.vresult.type;
945 
946                             if (rs.caseDim)
947                                 exp = Expression.combine(exp, new IntegerExp(rs.caseDim));
948                         }
949                         else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf()))
950                         {
951                             exp = exp.implicitCastTo(sc2, funcdecl.tintro.nextOf());
952                         }
953                         rs.exp = exp;
954                     }
955                 }
956                 if (funcdecl.nrvo_var || funcdecl.returnLabel)
957                 {
958                     scope NrvoWalker nw = new NrvoWalker();
959                     nw.fd = funcdecl;
960                     nw.sc = sc2;
961                     nw.visitStmt(funcdecl.fbody);
962                 }
963 
964                 sc2 = sc2.pop();
965             }
966 
967             if (global.params.inclusiveInContracts)
968             {
969                 funcdecl.frequire = funcdecl.mergeFrequireInclusivePreview(
970                     funcdecl.frequire, funcdecl.fdrequireParams);
971             }
972             else
973             {
974                 funcdecl.frequire = funcdecl.mergeFrequire(funcdecl.frequire, funcdecl.fdrequireParams);
975             }
976             funcdecl.fensure = funcdecl.mergeFensure(funcdecl.fensure, Id.result, funcdecl.fdensureParams);
977 
978             Statement freq = funcdecl.frequire;
979             Statement fens = funcdecl.fensure;
980 
981             /* Do the semantic analysis on the [in] preconditions and
982              * [out] postconditions.
983              */
984             immutable bool isnothrow = f.isnothrow && !funcdecl.nothrowInprocess;
985             if (freq)
986             {
987                 /* frequire is composed of the [in] contracts
988                  */
989                 auto sym = new ScopeDsymbol(funcdecl.loc, null);
990                 sym.parent = sc2.scopesym;
991                 sym.endlinnum = funcdecl.endloc.linnum;
992                 sc2 = sc2.push(sym);
993                 sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
994 
995                 // BUG: need to error if accessing out parameters
996                 // BUG: need to disallow returns
997                 // BUG: verify that all in and ref parameters are read
998                 freq = freq.statementSemantic(sc2);
999 
1000                 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1001                 const blockExit = freq.blockExit(funcdecl, null);
1002                 if (blockExit & BE.throw_)
1003                 {
1004                     if (isnothrow)
1005                         // @@@DEPRECATED_2.111@@@
1006                         // Deprecated in 2.101, can be made an error in 2.111
1007                         deprecation(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`",
1008                             funcdecl.toPrettyChars());
1009                     else if (funcdecl.nothrowInprocess)
1010                         f.isnothrow = false;
1011                 }
1012 
1013                 funcdecl.hasNoEH = false;
1014 
1015                 sc2 = sc2.pop();
1016 
1017                 if (global.params.useIn == CHECKENABLE.off)
1018                     freq = null;
1019             }
1020 
1021             if (fens)
1022             {
1023                 /* fensure is composed of the [out] contracts
1024                  */
1025                 if (f.next.ty == Tvoid && funcdecl.fensures)
1026                 {
1027                     foreach (e; *funcdecl.fensures)
1028                     {
1029                         if (e.id)
1030                         {
1031                             .error(e.ensure.loc, "%s `%s` `void` functions have no result", funcdecl.kind, funcdecl.toPrettyChars);
1032                             //fens = null;
1033                         }
1034                     }
1035                 }
1036 
1037                 sc2 = scout; //push
1038                 sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
1039 
1040                 // BUG: need to disallow returns and throws
1041 
1042                 if (funcdecl.fensure && f.next.ty != Tvoid)
1043                     funcdecl.buildResultVar(scout, f.next);
1044 
1045                 fens = fens.statementSemantic(sc2);
1046 
1047                 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1048                 const blockExit = fens.blockExit(funcdecl, null);
1049                 if (blockExit & BE.throw_)
1050                 {
1051                     if (isnothrow)
1052                         // @@@DEPRECATED_2.111@@@
1053                         // Deprecated in 2.101, can be made an error in 2.111
1054                         deprecation(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`",
1055                             funcdecl.toPrettyChars());
1056                     else if (funcdecl.nothrowInprocess)
1057                         f.isnothrow = false;
1058                 }
1059 
1060                 funcdecl.hasNoEH = false;
1061 
1062                 sc2 = sc2.pop();
1063 
1064                 if (global.params.useOut == CHECKENABLE.off)
1065                     fens = null;
1066             }
1067             if (funcdecl.fbody && funcdecl.fbody.isErrorStatement())
1068             {
1069             }
1070             else
1071             {
1072                 auto a = new Statements();
1073                 // Merge in initialization of 'out' parameters
1074                 if (funcdecl.parameters)
1075                 {
1076                     for (size_t i = 0; i < funcdecl.parameters.length; i++)
1077                     {
1078                         VarDeclaration v = (*funcdecl.parameters)[i];
1079                         if (v.storage_class & STC.out_)
1080                         {
1081                             if (!v._init)
1082                             {
1083                                 .error(v.loc, "%s `%s` zero-length `out` parameters are not allowed.", v.kind, v.toPrettyChars);
1084                                 return;
1085                             }
1086                             ExpInitializer ie = v._init.isExpInitializer();
1087                             assert(ie);
1088                             if (auto iec = ie.exp.isConstructExp())
1089                             {
1090                                 // construction occurred in parameter processing
1091                                 auto ec = new AssignExp(iec.loc, iec.e1, iec.e2);
1092                                 ec.type = iec.type;
1093                                 ie.exp = ec;
1094                             }
1095                             a.push(new ExpStatement(Loc.initial, ie.exp));
1096                         }
1097                     }
1098                 }
1099 
1100                 if (_arguments)
1101                 {
1102                     /* Advance to elements[] member of TypeInfo_Tuple with:
1103                      *  _arguments = v_arguments.elements;
1104                      */
1105                     Expression e = new VarExp(Loc.initial, funcdecl.v_arguments);
1106                     e = new DotIdExp(Loc.initial, e, Id.elements);
1107                     e = new ConstructExp(Loc.initial, _arguments, e);
1108                     e = e.expressionSemantic(sc2);
1109 
1110                     _arguments._init = new ExpInitializer(Loc.initial, e);
1111                     auto de = new DeclarationExp(Loc.initial, _arguments);
1112                     a.push(new ExpStatement(Loc.initial, de));
1113                 }
1114 
1115                 // Merge contracts together with body into one compound statement
1116 
1117                 if (freq || fpreinv)
1118                 {
1119                     if (!freq)
1120                         freq = fpreinv;
1121                     else if (fpreinv)
1122                         freq = new CompoundStatement(Loc.initial, freq, fpreinv);
1123 
1124                     a.push(freq);
1125                 }
1126 
1127                 if (funcdecl.fbody)
1128                     a.push(funcdecl.fbody);
1129 
1130                 if (fens || fpostinv)
1131                 {
1132                     if (!fens)
1133                         fens = fpostinv;
1134                     else if (fpostinv)
1135                         fens = new CompoundStatement(Loc.initial, fpostinv, fens);
1136 
1137                     auto ls = new LabelStatement(Loc.initial, Id.returnLabel, fens);
1138                     funcdecl.returnLabel.statement = ls;
1139                     a.push(funcdecl.returnLabel.statement);
1140 
1141                     if (f.next.ty != Tvoid && funcdecl.vresult)
1142                     {
1143                         // Create: return vresult;
1144                         Expression e = new VarExp(Loc.initial, funcdecl.vresult);
1145                         if (funcdecl.tintro)
1146                         {
1147                             e = e.implicitCastTo(sc, funcdecl.tintro.nextOf());
1148                             e = e.expressionSemantic(sc);
1149                         }
1150                         auto s = new ReturnStatement(Loc.initial, e);
1151                         a.push(s);
1152                     }
1153                 }
1154                 if (addReturn0())
1155                 {
1156                     // Add a return 0; statement
1157                     Statement s = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
1158                     a.push(s);
1159                 }
1160 
1161                 Statement sbody = new CompoundStatement(Loc.initial, a);
1162 
1163                 /* Append destructor calls for parameters as finally blocks.
1164                  */
1165                 if (funcdecl.parameters)
1166                 {
1167                     // check if callee destroys arguments
1168                     const bool paramsNeedDtor = target.isCalleeDestroyingArgs(f);
1169 
1170                     foreach (v; *funcdecl.parameters)
1171                     {
1172                         if (v.isReference() || (v.storage_class & STC.lazy_))
1173                             continue;
1174                         if (v.needsScopeDtor())
1175                         {
1176                             v.storage_class |= STC.nodtor;
1177                             if (!paramsNeedDtor)
1178                                 continue;
1179 
1180                             // same with ExpStatement.scopeCode()
1181                             Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
1182 
1183                             s = s.statementSemantic(sc2);
1184 
1185                             const blockexit = s.blockExit(funcdecl, isnothrow ? global.errorSink : null);
1186                             if (blockexit & BE.throw_)
1187                             {
1188                                 funcdecl.hasNoEH = false;
1189                                 if (isnothrow)
1190                                     error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
1191                                 else if (funcdecl.nothrowInprocess)
1192                                     f.isnothrow = false;
1193                             }
1194 
1195                             if (sbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null) == BE.fallthru)
1196                                 sbody = new CompoundStatement(Loc.initial, sbody, s);
1197                             else
1198                                 sbody = new TryFinallyStatement(Loc.initial, sbody, s);
1199                         }
1200                     }
1201                 }
1202                 // from this point on all possible 'throwers' are checked
1203                 funcdecl.nothrowInprocess = false;
1204 
1205                 if (funcdecl.isSynchronized())
1206                 {
1207                     /* Wrap the entire function body in a synchronized statement
1208                      */
1209                     ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
1210                     if (cd)
1211                     {
1212                         if (target.libraryObjectMonitors(funcdecl, sbody))
1213                         {
1214                             Expression vsync;
1215                             if (funcdecl.isStatic())
1216                             {
1217                                 // The monitor is in the ClassInfo
1218                                 vsync = new DotIdExp(funcdecl.loc, symbolToExp(cd, funcdecl.loc, sc2, false), Id.classinfo);
1219                             }
1220                             else
1221                             {
1222                                 // 'this' is the monitor
1223                                 vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
1224                                 if (funcdecl.hasDualContext())
1225                                 {
1226                                     vsync = new PtrExp(funcdecl.loc, vsync);
1227                                     vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
1228                                 }
1229                             }
1230                             sbody = new PeelStatement(sbody); // don't redo semantic()
1231                             sbody = new SynchronizedStatement(funcdecl.loc, vsync, sbody);
1232                             sbody = sbody.statementSemantic(sc2);
1233                         }
1234                     }
1235                     else
1236                     {
1237                         .error(funcdecl.loc, "%s `%s` synchronized function `%s` must be a member of a class", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.toChars());
1238                     }
1239                 }
1240 
1241                 // If declaration has no body, don't set sbody to prevent incorrect codegen.
1242                 if (funcdecl.fbody || funcdecl.allowsContractWithoutBody())
1243                     funcdecl.fbody = sbody;
1244             }
1245 
1246             // Check for undefined labels
1247             if (funcdecl.labtab)
1248                 foreach (keyValue; funcdecl.labtab.tab.asRange)
1249                 {
1250                     //printf("  KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1251                     LabelDsymbol label = cast(LabelDsymbol)keyValue.value;
1252                     if (!label.statement && (!label.deleted || label.iasm))
1253                     {
1254                         .error(label.loc, "%s `%s` label `%s` is undefined", funcdecl.kind, funcdecl.toPrettyChars, label.toChars());
1255                     }
1256                 }
1257 
1258             // Fix up forward-referenced gotos
1259             if (funcdecl.gotos && !funcdecl.isCsymbol())
1260             {
1261                 for (size_t i = 0; i < funcdecl.gotos.length; ++i)
1262                 {
1263                     (*funcdecl.gotos)[i].checkLabel();
1264                 }
1265             }
1266 
1267             if (funcdecl.isNaked() && (funcdecl.fensures || funcdecl.frequires))
1268                 .error(funcdecl.loc, "%s `%s` naked assembly functions with contracts are not supported", funcdecl.kind, funcdecl.toPrettyChars);
1269 
1270             sc2.ctorflow.callSuper = CSX.none;
1271             sc2.pop();
1272         }
1273 
1274         if (funcdecl.checkClosure())
1275         {
1276             // We should be setting errors here instead of relying on the global error count.
1277             //errors = true;
1278         }
1279 
1280         /* If function survived being marked as impure, then it is pure
1281          */
1282         if (funcdecl.purityInprocess)
1283         {
1284             funcdecl.purityInprocess = false;
1285             if (funcdecl.type == f)
1286                 f = cast(TypeFunction)f.copy();
1287             f.purity = PURE.fwdref;
1288         }
1289 
1290         if (funcdecl.safetyInprocess)
1291         {
1292             funcdecl.safetyInprocess = false;
1293             if (funcdecl.type == f)
1294                 f = cast(TypeFunction)f.copy();
1295             f.trust = TRUST.safe;
1296         }
1297 
1298         if (funcdecl.nogcInprocess)
1299         {
1300             funcdecl.nogcInprocess = false;
1301             if (funcdecl.type == f)
1302                 f = cast(TypeFunction)f.copy();
1303             f.isnogc = true;
1304         }
1305 
1306         finishScopeParamInference(funcdecl, f);
1307 
1308         // reset deco to apply inference result to mangled name
1309         if (f != funcdecl.type)
1310             f.deco = null;
1311 
1312         // Do semantic type AFTER pure/nothrow inference.
1313         if (!f.deco && funcdecl.ident != Id.xopEquals && funcdecl.ident != Id.xopCmp)
1314         {
1315             sc = sc.push();
1316             if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1317                 f.isctor = true;
1318             sc.stc = 0;
1319             sc.linkage = funcdecl._linkage; // https://issues.dlang.org/show_bug.cgi?id=8496
1320             funcdecl.type = f.typeSemantic(funcdecl.loc, sc);
1321             sc = sc.pop();
1322         }
1323 
1324         // Check `extern(C++)` functions for invalid the return/parameter types
1325         if (funcdecl._linkage == LINK.cpp)
1326         {
1327             static bool isCppNonMappableType(Type type, Parameter param = null, Type origType = null)
1328             {
1329                 // Don't allow D `immutable` and `shared` types to be interfaced with C++
1330                 if (type.isImmutable() || type.isShared())
1331                     return true;
1332                 else if (Type cpptype = target.cpp.parameterType(type))
1333                     type = cpptype;
1334 
1335                 if (origType is null)
1336                     origType = type;
1337 
1338                 // Permit types that are handled by toCppMangle. This list should be kept in sync with
1339                 // each visit method in dmd.cppmangle and dmd.cppmanglewin.
1340                 switch (type.ty)
1341                 {
1342                     case Tnull:
1343                     case Tnoreturn:
1344                     case Tvector:
1345                     case Tpointer:
1346                     case Treference:
1347                     case Tfunction:
1348                     case Tstruct:
1349                     case Tenum:
1350                     case Tclass:
1351                     case Tident:
1352                     case Tinstance:
1353                         break;
1354 
1355                     case Tsarray:
1356                         if (!origType.isTypePointer())
1357                             return true;
1358                         break;
1359 
1360                     default:
1361                         if (!type.isTypeBasic())
1362                             return true;
1363                         break;
1364                 }
1365 
1366                 // Descend to the enclosing type
1367                 if (auto tnext = type.nextOf())
1368                     return isCppNonMappableType(tnext, param, origType);
1369 
1370                 return false;
1371             }
1372             if (isCppNonMappableType(f.next.toBasetype()))
1373             {
1374                 .error(funcdecl.loc, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
1375                 if (f.next.isTypeDArray())
1376                     errorSupplemental(funcdecl.loc, "slices are specific to D and do not have a counterpart representation in C++", f.next.toChars());
1377                 funcdecl.errors = true;
1378             }
1379             foreach (i, param; f.parameterList)
1380             {
1381                 if (isCppNonMappableType(param.type.toBasetype(), param))
1382                 {
1383                     .error(funcdecl.loc, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toPrettyChars, param.type.toChars());
1384                     if (param.type.toBasetype().isTypeSArray())
1385                         errorSupplemental(funcdecl.loc, "perhaps use a `%s*` type instead",
1386                                           param.type.nextOf().mutableOf().unSharedOf().toChars());
1387                     funcdecl.errors = true;
1388                 }
1389             }
1390         }
1391 
1392         // Do live analysis
1393         if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
1394             funcdecl.type.isTypeFunction().islive)
1395         {
1396             oblive(funcdecl);
1397         }
1398 
1399         /* If this function had instantiated with gagging, error reproduction will be
1400          * done by TemplateInstance::semantic.
1401          * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1402          */
1403         funcdecl.semanticRun = PASS.semantic3done;
1404         if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()))
1405             funcdecl.hasSemantic3Errors = true;
1406         else
1407             funcdecl.hasSemantic3Errors = false;
1408         if (funcdecl.type.ty == Terror)
1409             funcdecl.errors = true;
1410         //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());
1411         //fflush(stdout);
1412     }
1413 
1414     override void visit(CtorDeclaration ctor)
1415     {
1416         //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1417         if (ctor.semanticRun >= PASS.semantic3)
1418             return;
1419 
1420         /* If any of the fields of the aggregate have a destructor, add
1421          *   scope (failure) { this.fieldDtor(); }
1422          * as the first statement of the constructor (unless the constructor
1423          * doesn't define a body - @disable, extern)
1424          *.It is not necessary to add it after
1425          * each initialization of a field, because destruction of .init constructed
1426          * structs should be benign.
1427          * https://issues.dlang.org/show_bug.cgi?id=14246
1428          */
1429         AggregateDeclaration ad = ctor.isMemberDecl();
1430         if (!ctor.fbody || !ad || !ad.fieldDtor ||
1431             global.params.dtorFields == FeatureState.disabled || !global.params.useExceptions || ctor.type.toTypeFunction.isnothrow)
1432             return visit(cast(FuncDeclaration)ctor);
1433 
1434         /* Generate:
1435          *   this.fieldDtor()
1436          */
1437         Expression e = new ThisExp(ctor.loc);
1438         e.type = ad.type.mutableOf();
1439         e = new DotVarExp(ctor.loc, e, ad.fieldDtor, false);
1440         auto ce = new CallExp(ctor.loc, e);
1441         auto sexp = new ExpStatement(ctor.loc, ce);
1442         auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
1443 
1444         // @@@DEPRECATED_2.106@@@
1445         // Allow negligible attribute violations to allow for a smooth
1446         // transition. Remove this after the usual deprecation period
1447         // after 2.106.
1448         if (global.params.dtorFields == FeatureState.default_)
1449         {
1450             auto ctf = cast(TypeFunction) ctor.type;
1451             auto dtf = cast(TypeFunction) ad.fieldDtor.type;
1452 
1453             const ngErr = ctf.isnogc && !dtf.isnogc;
1454             const puErr = ctf.purity && !dtf.purity;
1455             const saErr = ctf.trust == TRUST.safe && dtf.trust <= TRUST.system;
1456 
1457             if (ngErr || puErr || saErr)
1458             {
1459                 // storage_class is apparently not set for dtor & ctor
1460                 OutBuffer ob;
1461                 stcToBuffer(ob,
1462                     (ngErr ? STC.nogc : 0) |
1463                     (puErr ? STC.pure_ : 0) |
1464                     (saErr ? STC.system : 0)
1465                 );
1466                 ctor.loc.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor.toPrettyChars(), ob.peekChars());
1467                 ctor.loc.deprecationSupplemental("The destructor will be called if an exception is thrown");
1468                 ctor.loc.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
1469 
1470                 ce.ignoreAttributes = true;
1471             }
1472         }
1473 
1474         version (all)
1475         {
1476             /* Generate:
1477              *   try { ctor.fbody; }
1478              *   catch (Exception __o)
1479              *   { this.fieldDtor(); throw __o; }
1480              * This differs from the alternate scope(failure) version in that an Exception
1481              * is caught rather than a Throwable. This enables the optimization whereby
1482              * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1483              * applies to Exception.)
1484              */
1485             Identifier id = Identifier.generateId("__o");
1486             auto ts = new ThrowStatement(ctor.loc, new IdentifierExp(ctor.loc, id));
1487             auto handler = new CompoundStatement(ctor.loc, ss, ts);
1488 
1489             auto catches = new Catches();
1490             auto ctch = new Catch(ctor.loc, getException(), id, handler);
1491             catches.push(ctch);
1492 
1493             ctor.fbody = new TryCatchStatement(ctor.loc, ctor.fbody, catches);
1494         }
1495         else
1496         {
1497             /* Generate:
1498              *   scope (failure) { this.fieldDtor(); }
1499              * Hopefully we can use this version someday when scope(failure) catches
1500              * Exception instead of Throwable.
1501              */
1502             auto s = new ScopeGuardStatement(ctor.loc, TOK.onScopeFailure, ss);
1503             ctor.fbody = new CompoundStatement(ctor.loc, s, ctor.fbody);
1504         }
1505         visit(cast(FuncDeclaration)ctor);
1506     }
1507 
1508 
1509     override void visit(Nspace ns)
1510     {
1511         if (ns.semanticRun >= PASS.semantic3)
1512             return;
1513         ns.semanticRun = PASS.semantic3;
1514         static if (LOG)
1515         {
1516             printf("Nspace::semantic3('%s')\n", ns.toChars());
1517         }
1518         if (!ns.members)
1519             return;
1520 
1521         sc = sc.push(ns);
1522         sc.linkage = LINK.cpp;
1523         foreach (s; *ns.members)
1524         {
1525             s.semantic3(sc);
1526         }
1527         sc.pop();
1528     }
1529 
1530     override void visit(AttribDeclaration ad)
1531     {
1532         Dsymbols* d = ad.include(sc);
1533         if (!d)
1534             return;
1535 
1536         Scope* sc2 = ad.newScope(sc);
1537         for (size_t i = 0; i < d.length; i++)
1538         {
1539             Dsymbol s = (*d)[i];
1540             s.semantic3(sc2);
1541         }
1542         if (sc2 != sc)
1543             sc2.pop();
1544     }
1545 
1546     override void visit(AggregateDeclaration ad)
1547     {
1548         //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1549         if (!ad.members)
1550             return;
1551 
1552         StructDeclaration sd = ad.isStructDeclaration();
1553         if (!sc) // from runDeferredSemantic3 for TypeInfo generation
1554         {
1555             assert(sd);
1556             sd.semanticTypeInfoMembers();
1557             return;
1558         }
1559 
1560         auto sc2 = ad.newScope(sc);
1561 
1562         for (size_t i = 0; i < ad.members.length; i++)
1563         {
1564             Dsymbol s = (*ad.members)[i];
1565             s.semantic3(sc2);
1566         }
1567 
1568         sc2.pop();
1569 
1570         // Instantiate RTInfo!S to provide a pointer bitmap for the GC
1571         // Don't do it in -betterC or on unused deprecated / error types
1572         if (!ad.getRTInfo && global.params.useTypeInfo && Type.rtinfo &&
1573             (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) &&
1574             (ad.type && ad.type.ty != Terror))
1575         {
1576             // Evaluate: RTinfo!type
1577             auto tiargs = new Objects();
1578             tiargs.push(ad.type);
1579             auto ti = new TemplateInstance(ad.loc, Type.rtinfo, tiargs);
1580 
1581             Scope* sc3 = ti.tempdecl._scope.startCTFE();
1582             sc3.tinst = sc.tinst;
1583             sc3.minst = sc.minst;
1584             if (ad.isDeprecated())
1585                 sc3.stc |= STC.deprecated_;
1586 
1587             ti.dsymbolSemantic(sc3);
1588             ti.semantic2(sc3);
1589             ti.semantic3(sc3);
1590             auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false);
1591 
1592             sc3.endCTFE();
1593 
1594             e = e.ctfeInterpret();
1595             ad.getRTInfo = e;
1596         }
1597         if (sd)
1598             sd.semanticTypeInfoMembers();
1599         ad.semanticRun = PASS.semantic3done;
1600     }
1601 }
1602 
1603 private struct FuncDeclSem3
1604 {
1605     // The FuncDeclaration subject to Semantic analysis
1606     FuncDeclaration funcdecl;
1607 
1608     // Scope of analysis
1609     Scope* sc;
1610     this(FuncDeclaration fd,Scope* s) scope @safe
1611     {
1612         funcdecl = fd;
1613         sc = s;
1614     }
1615 
1616     /* Checks that the overridden functions (if any) have in contracts if
1617      * funcdecl has an in contract.
1618      */
1619     void checkInContractOverrides()
1620     {
1621         if (funcdecl.frequires)
1622         {
1623             for (size_t i = 0; i < funcdecl.foverrides.length; i++)
1624             {
1625                 FuncDeclaration fdv = funcdecl.foverrides[i];
1626                 if (fdv.fbody && !fdv.frequires)
1627                 {
1628                     .error(funcdecl.loc, "%s `%s` cannot have an in contract when overridden function `%s` does not have an in contract", funcdecl.kind, funcdecl.toPrettyChars, fdv.toPrettyChars());
1629                     break;
1630                 }
1631             }
1632         }
1633     }
1634 }
1635 
1636 extern (C++) void semanticTypeInfoMembers(StructDeclaration sd)
1637 {
1638     if (sd.xeq &&
1639         sd.xeq._scope &&
1640         sd.xeq.semanticRun < PASS.semantic3done)
1641     {
1642         uint errors = global.startGagging();
1643         sd.xeq.semantic3(sd.xeq._scope);
1644         if (global.endGagging(errors))
1645             sd.xeq = sd.xerreq;
1646     }
1647 
1648     if (sd.xcmp &&
1649         sd.xcmp._scope &&
1650         sd.xcmp.semanticRun < PASS.semantic3done)
1651     {
1652         uint errors = global.startGagging();
1653         sd.xcmp.semantic3(sd.xcmp._scope);
1654         if (global.endGagging(errors))
1655             sd.xcmp = sd.xerrcmp;
1656     }
1657 
1658     FuncDeclaration ftostr = search_toString(sd);
1659     if (ftostr &&
1660         ftostr._scope &&
1661         ftostr.semanticRun < PASS.semantic3done)
1662     {
1663         ftostr.semantic3(ftostr._scope);
1664     }
1665 
1666     if (sd.xhash &&
1667         sd.xhash._scope &&
1668         sd.xhash.semanticRun < PASS.semantic3done)
1669     {
1670         sd.xhash.semantic3(sd.xhash._scope);
1671     }
1672 
1673     if (sd.postblit &&
1674         sd.postblit._scope &&
1675         sd.postblit.semanticRun < PASS.semantic3done)
1676     {
1677         sd.postblit.semantic3(sd.postblit._scope);
1678     }
1679 
1680     if (sd.dtor &&
1681         sd.dtor._scope &&
1682         sd.dtor.semanticRun < PASS.semantic3done)
1683     {
1684         sd.dtor.semantic3(sd.dtor._scope);
1685     }
1686 }