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