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