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