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