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