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