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